/CBofN

Source code from the book "The Computational Beauty of Nature"

Primary LanguageCGNU General Public License v2.0GPL-2.0

==========================================================================
CBofN C Source v2.1 --- Copyright (c) 1995--1998 --- by Gary William Flake
==========================================================================

This is the README file for the example source code distribution from my
book ``The Computational Beauty of Nature,'' hereafter abbreviated as
CBofN.  As a shameless sales plug, CBofN is about how nature can be
appreciated in terms of simple computational processes.  The book is in
five parts (Computation, Fractals, Chaos, Complex Systems, and Adaptation)
and explains each topic in terms of the others.  The source code in this
distribution contains many simple example programs of each topic.  Unlike
most other books dealing with these topics, every single image contained in
CBofN can be duplicated by the reader with these programs.

All of the code is written in C and should compile on most any platform.  I
have personally compiled it under Solaris, Linux, and Windows 98.  Each
program is command-line driven, so you only need to compile the program
once to do 99.9% of what they can do.  You may also find the programs
surprisingly powerful given their relatively small sizes.  Moreover, all of
the examples are verbosely documented, so they should be easy to modify.
In fact, the man pages are automagically generated from the C source files
with a Perl script.

You may use the source code for any purpose according to the standard GNU
"copyleft" agreement (also contained in this distribution) as long as you
neither remove nor modify my comments in the code.  Anything else goes.  Of
course, there is no warranty for the code, so if your computer reaches some
sort of semi-conscious state, it ain't my fault.

This README is divided into three more sections.  The first section has
information on how to get a pristine copy of the software distribution as
well as how to get a copy of CBofN.  The second section contains a brief
summary of all of the programs organized by the book part from which the
examples come from.  The final section explains some of the programming
issues involved in producing these examples and will give you some hints if
you want to expand on the programs.

NEWS:  Look in cbn/code/cbn98/README in the distribution for information 
specific to the Windows port.

Enjoy!  -- GWF


============================================
Getting the Source Code of CBofN (and CBofN)
============================================

The home website for CBofN is located at

  https://mitpress.mit.edu/sites/default/files/titles/content/cbnhtml/home.html

Inside the main page there is a link leading to the source code section.
Follow this link.  In the the source code section there are many options
for downloading various source code distributions and precompiled binaries.

To get a copy of CBofN, check out the ordering information section from
the URL above.


================
Program Overview
================

Programs that have graphical output can produce either raw points,
PostScript, PPM, or plot to an X window, Linux VGA, Windows, or Mac
device.  See the ``Programming Issues'' for how the plotting methods
can be expanded.

Computation
-----------

 * STUTTER - a simple lisp interpreter that only understands car, cdr,
   cons, if, set, equal, quote, and lambda, but is still Turing-complete.
   Uses stop-and-copy garbage collection and has an adjustable heap size.
   Examples that implement integer and floating-point arithmetic are
   provided.  There is even an example STUTTER function to compute the
   square root of a floating-point argument with nothing but the primitives
   listed above.


Fractals
--------

 * DIFFUSE - diffussion limited aggregate growth that looks like coral.

 * LSYS - builds L-systems fractals.  Accepts multiple rules so that
   complicated fractals (such as a Penrose tiling) can be expressed.  Great
   for generating plant-like fractals.

 * MRCM - uses the Multiple Reduction Copy Machine algorithm to generate
   affine fractals.  Excepts an arbitrary number of transformations.  Good
   for making snowflakes and mosaic patterns.

 * IFS - similar to MRCM but uses Iterated Function Systems for finer
   granularity.

 * MANDEL - plot the famous Mandelbrot set.  There are options for the
   displayed coordinates, zoom level, coloring schemes, etc.

 * JULIA - generates Julia sets, which are related to the Mandelbrot set
   and has options similar to MANDEL.


