User Tools

Site Tools


dev:program_ulam

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
dev:program_ulam [2015/05/27 06:14] – [Run] xychendev:program_ulam [2016/01/14 07:13] (current) ackley
Line 18: Line 18:
 Similarly, the first letter of every variable name, and of the name of every function or method (both terms mean the same thing in ULAM), must be a **lowercase** letter.   So examples of legal variable or function names could include ''i'', ''count'', ''isInitted'', or ''cMAX_VALUE'', but not ''IsInitted'', ''Reset'', or ''MAX_VALUE'' Similarly, the first letter of every variable name, and of the name of every function or method (both terms mean the same thing in ULAM), must be a **lowercase** letter.   So examples of legal variable or function names could include ''i'', ''count'', ''isInitted'', or ''cMAX_VALUE'', but not ''IsInitted'', ''Reset'', or ''MAX_VALUE''
  
 +
 +==== EventWindow Indices ====
 +
 +{{ :dev:event-window-10.png?300|}} The image at right (click to enlarge) shows the indexing scheme used for sites within an ''EventWindow'' Both 2D 'coord' numbering and a 1D 'site number' approach are offered.  
 +
 +The ''getCoord(siteNum)'' function converts an 1D index (which is an ''Unsigned(6)'' ) to a 2D coordinate (which is a quark ''C2D''). The ''getSiteNumber(coord)'' convert ''C2D'' back to 1-d ''Unsigned(6)'' The quark ''C2D'' has ''getX()'' and ''getY()'' methods to access the //x// and //y// coordinate values individually.
 +
 +In general, when code is referring to individual fixed sites within the event window, the 1D coordinate system is used (see the 'First' element below for an example).  Two-dimensional C2D indexing is more commonly used when there is some flexibility depending on geometry or relative positions.  
  
  
Line 28: Line 36:
   EventWindow ew;   EventWindow ew;
   Void behave(){   Void behave(){
-    ew[1]=ew[0];+    ew[1]=ew[0]; // Copy self one site west
   }   }
 } }
Line 44: Line 52:
 /home/user/ULAM/ulam1/bin/ulam -l First.ulam /home/user/ULAM/ulam1/bin/ulam -l First.ulam
 </code> </code>
-Running ulam with the ''-h'' switch will show all the switches for the ULAM compiler. The switch ''-l'' requests the creation of a dynamically-loadable library file from all the .ulam  files on the command line. The resulting library file, called ''libcue.so'', will be created in the ''/home/user/elements/.gen/bin/'' folder.      +Running ulam with the ''-h'' switch will show all the switches for the ULAM compiler. The switch ''-l'' requests the creation of a dynamically-loadable library file from all the .ulam  files on the command line. The resulting library file, called ''libcue.so'', will be created in the ''/home/user/elements/.gen/bin/'' folder.
 ==== Run ==== ==== Run ====
 We also must specify where the simulator ''mfms''is located. The switch ''-ep'' tells ''mfms'' to load our ulam elements. The mfms -h can show all the switches for MFM. We also must specify where the simulator ''mfms''is located. The switch ''-ep'' tells ''mfms'' to load our ulam elements. The mfms -h can show all the switches for MFM.
Line 52: Line 59:
 </code> </code>
  
-Here is some screenshots of the mfms simulator at startup  {{:dev:mfms_start.png?400 |}}. The simulator is an 160*96 canvas. By default the help menu will pop at startupWe can use <code>mfms -n</code> to switch it off from the beginning or use the 'hkey-command to turn it off.  +=== A quick tour of mfms simulator === 
-The 't' command will show us the palettethe pencil tool, how to place a ''First'' atom.  How to start the simulation.  Screenshot after a couple AEPS.  Screenshot after many AEPS.+On the left is a screenshot of the mfms simulator at startup  {{:dev:mfms_start.png?410 |}}. The simulator is an 160*96 canvas. The help menu will pop at startup unless We use ''mfms -n'' to switch it off. We can also use the ''command'' to turn it on and off manually.  
 + 
 +On the right, we use the ''command'' to show the palette{{ :dev:mfms_t.png?direct&230|}}. The colors are elements. The pencil tool is selected by default. We can draw a dot or a line of ''Atoms of an element'' use the pencil tool. For shortwe will use ''Atom'' instead of ''Atom of an element'' in the following tutorial. If we want to draw or delete atoms in a big area, we can use the brush or eraser tool. The rightmost button also allow us to change the size of our brush and eraser. We can use two colors at one time. In this screenshot, we can draw back ''Empty'' atom with left-clicks, and white ''Wall'' atom with the right-clicks. 
 + 
 +Two other useful panels are ''logs'' and ''statistics and settings''. They are brought up by ''l command'' and ''i command'' respectively. We can demonstrate the use of these two panels later in the tutorial. 
 + 
 +=== experiment the First element === 
 +To place a ''First'' atom, select it from the palette and left-click on the canvasTo start or pause the simulation, use the ''SPACE command''The following screenshots shows the behavior of ''First''At 0.000 kAEPS there is only 1.0 First atom on the canvas. At 0.025 kAEPS, the ''First'' grows westward. There are 10 of them on the canvas. At 0.505 kAEPS, the ''First'' stops growing because they hit the west border. There are 67.4 atoms on the canvas. Why 0.4 atoms?   
 + 
 +{{:dev:mfms_first_0000kps.png?nolink&260 |}}{{:dev:mfms_first_0025kps.png?nolink&260 |}}{{:dev:mfms_first_0505.png?nolink&260 |}} 
 + 
 +From the left to the right, these pictures shows a sequence of how ''First'' grows to the west. 
  
 ===== The 'Second' Element ===== ===== The 'Second' Element =====
