home *** CD-ROM | disk | FTP | other *** search
-
- Documentation for writing C code to generate Cellsim rules
- Cellsim V2.5
-
-
- ****************************************
- YOU MUST HAVE THE MAKEFILE
- ("Use the Makefile, Luke!")
-
- To use the new method of writing your own rules, you must have a copy
- of the file "Makefile" (which is in the directory "Rule_src" under the
- "V2.5" directory of this distribution of Cellsim); you should have a copy
- of the "Makefile" in the same directory as your C files for the rules.
-
- Note also that the second line of the Makefile, the definition of MDIR,
- should point to the full pathname of the "Rule_mdir" directory under the
- Cellsim V2.5 directory. This is necessary, so that the C compiler will
- know where to find the necessary include file, and the other C files it
- needs to generate your rules.
-
-
- ****************************************
- WRITING AN UPDATE FUNCTION
-
- Update functions must be written in C.
-
- During the following documentation, you are advised to consult the files
- "heat2.m256.c" and "life.m2" in the "Rule_src" directory, as examples of how
- to write an update-function file for both 256-state computed-function rules,
- and lookup-table rules. Writing rules is really much simpler than this
- documentation makes it sound; looking at the examples after you've read this
- will clarify any confusion about the process, I hope.
-
- The first thing in your rule file (besides any comments) should be the line:
-
- #include "nborhood.h"
-
- This will include definitions of the neighborhood structures and
- variables, plus a few macros to extract the neighbors from the structures
- for you.
-
- Next, you should declare all of the functions in your file. You -must-
- declare your update function here. If you are using 256 states and will
- be using "before" and "after" functions, you must declare them too.
- An example of doing this is:
-
- byte my_update_func();
-
- Your update function should return a "byte", which has been typedef'ed
- to be an unsigned char.
-
- Next, if you are using 256 states, you should declare any static variables,
- if you want any. For example, the heat2.m256.c rule defines:
-
- static int hsum=0;
-
- as a private integer it will use.
-
- Note that the following variable names are reserved (they are defined in
- the "nborhood.h" file):
- tl, l, bl, t, c, b, tr, r, br, ll, rr, lll, rrr, cw, ccw, opp, phase,
- x,y,time, parm1, parm2, center, north, south, east, west, northeast,
- southeast, northwest, southwest, clockwise, counterclockwise, and
- opposite.
-
- So be sure you don't define your own variables that would conflict with
- these.
-
-
- The first actual routine in your file must be an initialization routine,
- which will be called once when the rule-file is first used. This function
- -must- have the name "init_function"! In this function, there is one thing
- you are required to do: set the value of "update_function". When using 256
- states, this is necessary so that Cellsim will know what to call to update a
- cell's value; when using fewer states, it is necessary so that the library
- routines will know what function to call to generate the lookup table.
- For example, an initialization function could be:
-
- void
- init_function()
- {
- update_function = my_update_func;
- }
-
- Note that there are *not* parenthesis after "my_update_func". This is
- because we aren't calling my_update_func, we are using its name (actually
- its address) in the assignment statement. If you accidentally say something
- like: update_function = my_update_func(); then things will probably
- crash when you try to run.
-
- Note that the following names are reserved; that is, you cannot use them
- as the names of your own functions:
-
- initialization_function, update_function, before_function, after_function
-
- Cellsim uses these names as pointers to your routines.
-
- Note that if you are using 256 states, you can also set either or both of
- the global parameters in your initialization function, by simply assigning
- values to the variables "parm1" and "parm2". If you are going to be doing
- analysis or modifications on the image array before or after each time-step,
- you can also set the values of the function-pointers "before_function" and
- "after_function", just as you did for "update_function". See heat2.m256.c
- for a demonstration of this.
- When using lookup-table rules, setting parm1 and/or parm2 will have no effect,
- and trying to set either "before_function" or "after_function" will cause
- an error when trying to compile your routine.
-
-
- ****************************************
- THE UPDATE FUNCTION
-
- When using 256 states, your update function will be called for every cell
- in the array, every time step. Therefore, if you run on a 64x64 array for
- a couple hundred time steps, your update function will be called a million
- times! Because of this, you don't want to make your update function
- unnecessarily complicated. When using less than 256 states, your update
- function will be called once for every possible neighborhood configuration,
- to generate the lookup table (e.g. 512 times for the "m2" neighborhood).
- Therefore, it's OK if your function is a little slow, since once the table
- has been generated, your function won't be used again.
-
- Your update function will receive only one parameter; it will be a
- pointer to a structure which contains all of the neighbors of the current
- cell. If you are using 256 states, the structure will also contain the
- current values of parm1 and parm2, the current "time" (what time-step you
- are currently on, as displayed in the Cellsim control panel), and x and y
- coordinates of the current cell (only x coordinate, for linear neighborhoods).
- You must declare that parameter as the appropriate type; the possible
- neighborhood structures are:
- moore_nbors, vonn_nbors, margolus_nbors, lr1_nbors, lr2_nbors, lr3_nbors
- Remember that the parameter is a pointer to a structure, so you would
- declare the parameter for example as:
- moore_nbors *nbors;
- where "nbors" is the parameter to your update-funtion.
-
- There are macros defined to extract these neighbors from their structure
- and store them into local variables. The name of the macro depends on the
- neighborhood. They are:
- Get_moore_nbors, Get_vonn_nbors, Get_margolus_nbors,
- Get_lr1_nbors, Get_lr2_nbors, Get_lr3_nbors
-
- You call them by treating them as a simple statement, i.e. you simply say:
-
- Get_moore_nbors;
-
- That will set the Moore-neighborhood variables:
-
- tl, l, bl, t, c, b, tr, r, br
-
- and parm1, parm2, x, y, time as well, if you are using 256 states
-
- which your function can then use. Note that all of these variables are
- integers, although they will only have 1-byte values in them. They are
- integers to prevent overflow problems that arise when you do arithmetic
- with 1-byte (unsigned char) variables. However, your function should
- still return a 1-byte value.
-
- The rest of your function, after you've called the appropriate macro to
- set the neighborhood variables, should be the actual code to compute the
- new value of this cell. A simple example of computating the new value of a
- cell would be to add the values of the neighbors, and return the sum mod 4,
- assuming you are using a neighborhood with at least 4 states/cell.
- You wouldn't even need a local variable in your function to do this,
- your whole update function could look like this:
-
- byte
- my_update_func(nbors)
- moore_nbors *nbors;
- {
- return (tl + l + bl + t + c + b + tr + r + br) % 4;
- }
-
-
- That's all there is to it.
-
-
- ****************************************
- THE BEFORE AND AFTER FUNCTIONS
-
- If you are using 256 states, then in addition to the update function, you
- can also write an analysis function to be called before the array is updated,
- and another one to be called after the array is updated, if you like. These
- functions can be set in the initialization routine, as described above.
- This feature is not available for lookup-table rules, so that they can
- run as fast as possible. If you need this feature for a 4-state rule, for
- example "myrule.v4.c", then rename your file to "myrule.v256.c" so that it
- will be used as a computed-function rule rather than a lookup-table rule.
- This will let you use the before and after functions; your update function
- will have to make sure it only returns values between 0 and 3, however, if
- that is what you want.
- The before and after functions each receive one argument, which is a
- pointer to a structure containing: a pointer to the current array, the
- current time, the size of the array, and the two global parameters parm1
- and parm2. The precise definition of this
- structure is:
-
- typedef struct {
- unsigned char *array;
- int time;
- int size;
- int parm1, parm2;
- } array_info_struct;
-
- The array is stored as a linear array of bytes; the first byte is the
- upper-left cell, the second byte is the second cell on the first row, and
- so on. You can modify the contents of the array if you wish, or simply
- perform some data analysis and perhaps print out some numbers or store
- them in a file. (You can open a file from your initialization function).
-
-
- ****************************************
- COMPILING YOUR UPDATE FUNCTIONS
-
- If your rule is a 256-state rule, you can simply compile your update
- function by saying, for example:
- cc -c myrule.m256.c
- which will generate a file "myrule.m256.o" which you can then
- load into Cellsim.
- However, since you already had to copy the Makefile from the "Rule_src"
- directory into the current directory, you can just use the "make" utility
- to compile your rule. To do so, you would type:
- make myrule.m256
- and it would generate a file "myrule.m256.sun3.o" (or sun4, if that is what
- you are running on).
-
- The Makefile will also work for non-computed-function (lookup-table) rules;
- for example if you had a file "myrule.v8.c", you could simply say:
- make myrule.v8
- and it would compile your C file, along with another C file supplied as
- part of Cellsim, which contains the main() which loops through all possible
- neighborhoods. It would then generate a temporary executable file to call
- your routines, generate the lookup table, and write the table out to the
- file "myrule.v8". So after you've typed "make myrule.v8" there would be a
- file called "myrule.v8" in the current directory, which is the lookup-table
- file.
-
- You can also edit the Makefile to tell it where to deposit the lookup-tables
- and/or ".o" files once they have been generated.
-
-
- /*
- *
- * Cellsim copyright 1989, 1990 by Chris Langton and Dave Hiebeler
- * (cgl@lanl.gov, hiebeler@heretic.lanl.gov)
- *
- * This package may be freely distributed, as long as you don't:
- * - remove this notice
- * - try to make money by doing so
- * - prevent others from copying it freely
- * - distribute modified versions without clearly documenting your changes
- * and notifying us
- *
- * Please contact either of the authors listed above if you have questions
- * or feel an exception to any of the above restrictions is in order.
- *
- * If you make changes to the code, or have suggestions for changes,
- * let us know! If we use your suggestion, you will receive full credit
- * of course.
- */
-
- /*****
- * Cellsim history:
- *
- * Cellsim was originally written on Apollo workstations by Chris Langton.
- *
- * Sun versions:
- *
- * - version 1.0
- * by C. Ferenbaugh and C. Langton
- * released 09/02/88
- *
- * - version 1.5
- * by Dave Hiebeler and C. Langton May - June 1989
- * released 07/03/89
- *
- * - version 2.0
- * by Dave Hiebeler and C. Langton July - August 1989
- * never officially released (unofficially released 09/08/89)
- *
- * - version 2.5
- * by Dave Hiebeler and C. Langton September '89 - February 1990
- * released 02/26/90
- *****/
-