Chaos
-----

 * GEN1D - generate a time series from a one-dimensional map.  Nothing
   fancy; it just shows how chaos can be seen in simple systems.

 * BIFUR1D - plot a bifurcation diagram for a one-dimensional map to
   illustrate how a change in a single parameter can move a system from
   fixed-point behavior, to periodic, and finally to chaos.  Different
   regions can be zoomed in on.

 * PHASE1D - plot the phase-space and trajectories of a one-dimensional
   map.  Showing trajectories in the phase space more clearly illustrates
   why fixed-points and limit cycles occur.  This can also be used to show
   the exponential divergence of nearby trajectories.

 * HENON - plot the phase space of the Henon map, a two-dimensional system
   with a fractal shape.  Different regions can be zoomed in on.

 * HENBIF - plot a bifurcation diagram for the Henon system.  This is
   similar to BIFUR1D but shows that bifurcations apply to multidimensional
   systems as well.

 * HENWARP - takes a square of a specified area and ``warps'' it a fixed
   number of times by the Henon system.  This illustrates the stretching
   and folding motion of chaotic systems as well as shows how points within
   an attractor's basin of attraction are eventually forced into a strange
   attractor.

 * LORENZ - plot the phase space of the Lorenz system, a three-dimensional
   system described by differential equations with a fractal shape.  Both
   plain state space plots and delayed state space plots are possible.

 * MG -plot a two-dimensional embedding of the phase space of the
   Mackey-Glass system, a delay differential system, with arbitrary
   parameters.

 * ROSSLER - similar to LORENZ, but uses the Rossler system.

 * GSW - the time evolution of an individual-based three species
   predator-prey ecosystem is simulated according to the specified
   parameters.  The three species consist of plants, herbivores, and
   carnivores (grass, sheep, and wolves; hence the name GSW).  Updates are
   done synchronously, and each species has several parameters which can
   control the life cycle, from the ability to give birth, to the
   likelihood of starvation.  Population statistics of the three species
   can be calculated over a subset of the entire grid.

 * PREDPREY - plot the phase space of a three species predator-prey system,
   a three-dimensional system described by differential equations and with
   a fractal shape.  Both plain state space plots and delayed state space
   plots are possible.

 * LOTKA - integrate the two-species Lotka-Volterra predator-prey system
   with the second-order Euler's method.  This program serves as a simple
   introduction to differential equations.

 * HENCON - control the Henon system with the OGY control law for arbitrary
   choices of the system parameters.  The control law is analytically
   calculated based on the system parameters.  The user can select times in
   which control is turned on and off so that time-to-control and
   transients can be observed.  Gaussian noise can also be injected into
   the system.


Complex Systems
---------------

 * CA - simulate arbitrary one-dimensional cellular automata with an
   arbitrary choice of simulation parameters.  Random rules can be
   generated and used with a desired lambda value.

 * LIFE - simulate Conway's Game of Life with an arbitrary set of initial
   conditions.  Input files need to be in the PBM file format.

 * HP - simulate and plot the time evolution of the hodgepodge machine
   according to specified parameters.  With a proper choice of parameters,
   this system resembles the Belousov-Zhabotinsky reaction which forms
   self-perpetuating spirals in a lattice.

 * TERMITES - Simulate a population of termites which do a random walk
   while possibly carrying a wood chip.  Under normal circumstances, the
   termites will self-organize and move the wood chips into piles without a
   global leader.  The termites' behavior is dictated by the following set
   of rules: If a termite is not carrying anything and she bumps into a
   chip, then she picks it up, reverses direction, and continues with the
   random walk.  If she is carrying a chip and bumps into another, she
   drops her chip, turns around, and starts walking again.  Otherwise, she
   just does a random walk whether she is carrying a chip or not.

 * VANTS - simulate and plot a population of generalized virtual ants
   (vants).  The behavior of the vants is determined by a bit string with
   length equal to the number of states that each cell in the vants' grid
   world can take.  If a vant walks on a cell in state S, then the vant
   turns right if the S'th bit of the rule string is 1 and left if it's 0.
   As it leaves the cell the vant changes the state of the old cell to (S +
   1) % (number of states).

 * BOIDS - simulate a flock of boids according to rules that determine
   their individual behaviors as well as the ``physics'' of their universe.
   A boid greedily attempts to apply four rules with respect to its
   neighbors: it wants to fly in the same direction, be in the center of
   the local cluster of boids, avoid collisions with boids too close, and
   maintain a clear view ahead by skirting around others that block its
   view.  Changing these rules can make the boids behave like birds, gnats,
   bees, fish, or magnetic particles.  See the RULES section of the manual
   pages for more details.

 * SIPD - the spatial iterated Prisoner's Dilemma is simulated and plotted
   over time according to the specified parameters.  Each cell in a grid
   plays a specific strategy against its eight neighbors for several
   rounds.  At the end of the last round, each cell copies the strategy of
   its most succesful neighbor, which is then used for the next time step.
   Possible strategies include 'Always Cooperate,' 'Always Defect,'
   'Random,' 'Pavlov,' and 'Tit-for-Tat.'

 * EIPD - the ecological iterated Prisoner's Dilemma is simulated over time
   according to the specified parameters.  At every time step the
   population of each strategy is calculated as a function of the expected
   scores earned against all strategies weighted by the populations of the
   opponents.  Possible strategies include 'Always Cooperate,' 'Always
   Defect,' 'Random,' 'Pavlov,' and 'Tit-for-Tat.'

 * ASSOC - attempt to reconstruct a potentially corrupted image with a
   McCulloch-Pitts feedback neural network that acts as an associative
   memory.  The weights of the network are determined via Hebb's rule after
   reading in multiple patterns.  Weights can be pruned either by size,
   locality, or randomly.

 * HOPFIELD - solve a task assignment problem via a Hopfield neural network
   while plotting the activations of the neurons over time.  The program
   uses the K-out-of-N rule for setting the external inputs and synapse
   strength of the neurons.


