swarm-support
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Swarm-Support] C arrays and swarm: strange behaviour (long)


From: paul box
Subject: [Swarm-Support] C arrays and swarm: strange behaviour (long)
Date: Wed, 19 Mar 2008 11:39:57 +0930

Hello All

After many days of trying to debug a model, I have traced the problem
to what I can only describe as a nasty bug.  I will try to reproduce
it here with as much detail as possible.

I am working on a model that is running an iterated prisoner's dilemma
(IPD).  Each group of players belong to a community, which contains a
list of players, plus four lists containing members who follow one of
four available strategies.  Players are members of the global player
list, and switch membership between the four available strategy lists
according to their average payoff:

  id <List> playerList;
  id <List> cList, dList, ctftList, dtftList;

The five lists (four lists with the subset of players following that
strategy, and a fifth list containing everyone in the community):

  enum strategy {SOCIAL, BASTARD, CTFT, DTFT, TOTAL};

The method where the players decide which list to abandon one list and
join another is in a method called 'shiftLists', where the criteria
for leaving one list is if the average payoff in their collection is
less than the average payoff for the global population.

I implemented by declaring three local arrays (inside the -shiftList
method itself), holding relevant summary statistics for each or the
lists: avePay[5]. proportion[5], and trigger[5].  There is also a
local pointer to a Player object, and two integers i and j for
iterating through loops:

-shiftLists {
  Player * playboy;
  double avePay[TOTAL]; //
  double proportion[TOTAL];
  double trigger[TOTAL];
  int i, j;

The average pay of each strategy is calculated for each list:

    for (i=SOCIAL; i<=TOTAL; i++) avePay[i] = 0.0;
    for (i=SOCIAL; i<=TOTAL; i++)
      for (j=0; j<[[self listOf: i] getCount]; j++)
        avePay[i] += [[[self listOf: i] atOffset: j] getScore];
    for (i=SOCIAL; i<=TOTAL; i++)
      avePay[i] /=  (double) [[self listOf: i] getCount];

The proportion is simply the fraction of the total in each strategy:


  proportion[SOCIAL] = (double) [cList getCount] / [playerList getCount];
  proportion[BASTARD] = (double) [dList getCount] / [playerList getCount];
  proportion[CTFT] = (double) [ctftList getCount] / [playerList getCount];
  proportion[DTFT] = (double) [dtftList getCount] / [playerList getCount];
  proportion[TOTAL] = (double) [playerList getCount] / [playerList getCount];

And a "trigger", which is simply avePay[strategy] / avePay[TOTAL];
those players in the list i where trigger[i] < 1 are told to search
for a new strategy.

 for (i = SOCIAL; i <= DTFT; i++) {
    trigger[i] = avePay[i] / avePay[TOTAL];
  }

And the program from there continues on to have players who's strategy
trigger[i]< 1 adopt a new strategy, drop themselves from their
existing list, and join the list corresponding to the new strategy.

OK, here's the problem: I was getting incomprehensible behaviour when
running this.  I started putting in copious printf statements.  From
the start, with the printf statements included:

-shiftLists {
  Player * playboy;
  double avePay[TOTAL]; //
  double proportion[TOTAL];
  double trigger[TOTAL];
  int i, j;
  printf ("declared %d lists!\n", TOTAL);

  [playerList forEach: M (unflag)];

  // compute locally the relative scores amoung your community

  // initialize
  for (i=SOCIAL; i<=TOTAL; i++) avePay[i] = 0.0;
  // for each member in each list, sum their score
  for (i=SOCIAL; i<=TOTAL; i++)
    for (j=0; j<[[self listOf: i] getCount]; j++)
      avePay[i] += [[[self listOf: i] atOffset: j] getScore];
  // divide each summed score by the number of members in each list to
  // get averages
  printf ("total scores are ");
  for (i=SOCIAL; i<=TOTAL; i++)
    printf ("(%d) %g, ", i, avePay[i]);
  printf ("\n");
  for (i=SOCIAL; i<=TOTAL; i++)
    avePay[i] /=  (double) [[self listOf: i] getCount];
  printf ("average scores are ");
  for (i=SOCIAL; i<=TOTAL; i++)
    printf ("(%d with %d)  %g, ", i, [[self listOf: i] getCount],  avePay[i]);
  printf ("\n");

  proportion[SOCIAL] = (double) [cList getCount] / [playerList getCount];
  proportion[BASTARD] = (double) [dList getCount] / [playerList getCount];
  proportion[CTFT] = (double) [ctftList getCount] / [playerList getCount];
  proportion[DTFT] = (double) [dtftList getCount] / [playerList getCount];
  proportion[TOTAL] = (double) [playerList getCount] / [playerList getCount];

  printf ("ave and num: ");

  // for (i=SOCIAL; i<=TOTAL; i++) {
//     printf ("(%d) %g/%g, ", i, avePay[i], proportion[i]);
//   }
  printf ("\n");

 printf ("numbers in each list: %d, %d, %d, %d, %d\n",
         [[self listOf: SOCIAL] getCount],
         [[self listOf: BASTARD] getCount],
         [[self listOf: CTFT] getCount],
         [[self listOf: DTFT] getCount],
         [[self listOf: TOTAL] getCount]);

 ... and so on....


This produces the following lines of output as -shiftLists is iterated through:

declared 4 lists!
total scores are (0) 0, (1) 2, (2) 0, (3) 12, (4) 14,
average scores are (0 with 1)  0, (1 with 1)  2, (2 with 1)  0, (3
with 17)  0.705882, (4 with 20)  0.7,
ave and num:
numbers in each list: 1, 1, 1, 17, 20
triggers: 0, 2.85714, 0, 1.0084
declared 4 lists!
total scores are (0) 0, (1) 11, (2) 24, (3) 2, (4) 37,
average scores are (0 with 3)  0, (1 with 6)  1.83333, (2 with 10)
2.4, (3 with 1)  2, (4 with 20)  1.85,
ave and num:
numbers in each list: 3, 6, 10, 1, 20
triggers: 0, 0.990991, 1.2973, 1.08108
declared 4 lists!
   ...etc...

Now, when I run the same code, but uncomment the loop with the printf
statement (right below the statement 'printf ("ave and num: ");) and
changing NOTHING ELSE, I get the following output:

declared 4 lists!
total scores are (0) 0, (1) 2, (2) 8, (3) 9, (4) 19,
average scores are (0 with 3)  0, (1 with 5)  0.4, (2 with 5)  1.6, (3
with 7)  1.28571, (4 with 20)  0.95,
ave and num: (0) 0/0.15, (1) 0.4/0.25, (2) 1.6/0.25, (3) 1.28571/0.35,
(4) 0.15/1,
numbers in each list: 3, 5, 5, 7, 20
triggers: 0, 2.66667, 10.6667, 8.57143
declared 4 lists!
total scores are (0) 16, (1) 4, (2) 0, (3) 18, (4) 38,
average scores are (0 with 8)  2, (1 with 5)  0.8, (2 with 2)  0, (3
with 5)  3.6, (4 with 20)  1.9,
ave and num: (0) 2/0.4, (1) 0.8/0.25, (2) 0/0.1, (3) 3.6/0.25, (4) 0.4/1,
numbers in each list: 8, 5, 2, 5, 20
triggers: 5, 2, 0, 9
declared 4 lists!
    ...etc...



The only difference between the two lines of code should be after the
line that begins 'ave and num:' -- it should print out the strategy
number inparentheses, the average score for that strategy, a forward
slash, and the proportion of the population using that strategy.

When that print statement is commented out, the following two lines
should read 'numbers in each list', followed by five numbers separated
by commas, the first four should add up to the fifth (e.g., 1, 1, 1,
17, 20 in the top example).  The next line, beginning with the word
'triggers' should give a series of numbers from 0 to something not
that far above 1 (the avearge score for the subset of the population
using that strategy divided by the average score for the entire
population).  In the top example, the range from 0 to 2.85714, which
is to be expected.

In the second example, the lines beginning with 'total scores are' and
'average scores are' are still producing output that is reasonable:
the numbers of the lists still add up to to 20, and the weighted
averages of the first four elements (scores) equal the average value
of the fifth element.  But when the next line is printed out (the line
beginning with 'ave and num:') the first four elements are consistent
with the previous lines (same average, and proportion of population
consistent with counts of individuals).  But the last element,
starting with the number (4), gives an incorrect average.  The
following lines also give garbage numbers.

Working through the lines on the second example:
declared 4 lists!
total scores are (0) 16, (1) 4, (2) 0, (3) 18, (4) 38,
average scores are (0 with 8)  2, (1 with 5)  0.8, (2 with 2)  0, (3
with 5)  3.6, (4 with 20)  1.9,

   These numbers are correct:  16/8 = 2, 4/5=0.8, 0/2=0, 18/5=2.6, and 38/20=1.9

ave and num: (0) 2/0.4, (1) 0.8/0.25, (2) 0/0.1, (3) 3.6/0.25, (4) 0.4/1,

    incorrect: the last line should read (4) 1.9/1

numbers in each list: 8, 5, 2, 5, 20

    correct: 8 + 5 + 2 + 5 = 20

triggers: 5, 2, 0, 9

   incorrect: the four elements should be:
               2/1.9  = 1.0526 (not 5)
               .8/1.9 = .42105 (not 2)
               0/1.9 = 0   (correct)
               3.06/1.9 = 1.6105 (not 9)

And of course the behaviour of the program is completely different as
subsequent actions are based on these values.


This is a lengthy description, but the bottom line is this: the sole
difference in the two examples is that the first one has the following
line commented out:

//  for (i=SOCIAL; i<=TOTAL; i++) {
//     printf ("(%d) %g/%g, ", i, avePay[i], proportion[i]);
//   }


The line does no manipulation, it only prints out the values of those
arrays.

I am nonplussed that a print statement is the only apparent cause of
this strange behaviour.

Any ideas of what is going on, or what I might be missing?

I have attached a more complete version of the code in question to
this message.


-- 
//////////////////////////
// Paul Box
// Alice Springs, NT Australia
//

Attachment: Communty.m
Description: Binary data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]