Table of Contents

Week One

Q: The range of Unary

What is the range for an Unary number? How many bits does it take?

A: To understand the range of an Unary number, we first have to know how it is represented. An Unary(n) number takes n bits. It represents an integer of the number of 1's in it. For example Unary(5) myUnary5 takes 5 bits. There could be 0 to 5 1's in it. So the range is from 0 to 5.

That explains why the following code will output 1,3 and 7 when the value I expected is only 0,1,2,3.

DebugUtils du;
Unary(4) ns;
if(ns==0){
  ns=1;
}
else if(ns==1){
  ns=2;
}
else if(ns==2){
  ns=3;
}
else if(ns==3){
  ns=0;
}
du.printContext();

Q: More about the bits in Unary

If the value of an myUnary5 is 1, does it mean the possible bits that myUnary5 holds could be '00001', '00010', '00100', '01000' and '10000'?

A: 30-May-2015 02:56:33PM-0600: Yes, a Unary value that contains a single 'on' bit will have value 1, regardless of its position. So, for example, in a Unary(3), there is only one representation of zero (000), and one representation of three (111), but there are three possible representations for one (001, 010, 100) and three representations for two (110, 101, 011). Only the number of one bits (known as the 'population count' or 'popcount') matters in determining a Unary value.

Week Two

Q: Dynamic atom coloring?

We can override some properties of an element, such as its color, when we were programming C++ to create elements on the MFM. How can we do the same thing in ULAM? I want to create two types of Res with different colors. (This is a simplification of the Aura and Medicine element. Later I will convert them to real Aura and Medicine)

A: 28-May-2015 01:04:05PM-0600 There was a getColor() special function to allow the ULAM programmer to determine atom colors at runtime, but that mechanism is currently broken by the in-progress Site redesign efforts. Hope for getColor or some replacement to reappear within a week!

Q: Access other atom data members?

Sometimes we want to get other Atom's data member. In the 'Aura and Medicine' game, a Medicine atom will compare the density that it observed with the density stored in another Aura atom. How can we access the data member of other atoms? I tried to write like this but got compile errors:

Atom a = ew[slot];
Int yourDensity = a.density;

A: 29-May-2015 04:37:12AM-0600: Probably the most straightforward is to use an 'is' expression combined with a cast:

Atom a = ew[index];
if (a is Foo) {       
  Foo f = (Foo) a;    // Note that f is a copy of a!
  Int n = f.fooField;
  // ..use n for something..
} // else a is not a Foo

If you want to modify fields of an atom this way, you need to write the changes back:

element Foo {
  EventWindow ew;
  Int(7) fooField;

  Void behave() {
    if (ew[1] is Foo) {
      Foo f = (Foo) ew[1];  // Makes a copy
      ++f.fooField;         // Modifies the copy
      ew[1] = f;            // Updates eventwindow
    }
  }
}

Q: WindowServices next() returning -1?