Adaptation
----------

 * GASTRING - use a genetic algorithm to breed strings that match a
   user-specified target string.  This program illustrates how GAs can
   perform a type of stochastic search in a space of discrete objects.
   Reproduction of strings entails crossover and mutation with strings
   being selected based on fitness.

 * GABUMP - use a genetic algorithm to find the maximum of a single-humped
   function that is centered at a user-specified location.  This program
   serves as an example of how GAs can be used to optimize functions which
   take a floating point argument.  Reproduction of strings entails
   crossover and mutation with strings being selected based on fitness.

 * GASURF - use a genetic algorithm to find the maximum of a multi-humped
   function.  This program serves as an example of how GAs can be used to
   optimize function which take a multiple floating point arguments.
   Reproduction of strings entails crossover and mutation with strings
   being selected based on fitness.

 * GATASK - use a genetic algorithm to solve a task assignment problem with
   user-specified costs.  This program illustrates how GAs can perform
   combinatorial optimization.  Reproduction of strings entails special
   crossover and mutation operations which preserve constraints on the form
   of feasible solutions with strings being selected based on fitness.

 * GAIPD - use a genetic algorithm to evolve IPD strategies according to
   user-specified constraints.  This program illustrates how GAs can
   demonstrate co-evolution since IPD strategies can only be successful
   within the context of their likely opponents.  Reproduction of
   strategies entails crossover and mutation with strategies being selected
   based on fitness.

 * ZCS - train a zeroth level classifier system (ZCS) to traverse a
   two-dimensional terrain, avoid obstacles, and find food with the
   implicit bucket brigade algorithm and a genetic algorithm.  At the
   beginning of each step the ZCS is placed at a random location of it's
   world.  It interacts with its environment until it finds food, which
   yields a reward.  The simulation then restarts with the ZCS placed at a
   new random location.  The progress of the ZCS is continuously plotted,
   while the statistics on the time to find food are calculated and
   displayed.  At the end of the simulation the classifiers that make up
   the final ZCS are saved to a log file.

 * ZCSCUP - train a zeroth level classifier system (ZCS) to solve the cups
   problem with the implicit bucket brigade algorithm and a genetic
   algorithm.  Solving this problem requires the ZCS to learn to remember
   important features from previous states, which makes this problem very
   challenging.  The ZCS always starts in the same initial position. It
   interacts with its environment until it finds both cups, which (only at
   that point) yields a reward.  The simulation then restarts with the ZCS
   placed at the original location.  The progress of the ZCS is
   continuously plotted, while the statistics on the time to find both cups
   are calculated and displayed.  At the end of the simulation the
   classifiers that make up the final ZCS are saved to a log file.

 * MLP - train a multilayer perceptron with a single hidden layer of
   neurons on a set of data contained in a file using the backpropagation
   learning algorithm with momentum.  Output units can be linear or
   sigmoidal, allowing you to model both discrete and continuous output
   target values.


