Teaching and Learning with Swarm

Paul E. Johnson
Dept. of Political Science
1541 Lilac Lane, Room 504 Blake Hall,
University of Kansas
Lawrence, Kansas 66045
(785) 864-9086
pauljohn@ku.edu

Swarm as a teaching tool

My Students:

How does Swarm help?

What is my role in Swarm community?

Its not good to write simulations from scratch

Artificial Stock Market

This is a famous model, one of the leading published examples of individual-based simulation modeling. (Palmer, R.G, W. Brian Arthur, John H. Holland, Blake LeBaron, and Paul Taylor. 1994. Artificial economic life: a simple model of a stock market. Physica D 75: 264-274. )

My objective: learn from the model.
My current role: sanitize/restructure so the code won't overwhelm students

http://ArtStkMkt.sourceforge.net
has release information/patches/CVS archive.

Original Objective-C version written on Next computer by SFI team
Swarm version of code originally by Brandon Weber (version 2.0)
ArtStkMkt site presents patches and justifications for revisions
 

ASM Lessons: Things I've learned about why Swarm is Useful

  1. ASM I: Importance of "object orientation"
    1. managing details inside subclasses to avoid clutter & mistakes
    2. managing input and output of parameters and data
  2. ASM II: Collections concepts:  for keeping track of objects
  3. ASM III: Scheduling concepts.
  4. ASM IV: GUI

ASM I--object orientation

Example A: Classes instead of C-structs.

Example B: Concentrate calculations (especially bit math) in lower level classes.

 Agents keep track of the world by strings of  bits (actually, "trits"), as in [01 10 00 10 01 10 01 10].
 To save memory, this is packed into a 16 bit integer, and the 0's and 1's are manipulated with bit math.

Usage example:

 myworld[WORD(i)] |= realworld[n] << SHIFT[i];


    This accesses the i'th "trit" in a larger sequence, and adjust it, using a SHIFT macro which is defined elsewhere.

Within the plain C approach, this was necessary because there was no object to whom one could delegate the bit math.
 

New More Object-Oriented Swarm Version:

Create classes where bit strings are to be stored.  (see BitVector class, or BFcast class which accesses it)
Create interfaces to these classes with obvious names, as in

(void) setConditionsbit: (int) bit To: (int) x
-(int) getConditionsbit: (int)bit
-(void) switchConditionsbit: (int) bit

The "trits" are  translated into and from integer values according to a table like this:
 
binary value  integer equivalent   meaning
00  0  # or "don't care"
01 NO
 10  2  YES
 11    3 not in use, a place holder value

All of the bit math is confined to the BitVector class, all other operations to get or set the bit values are used in a standard object oriented way.  Create a conditions object from the BFcast class, and tell that one to set the third bit to integer value 1.

 [conditions setConditionsbit: 3 To: 1];
 

ASM II--collections


Original Objective-C ASM model used no collections concepts. It used "raw" C memory allocation
 (from sfsm/src/bfagent.m):
 

1. Declare instance variables for pointers to arrays of structs

 struct BF_rule *rule;       // array of size numrules
 struct BF_rule *rptrtop;    // top of rule array (rule + p->numrules)
 
2. Allocate a big chunk of memory for the array of structs (p->numrules=integer size)
 
  rule = (Rule) getmem(sizeof(RuleStruct)*p->numrules); //gets  memory for structs
  rptrtop = rule + p->numrules;                               //pointer math finds the "last" pointer
 
3.  Step through it with pointer math.
     Rule rptr;
    for (rptr = rule; rptr < rptrtop; rptr++) {
            rptr->forecast = 0.0;
            rptr->oldforecast = global_mean;
            rptr->next = NULL;
            rptr->oldnext = NULL;
    }
Note :

New Improved Swarm version of the same thing (Collections library).


1. Rewrite "structs" to objects.
2. Use container to keep objects.  In this case, a Swarm Array is used:

    fcastList=[Array create: [self getZone] setCount: numfcasts];

3. Use standard Swarm approach to "step through" the collection.

Here are a couple of "before" and "after" examples for comparison:
Before:
   struct BF_fcast *fptr, *topfptr;
   topfptr = fcast + p->numfcasts;
   for (fptr = fcast; fptr < topfptr; fptr++)
      {
        if (fptr->conditions[0] & real0) continue;
        *nextptr = fptr;
        nextptr = &fptr->next;
      }
After: 

id <Index> index=[ fcastList begin: [self getZone]];

for ( aForecast=[index next]; [index getLoc]==Member;     aForecast=[index next] )
    {
      if ( [aForecast getConditionsWord: 0] & real0 )   continue ;
      //if that's true, this does not get done:
      [activeList addLast: aForecast];
    }
index drop];
 


 
 
//Before
 //This is an example of a "homemade" list traversal
      for (fptr=activelist; fptr!=NULL; fptr=fptr->next)
        {
          fptr->lastactive = currentTime;
          if (++fptr->count >= mincount)
      {
        ++nactive;
        if (fptr->strength > maxstrength)
          {
            maxstrength = fptr->strength;
            bestfptr = fptr;
          }
      }
   }
//After introduction of Swarm collections 
  index=[activeList begin: [self getZone]];
  for( aForecast=[index next]; [index getLoc]==Member; aForecast=[index next] )
    {
      [aForecast setLastactive: currentTime];
      if([aForecast incrCount] >= mincount)
        {
          double strength=[aForecast getStrength];
          ++nactive;
          if (strength > maxstrength)
            {
              maxstrength = strength;
              bestForecast= aForecast;
            }
        }
    }
  [index drop];

 

ASM III--Scheduling

ASM uses a homemade schedule, which essentially amounts to a loop over the actions of the system and the agents.

Observe in main.m, agents are created and then the system repeats until a pre-designated time.

// Perform any events scheduled for startup
    performEvents();
// Main loop on periods
    while (t < lasttime) {
    // Either perform a fake warmup period or a normal one (increments t)
        if (t < 0)
            warmup();
        else
            period();
    // Perform any scheduled events
        performEvents();
    }

This is calling functions warmup() and period() that exist in control.m, which in turn loop over agents.

As far as I can see, this scheduling approach is not wrong, but it certainly isn't very right.
 

Conveyor Belt  metaphor for Swarm's scheduling apparatus.

Time is a sequence of small links in a chain:

All Swarms that have been created in the program can "throw actions" onto the belt when desired.  When Swarms are created, their "time scales" mesh because the actions they mandate fit "onto" this chain at the appropriate time.

Swarm has standard terminology/structure to assure that:
    a repeated action does in fact repeat
     several actions thrown onto the belt at the same time are handled "appropriately".

    "Appropriately" means there are ways to control the order in which actions at the same time are executed.  One may design simulations that randomize actions that are in the same link of the the conveyor chain, or not.
 

GUI (Graphical User Interface)

The original ASM model was presented to run in batch mode.
The original graphical controls/displays were written in a specialized Next-only framework and were deleted for the general release.

Swarm provides some standardized graphical displays that make it easier to monitor and interact with an on-going simulation.
   http://ArtStkMkt.sourceforge.net/screenshots/asm-20000530.gif

As the original ASM authors discovered, it is difficult and risky to write a GUI from scratch!
 

OK, But Does it Work in the classroom?

Example Student Research Projects (from interdisciplinary seminar)

What Can We Do About it?