Line 68: Line 87:
 */ */
 element Second{ element Second{
 +  EventWindow ep;
   Void behave(){   Void behave(){
-    EventWindow ep; 
     ep[1]=ep[0];     ep[1]=ep[0];
   }   }
Line 79: Line 97:
 But that's not all: We can specify //multiple// symmetries in the ''\symmetries'' declaration, in which case one of them will be **picked at random before //each// event**.  ''Second'' is an example of the most extreme case, using ''all'' to enable all eight flips and rotations of the axes.  With a random coordinate transformation on each event, the "west" neighbor might actually be any of the four sites immediately adjacent to the  Second atom.  Look what ''Second'' does: But that's not all: We can specify //multiple// symmetries in the ''\symmetries'' declaration, in which case one of them will be **picked at random before //each// event**.  ''Second'' is an example of the most extreme case, using ''all'' to enable all eight flips and rotations of the axes.  With a random coordinate transformation on each event, the "west" neighbor might actually be any of the four sites immediately adjacent to the  Second atom.  Look what ''Second'' does:
  
-**TODO** Screenshots  +{{:dev:mfms_second_0000kps.png?nolink&200 |}}{{:dev:mfms_second_0024kps.png?nolink&200 |}}{{:dev:mfms_second_0109kps.png?nolink&200 |}}{{:dev:mfms_second_0217kps.png?nolink&200 |}} 
 + 
 +''Second'' grows and fills the entire canvas. 
 +  
  
 ===== The 'Third' Element ===== ===== The 'Third' Element =====
 We already know duplicate. Then we can swap.  We already know duplicate. Then we can swap. 
-<code>+<code - Third.ulam>
 /** /**
   Third is a demo element.   Third is a demo element.
Line 91: Line 112:
 */ */
 element Third{ element Third{
 +  EventWindow ep;
   Void behave(){   Void behave(){
-    EventWindow ep; 
     ep.swap(0,1);     ep.swap(0,1);
   }   }
Line 100: Line 121:
  
 ===== The 'Flip' Element ===== ===== The 'Flip' Element =====
-This element Five will shake back and forth 1 step along x axis.  +This element Flip will shake back and forth 1 step along x axis.  
-<code>+<code - Flip.ulam>
 /** /**
-  Fifth is a demo element.+  Flip is a demo element.
   \color #606   \color #606
-  \symbol Fv+  \symbol Fp
   \symmetries 0   \symmetries 0
 */ */
-element Five{+element Flip{
   Bool xFlip;   Bool xFlip;
 +  EventWindow ew;
   Void behave(){   Void behave(){
-    EventWindow ew; 
     if (xFlip==false){     if (xFlip==false){
         xFlip=true;         xFlip=true;
Line 127: Line 148:
 ===== The 'Box' Element ===== ===== The 'Box' Element =====
 This element Box will move in a loop of north, east, south, west. It seems like moving inside a box. This element Box will move in a loop of north, east, south, west. It seems like moving inside a box.
-<code>+<code - Box.ulam>
 /** /**
   Box is a demo element.   Box is a demo element.
Line 159: Line 180:
 </code>  </code> 
 The ''ew.changeSymmetry()'' method accepts 0,1,2,3,4,5,6,7. We use 0,1,2,3 to let the EventWindow rotate 0,90,180,270 degree to the right hand direction(clockwise). In ULAM primitive types like ''Unsigned'', we can specify any number of bits from 1 to 32. The type ''Unsigned(2)'' uses two bits and has possible values 0,1,2,3. So by giving our ''ns'' data member the type ''Unsigned(2)'' we use as few bits as possible while providing four possible states.  The ''ew.changeSymmetry()'' method accepts 0,1,2,3,4,5,6,7. We use 0,1,2,3 to let the EventWindow rotate 0,90,180,270 degree to the right hand direction(clockwise). In ULAM primitive types like ''Unsigned'', we can specify any number of bits from 1 to 32. The type ''Unsigned(2)'' uses two bits and has possible values 0,1,2,3. So by giving our ''ns'' data member the type ''Unsigned(2)'' we use as few bits as possible while providing four possible states. 
 +
 +===== Interaction between three Elements =====
 +We have tried several elements above. Here we implemented a game involves three elements: ''Provider'', ''Signal'' and ''Request''. The Requests diffuse around. Whenever they see Providers, they disappear. The Providers send out Signals to attract Requests. A Signal can catch a Request by a gradient check rule. The gradient here refers to the number of Signals observed by Signals and by Requests respectively. 
 +<code - Provider.ulam>
 +/**
 +  Provider is a demo element.
 +  \color #fba
 +  \symbol Pv
 +  \symmetries normal
 +*/
 +element Provider{
 +  DebugUtils du;
 +  EventWindow ew;
 +  AtomUtils au;
 +  Random rm;
 +
 +  Void behave(){
 +    WindowServices ws;
 +    ws.reset(1,1);
 +    Empty e;
 +    Signal s;
 +    Int et=au.getType((Atom) e);
 +    if(ws.scan(et)){ //check if there is empty slot to produce Signal atoms 
 +      if(rm.oneIn(3)){
 +        ew[ws.getPick(0)]=s;//pick a random site to send out a Signal
 +      }
 +    }
 +  }
 +}
 +</code>
 +<code - Signal.ulam>
 +/**
 +  Signal is a demo element.
 +  \color #ac3
 +  \symbol Sg
 +  \symmetries all
 +*/
 +element Signal{
 +  DebugUtils du;
 +  EventWindow ew;
 +  AtomUtils au;
 +  Random rm;
 +  Unsigned(6) density;
 +  Void diffuse(){
 +    if(ew[1] is Empty){
 +      ew.swap(0,1);
 +    }
 +  }
 +  Bool chkDense(){
 +    WindowServices ws;
 +    ws.reset(0,4);
 +    Signal s;
 +    Int st=au.getType((Atom) s);
 +    if(ws.scan(st)){
 +      density=ws.getHits(0);
 +      if(density<=1){
 +        return false;
 +      }
 +    }
 +    return true;
 +  }
 +  Void catchRequest(){
 +    WindowServices ws;
 +    Random rdm;
 +    ws.reset(1,4);
 +    Request r;
 +    Int rt=au.getType((Atom) r);
 +    for(Int slot=ws.next();slot>=0;slot=ws.next()){
 +      Atom a= ew[slot];
 +      if(a is Request){
 +        Request you=(Request) a;
 +        if(density>you.density){
 +          if(rdm.oneIn(2)){
 +            ew.swap(0,slot);
 +          }
 +        }
 +      }
 +    }
 +  }
 +  Void behave(){
 +    Bool isAlive=true;
 +    if(chkDense()){// if alone, I can walk around. I store the number of Signals that I observed. 
 +      diffuse();
 +    }
 +    else{          // if I am alone, I have some chance to disappear.
 +      if(rm.oneIn(density*5-4)){
 +        Empty e;
 +        ew[0]=e;
 +        isAlive=false;
 +      }
 +    }
 +    if(isAlive){
 +      catchRequest(); // if not disappear, I will swap position with some Request who observe  
 +                      // less Signal than me.
 +    }
 +  }
 +}
 +</code>
 +<code - Request.ulam>
 +/**
 +  Request is a demo element.
 +  \color #740
 +  \symbol Rq
 +  \symmetries all
 +*/
 +element Request{
 +  DebugUtils du;
 +  EventWindow ew;
 +  AtomUtils au;
 +  Random rm;
 +  Unsigned(5) density;
 +  Unsigned(5) pvdrcnt;
 +  Void diffuse(){
 +    if(ew[1] is Empty){
 +      ew.swap(0,1);
 +    }
 +  }
 +  Void chkDense(){
 +    WindowServices ws;
 +    ws.reset(0,4);
 +    Signal s;
 +    Provider p;
 +    Int st =au.getType((Atom) s);
 +    Int pt =au.getType((Atom) p);
 +    if(ws.scan(st,pt)){  // observe either Providers or Signals around me.
 +      density=ws.getHits(0);
 +      pvdrcnt=ws.getHits(1);
 +      if (pvdrcnt>0){    // if Provider exists, I will disappear.
 +        Empty e;
 +        ew[0]=e;
 +      }else{
 +          diffuse();     // if no Provider, I walk away and store the number of Signals I observed.
 +      }
 +    }
 +    else diffuse();      // if neither Provider or Signal appears, I walk away.
 +  }
 +
 +  Void behave(){
 +    chkDense();
 +  }
 +}
 +</code>
 +
 +===== Node Elements =====
 +We have some cool features in the new MFM simulator. One of them is that an Atom can change its color dynamically. We made this little ''Node'' element to simulate a neuron node. When a ''Node'' is triggered by its //left neighbors// within its ''EventWindow'', it fires. We let a ''Node'' to display various colors as long as it is trigger. If it doesn't fire, it remains dark. 
 +
 +{{:dev:node_init.png?250|}}  
 +<code - Node.ulam>
 +/**
 +  Node is a demo element.
 +  \color #986
 +  \symbol Nd
 +  \symmetries normal
 +*/
 +element Node{
 +  typedef Unsigned(6) SiteNum;
 +  typedef Int(16) Coord;
 +  typedef Unary(1) FireFlag;
 +  typedef Int(4) Weight;
 +  typedef Unsigned(8) ARGB[4];
 +  typedef Unsigned(8) ColorValue;
 +
 +  DebugUtils du;
 +  EventWindow ew;
 +  Once oc;
 +  AtomUtils au;
 +  Weight wa;
 +  Weight wm;
 +  Weight wb;
 +  FireFlag fire;
 +  Weight thresh;
 +  ColorValue red;
 +  ColorValue grn;
 +  ColorValue blu;
 +
 +  Int getSum(){
 +    Int sum;
 +    C2D mcd;
 +    WindowServices ws;
 +    ws.reset(1,4);
 +    for(Int slot=ws.next();slot>=0;slot=ws.next()){
 +      if(ew[slot] is Node){
 + Atom a=ew[slot];
 + Node you=(Node) a;
 + mcd=ew.getCoord((SiteNum)slot);
 + Coord mx=mcd.getX();
 + Coord my=mcd.getY();
 + if(mx<0){
 +   if(my<0){
 +     sum=sum+wa*you.fire;
 +   }else if(my==0){
 +     sum=sum+wm*you.fire;
 +   }else if(my>0){
 +     sum=sum+wb*you.fire;
 +   }
 + }
 +      }
 +    }
 +    return sum;
 +  }
 +  FireFlag getFire(Int s){
 +    if(s>=thresh){
 +      return 1;
 +    }
 +    return 0;
 +  }
 +  Void initSelf(){
 +    Random rd;
 +    Weight w;
 +    wa=(Weight)rd.between((Int)w.minof,(Int)w.maxof);
 +    wm=(Weight)rd.between((Int)w.minof,(Int)w.maxof);
 +    wb=(Weight)rd.between((Int)w.minof,(Int)w.maxof);
 +    thresh=(Weight)rd.between((Int)w.minof,(Int)w.maxof);
 +  }
 +  Void changeColor(){
 +    Random rd;
 +    red=rd.between(0,3)*80+rd.between(0,16);
 +    grn=rd.between(0,3)*80+rd.between(0,16);
 +    blu=rd.between(0,3)*80+rd.between(0,16);
 +  }
 +  ARGB getColor(Unsigned selector){
 +    ColorUtils cu;
 +    ARGB ret=cu.color(0xff00ff00u);
 +    if(fire==1){
 +      ret[1]=red;
 +      ret[2]=grn;
 +      ret[3]=blu;
 +    }else{
 +      ret=cu.color(0xff090806u);
 +    }
 +    return ret;
 +  }
 +  Void behave(){
 +    Int msum;
 +    if(oc.new()){
 +      initSelf();
 +      du.printContext();
 +    }
 +    msum=getSum();
 +    fire=getFire(msum);
 +    changeColor();
 +  }
 +}
 +</code>
 +
 +We use a ''Once'' quark to call the ''initSelf()'' //once//. We have used a lot of quarks before without realizing that. The ''EventWindow'', ''DebugUtils'', ''Random'', ''AtomUtils'' are all quarks. It's the same thing here to use a ''Once'': instantiate ''Once oc'', then use ''oc.new()'' to decide if this is the first time of a call. 
 +
 +In the ''changeColor()'' of this ''Node'' element, we use ''ARGB getColor()'' to give new color values. This ''getColor()'' returns a array with Four values: //Opacity//, //Red//, //Green// and //Blue//.  
 +
 +Like other Neurons, our ''Node'' will be fired by neighbors. In this simplified case, only the //left neighbors// can trigger our ''Nodes''. This time we need to scan the whole ''EventWindow''. To decide which neighbors are located to the left we use C2D coordinate. Those Atoms with negative x coordinate are to the left of our ''Node''
 +
dev/program_ulam.1432707286.txt.gz · Last modified: 2015/05/27 06:14 by xychen