==================
Programming Issues
==================

This section briefly describes the programming philosophy that I've been
operating under while producing this source code.  As such, the following
is mostly irrelevant to the casual user, but may be helpful to those who
wish to hack the code.

My primary goal while producing this code has been to make it short and
sweet.  I wanted each program to be comprehensible to others but to also
illustrate something useful.  And since I wanted every image in my book to
be reproducible by the reader, the programs had to be strong enough to do
some non-trivial things.  With this in mind, what follows are the basic
programming guidelines that I've followed.  Note that these are somewhat in
conflict with what most professional hackers would consider good
programming practices.  I make no apologies for having deviated from the
usual heuristics other than to say that I had my reasons.

  Input Interface - completely command-line driven with many options.
  Thus, I have no GUIs to make the code non-portable.  The command-line
  parser is easily understood by others and allows for long option names.
  Thus, there is no need to link to third-party libraries.  Moreover, the
  source code can be parsed by a Perl script to extract the options section
  for man pages.

  Output Interface - for graphics, I use a simple and generic plotting
  interface that maps well into virtually any known plotting technology.
  My plot routines only know how to plot dots and lines and to handle
  simple scaling of coordinates and colors.  The flip side to this is that
  adding drivers is simple.  Currently, I have drivers for X11, PostScript,
  PGM, raw, Linux VGA, and Windows.  Non-graphical output usually goes to the
  standard output.  In some cases, the reader may wish to use another
  third-party program to plot the numerical output.

  Globals - I use them to avoid excessive parameter passing.

  Exception Handling - almost none.  If you give a command-line option a
  nonsense value, a program may very well core dump.  So it goes.  Adding
  nice error checks would have bloated the code considerably.

  Documentation - self extracting and overly verbose.  All programs have a
  detailed comment at the beginning that gives an overview of the code.
  Every significant subroutine is documented.  I've also taken great pains
  to explain any hackery that is non-trivial.  The man pages are generated
  from a Perl script that grabs the initial header comment, the
  command-line options structure, and the help string.  Moreover, the
  header comment has a section entitled "NOTES" that does not appear in the
  man page and only serves to help those perusing the source code.

  Reuse - all programs link to a library named libmisc.a that contains
  many routines that are used by multiple programs.  Included in this are
  the plotting routines, the command-line parser, a simple text scanner
  for parsing data files, code to read PBM files, and other miscellany.

Modifying the code for your own use should be relatively easy.  Here are
some examples of what you may wish to do:

  1. Add a new plotting driver - See pgmplot.c or psplot.c for examples of
     how to write the drivers.  You only need to define four functions
     that initialize the driver, plot a point, plot a line, and finish the
     plot.  Afterwards, the plot_init() function in plot.c needs to have a
     little section of code added to tell the rest of the routines how to
     access the new driver.

  2. Add a feature - For example, you could add options to save and restore
     network weights in mlp.c.  Use the scanning routines to parse the
     output file.  Or, you could add another one-dimensional map to the
     chaos programs.

  3. Adapt the code - The source in zcscup.c is actually a modified version
     of zcs.c altered for a very specific task.  You could similarly
     modify other programs as well.

  4. Experiment with variations - some of the programs are highly
     experimental in that there are no "correct" implementations.  For
     example, you could improve on gsw.c by adding some simple AI to the
     animals.

  5. Just use libmisc.a - you may also use the routines in the common
     library for other tasks unrelated to the programs in this
     distribution.

Regardless of how deep you dive into the source code, I hope you enjoy the
programs.  Happy hacking!  -- GWF

==========================================================================