I have a problem using WindowServices with a for loop. I printed out the value of ws.next(). It is '-1'. I think that's why the code inside the for loop is not performed. Please tell me again how to pick a nearby neighbor in my EventWindow so that I can read or modify its fields.

   
WindowServises ws;
ws.reset(0,4);
Signal s;
Int st=au.getType((Atom) s);
if(ws.scan(st)){
  density=ws.getHits(0);
  if(density>0){
    du.print((Int) ws.next());
    for (Int idx = ws.next(); idx >= 0; idx = ws.next()) {
       Atom a = ew[idx];
       if (a is Signal) {
          //compare your density with mine
       }
    }
}    

A: 29-May-2015 06:24:01PM-0600: The WindowServices next() method returns -1 when there are no more event window indices to scan in your chosen range.. but the main issue here is: You don't want to use both a ws.scan() call and a for loop with ws.next, you want one or the other. If you use scan, then you use getHits to see if anything matched, and getPick to get a randomly-chosen match. That code has got other issues too (e.g., WindowServices).

Q: How to access event window site number when using ''WindowServices scan()''?

Thank you! I fixed the code. This time I use the for loop on ws.next(). I wanted to use ws.scan(someType) but then if I used ws.getPick(0) to find a match, how would I know its actual index in the event window?

WindowServices ws;
Random rdm;
ws.reset(1,4);
Request r;
Int rt=au.getType((Atom) r);
for(Int idx=ws.next();idx>=0;idx=ws.next()){
  Atom a= ew[idx];
  if(a is Request){
    Request you=(Request) a;
    if(density>you.density){
      if(rdm.oneIn(2)){
        ew.swap(0,idx);
      }
    }
  }
}

A: 29-May-2015 11:08:39PM-0600: As long as the corresponding ws.getHits returns greater than zero, then return value of ws.getPick is the event window index! You can do stuff like:

WindowServices ws;
ws.reset(1,4);
Request r;
Int rt=au.getType((Atom) r);
if (ws.scan(rt)) {            // Any matches for rt?
  Atom a = ew[ws.getPick(0)]; // Yes! Access chosen slot
  if(a is Request){           // This 'if' will always succeed..
    r = (Request) a;
    .. use r.density etc ..
  }
}

or even this:

WindowServices ws;
ws.reset(1,4);
Request r;
Int rt=au.getType((Atom) r);  // Get type of element Request
if (ws.scan(rt)) {            // Any matches for that?
  r = (Request) ew[ws.getPick(0)]; // Yes! Access slot of chosen one
  .. use r.density etc ..
}

because that particular ws.scan(rt) can only return true if ws.getPick(0) is going to return the event window index of a Request atom. (It's not this easy, though, if you are scanning for multiple things simultaneously.)

Q: Does ws.getPick(typeIndex) only return one site? How to access each site within an event window?

Thank you! Now I understand that ws.getPick(typeIndex) returns an event window index. ws.getPick(typeIndex) can randomly pick one atom of this type. When I want to select an atom of this type but also has the maximum value of a certain data member, I should use the for loop to check each atom of this type and get this maximum atom. Like here I want to find the Request ATOM which has the max density value within this EventWindow.

A: 31-May-2015 12:51:43AM-0600: To select an atom based on anything other than its type, in general you'll need to write a loop explicitly, rather than using scan() – although WindowServices can help with the event window indexing.

But even when you do need to loop, we have SelectorServices to provide some help for simpler tasks like finding and picking fairly among maxima and minima. Here are two SelectorServices examples. The first, SSDemo1, uses SelectorServices in a relatively general way, while the second, SSDemo2, is a bit optimized for shorter code.

SSDemo1.ulam
/**
   SSDemo1s share the highest Score among their connected group.
 */

element SSDemo1 {
  // Typedefs
  typedef Unsigned(8) Score;

  // Utilities
  EventWindow ew;
  Random random;
  DebugUtils du;

  // Data members
  Score val;

  Void behave() {
    if (val == 0) // randomize initial vals
      val = random.bits(val.sizeof);

    WindowServices ws;    // Scanning support
    SelectorServices ss;  // Selection support

    ws.reset(1,4); // Scan all but us (for this example)
    ss.reset();

    for (Int idx = ws.next(); idx >= 0; idx = ws.next()) {
      Atom a = ew[idx];
      if (a as SSDemo1)
        ss.maximize(idx, (Int) a.val);
    }
    // This code is fairly general, but cumbersome.  Compare SSDemo2
    if (ss.selectionMade()) {
      Int sidx = ss.getSelectedKey(); // The site that maximized
      SSDemo1 f = (SSDemo1) ew[sidx]; // which we know is a SSDemo1
      if (f.val > 0)                  // ..if they've been initted
        val = f.val;                  // ..pick up their val
      du.printContext();              // and report for debugging.
    }
  }
}
SSDemo2.ulam
/**
   SSDemo2s share the highest Score among their connected group.
 */

element SSDemo2 {
  // Typedefs
  typedef Unsigned(8) Score;

  // Utilities
  EventWindow ew;
  Random random;
  DebugUtils du;

  // Data members
  Score val;

  Void behave() {
    if (val == 0) // randomize initial vals
      val = random.bits(val.sizeof);

    WindowServices ws;    // Scanning support
    SelectorServices ss;  // Selection support

    ws.reset(0,4); // Scan everyone including us
    ss.reset();

    for (Int idx = ws.next(); idx >= 0; idx = ws.next()) {
      Atom a = ew[idx];
      if (a as SSDemo2)
        ss.maximize((Int) a.val);  // Don't need the idx this way..
    }
    // We scanned ourselves, so we know ss.selectionMade() will be
    // true.  So we just take the chosen value (even if it was ours).
    val = (Score) ss.getSelectedValue();
    du.printContext();
  }
}

Q: How to change the size of the MFM simulator?

Sometimes the canvas is too big for my experiment. If I don't want those atoms diffuse too far away, I will draw a box of Wall. Can we change the size of MFM simulator?

A: In version 3, the mfms simulator has a nice new feature: You can specify the grid size (and even the tile size!) on the command line.

Read the very beginning of the output from 'mfms -h' about geometry. If the geometry is specified is has to be the first argument on the command line.

Try something like:

you@linux$ ..path../mfms {2C2} -flags -what -ever

or even

you@linux$ ..path../mfms {1H1} -flags -what -ever

Q: Do smaller grid geometries make the simulator run faster?

Thank you! That's better than drawing Walls by hand. The right side is the resized MFM simulator by {2C2}. And isn't the smaller simulator running faster?

A: 31-May-2015 01:06:01AM-0600: It depends somewhat on your hardware – in particular, how many real cores you have, but yes, in general a smaller grid geometry – fewer and smaller tiles, down to some limit – will typically be faster than more and larger tiles. Any single tile geometry will be running single-threaded, though, so in some cases multiple smaller tiles will be faster than one bigger one – you'll need to experiment some, if maximizing AER is crucial. Also, if you type a a few times after typing i in the simulator, it will display the AER it is producing, so you can get a rough sense of what's faster and slower.

On a separate point, note that the “edge of the grid” is somewhat different that a ring of Walls. For example, non-existent sites return false from the EventWindow isLive method, but sites containing Walls return true. For consistency you might want to draw a ring of Wall around the boundary of even a smaller grid.