- Introduction to NausiCAä
- Concepts
- Running NausiCAä
- Using the NausiCAä GUI
- Using NausiCAä as a library
- Reference Guide
- Codon Catalog
- a (Constant)
- ba (Bitwise Left Rotate)
- be (Greater Than)
- bo (Negate)
- bu (Less Than)
- chi (Min)
- cho (Bandpass)
- da (Data Block)
- de (Hyperpolic Tangent)
- do (Duplicate)
- e (Avg N)
- ga (Abort)
- ge (Push All Rotate)
- gi (Avg)
- go (Push All)
- gu (Count DEPRECATED - BROKEN - Use
pu
instead) - ha (Exclamatory)
- he (Convolve)
- hi (Histogram)
- ho (Divide)
- hu (Supersymmetry)
- i (Pow)
- ja (Jump)
- ji (Skip N)
- jo (Min N)
- jya (Relative Coordinate)
- ka (Bitwise Or)
- ke (Greater)
- ki (Push Surrounding)
- ko (Bitwise Rotate Left)
- ku (Bitwise Rotate Right)
- kya (Coordinate)
- ma (Equals)
- me (Sum N)
- mi (Sum)
- mo (Modulo)
- mu (Multiply)
- mya (Mandelbulb)
- na (Lesser)
- ne (Not Equals)
- ni (Square Root)
- no (Push N)
- nu (Cube Root)
- nya (Mandelbrot)
- o (Push Neighbor)
- pa (Push Cardinal)
- pe (Absolute Value)
- pi (Filter)
- po (Equals Array)
- pu (Count - Fixed)
- ra (If)
- ri (Max N)
- re (Sine)
- ro (Skip)
- ru (Sigmoid)
- sa (Stop)
- se (Not)
- shi (Position)
- so (Not Intersects)
- su (Subtract)
- ta (Max)
- te (Time)
- to (Bitwise And)
- tsu (Bitwise Xor)
- wa (Most)
- wo (Least)
- u (Intersects)
- ya (Self)
- yo (Intersects Self)
- yu (Fork)
- za (Halt)
- ze (Random)
- zu (Non-zero)
- Example automata
- Codon Catalog
- Bugs
NausiCAä is an application and library for creating visualizations of computation on discrete lattices in one, two, or three dimensions. Lattices are composed of "cells", where each cell has a coordinate in the lattice. A lattice may be composed of either non-negative integer values, or non-negative real values.
In summary, NausiCAä creates visualizations of computations that are similar to cellular automata, with some notable differences. But the name stuck, so here we are.
This documentation is organized into three main sections. First, we describe the various concepts that NausiCAä uses to create visualizations. Second, we cover how to use the GUI application. Third, we provide a reference guide and example automata.
(Note: In this guide, we use the Mac syntax "⌘" when denoting the meta key in keyboard shortcuts for GUI commands. Substitute this with whatever meta key is appropriate for your OS.)
Automata are a collection of various parameters that are used to generate visualizations. These parameters include Rules, Sequences, Neighborhood, Dimensions, Colors, Values, Palette, Language, Value Kind, and more, and are described in the following sections.
Automata can be loaded and saved, and the visualizations generated by them
can be exported. Automata are stored as .ca
files in JSON text format,
and so can be manipulated via any text editor or other program in
addition to the GUI itself. Visualizations are exported in PNG format.
Video frames can also be generated (i.e., each iteration of the evaluation
is exported as a PNG file in sequence order), or alternatively the entire
set of iterations can be exported as a single animated GIF file.
Visualizations are generated by Rules which are specified using the following syntax:
Cycles[/Weight[;Decay]]:Incantation
- Cycles: Positive integer indicating the number of iterations this incantation will run (only relevant if using Sequences, which will be explained later).
- Weight: Optional update weight (default 1.0). A real value that will be multiplied to rule output value. Can be used to decrease or increase the "speed" at which the lattice changes.
- Decay: Optional weight decay (default 1.0). A real value that if set will change the weight value with each iteration, i.e. weight' = weight * decay.
- Incantation: A kind of genome-like set of codons, written as syllables in the Machine Elvish language, which is described in the Machine Elvish section below.
A Sequence is a list of rules that run in serial one after the other. Each rule in a sequence is called a Stage, and runs for its cycle time, and when the end of the list is reached the sequence repeats with the first rule.
The syntax is simply a list of Rules separated by newlines:
Cycles1[/Weight1[;Decay1]]:Incantation1
Cycles2[/Weight2[;Decay2]]:Incantation2
...
A Neighborhood defines the set of neighboring cells that are available for use during incantation evaluation. Several types of neighborhoods are supported.
All neighborhood types also support a size attribute that is a positive integer. Size 1 means only include cells directly adjacent to the self cell, and each subsequent value (2, 3, ...) expands that range by 1 cell.
All neighboring cells in both cardinal directions and kitty-corner, including self.
All neighboring cells in cardinal directions, including self.
All cells within a discrete approximation of a circle around the self cell, including self. Note that circular neighborhoods only make sense for size > 1, otherwise the neighborhood degenerates into a von Neumann neighborhood.
The automata's Kind defines the type of value stored in each cell in the lattice.
Discrete lattices contain integer values (i.e., Java int type).
Continues lattices contain real values (i.e., Java double type).
RGB lattices contain (red, green, blue) colorspace values in the range of 0-255 packed into integer values. Note that these lattices have no configurable palette, since the RGB value is directly stored in the lattice.
RGBA lattices contain (red, green, blue, alpha) colorspace values in the range of 0-255 packed into integer values. Note that these lattices have no configurable palette, since the RGBA value is directly stored in the lattice.
Machine Elvish is a simple language for expressing computations. It is structured as a sequence of syllables (aka codons) which forms an "incantation" and evaluates over a state which is represented as a stack. Values are pushed to or popped from the stack by each syllable in the incantation. Machine Elvish may manipulate the stack in other ways as well.
Let's look at a very simple example incantation:
ya
This incantation consists of one syllable, "ya". The "ya" syllable represents a computation where the current value of the lattice at the coordinate being evaluated is pushed onto the stack. In other words, it is the identity computation.
An incantation is evaluated for each cell in the lattice. During evaluation, the incantation may store temporary state in a "stack" via push, pop, and related operations. When evaluation is finished, a final value is popped from the stack, and this becomes the new cell value. (Weight may also be applied at this point, if it was specified in the incantation.)
Codons may also be "bonded" together to create compound codons which will be mutated as an atomic unit using the "+" connector. For example:
ki ya+a1+mi2 mu
The compound codon in this incantation adds 1 to the current cell. When the incantation is mutated, for example by swapping the order of two codons, it will be treated as a single codon. So a swap mutation might result in:
ya+a1+mi2 ki mu
This compound codon, slightly more complex, generates a series of circles:
kya0+kya0+mu2+kya1+kya1+mu2+mi2+ni
Listing the codons, metadata, and stack state out one by one:
syllbl codon description stack state
kya0 Coord (x cell coordinate) x
kya0 Coord (x cell coordinate) x x
mu2 Muln (multiply top 2) x*x
kya1 Coord (y cell coordinate) x*x y
kya1 Coord (y cell coordinate) x*x y y
mu2 Muln (multiply top 2) x*x y*y
mi2 Sumn (sum top 2) x*x+y*y
ni Sqrt (square root) sqrt(x*x+y*y)
You might recognize this as an encoding of Pythagoras's distance formula, and results in the visualization:
The set of codons that may appear in Machine Elvish incantations can be controlled by the use of language variants. Variants constrain the set of codons based on one or more of the following criteria:
- Deterministic: A codon that, given a particular Pattern, will always
evaluate to the same value. For example,
a8
always evaluates to8
, orya
which always evaluates to the self cell value. - Nondeterministic: A codon that, given a particular Pattern, may not
always evaluate to the same value. For example,
ze
uses the RNG to evaluate to a random value. - Contextual: A codon that uses the supplemental context during evaluation.
This context provides access to cell coordinates, the RNG, and time step.
For example,
kya0
evaluates to the X coordinate of the current cell. - Positioning: A codon that can affect the execution order of the incantation.
For example,
ja
can skip forward over some number of codons, causing them not to be evaluated, or it can jump backward, causing some number of codons to be evaluated multiple times (e.g., a loop). - Tape: A codon that accesses values on the state stack (tape), or uses other
properties of the stack. For example,
mu2
, which multiplies the top two values on the stack, orshi
, which pushes the current stack size onto the stack.
Language variants can also introduce compound codons. There are currently four language variants: Classic, Universal, Circular, and Fractal.
The Classic variant limits the set of codons to include only those associated with deterministic cellular automata.
The Universal variant sets no limits on codons, meaning that all codons may be used in the incantation.
The Circular variant introduces several compound codons that create circles, ellipses, arcs, and other kinds of curves based on both relative and absolute cell coordinates.
The Fractal variant introduces several compound codons based on the Mandelbrot and Mandelbulb fractals. These compound codons use cell coordinates in various ways to plot either or both fractal sets.
Incantations may contain "variables", which are demarcated by {varname}
within the incantation. For example:
a{var1}
Represents a Constant codon whose value is whatever the value of var1
is set to. Variables are set at execution time and fixed throughout the run.
- JVM 21: You should be able to obtain this for your OS somehow, or it might already be installed. On MacOS, it can be installed via the Homebrew package openjdk.
- JavaFX 21: You should be able to obtain this for your OS somehow.
The link in the most recent stable binary release contains a zipfile with the entire release.
Depending on the host OS, this can then be executed however your OS normally executes
programs. Typically that would be through one of the batch files in the bin
dir. This is clearly non-ideal, but works non-ideally. That means running either
Nausicaa-1.0/bin/nausicaa
or
Nausicaa-1.0/bin/nausicaa.bat
depending on your OS.
NausiCAä uses Gradle for builds. It's currently difficult to build from source because it has some dependencies on libraries that were never published to maven central or any other well-known shared location. That's because it previously used a build system called 'mu' which had its own publishing system.
So, if you want to build from source, the easist way is probably to follow these steps:
- Download and unpack the binary as described above
- Edit the
build.gradle
file and add the location of the unpacked binary'slib
directory to therepositories
flatDir
section. - At this point, gradle should work as usual.
I realize this obviously isn't completely from source, but it's the only way to make it work until I can get the dependencies properly into the shared gradle/maven ecosystem.
NausiCAä stores its configuration in a file in your home directory
called .nausicaa
. This is a JSON file that contains all configuration
options you've set through the GUI.
By default, the main window shows 9 subwindows arranged in a 3x3 grid. The center window displays the "current" automata. Arranged around the center window are 8 random variations on the current automata, generated by "mutating" the current automata's incantation or other attributes.
By clicking on any of 8 surrounding subwindows, you "select" that mutation as the new "current" mutation. It becomes the new center subwindow and 8 subsequent mutations are generated based on it. If instead you click the center subwindow, then it remains the current mutation and 8 different random mutations are generated.
This allows you to arrive at interesting automata by making repeated slight modifications to automata.
The command Window | Hide mutations (⌘Y)
allows you to hide (or show)
mutations so you can focus on the current automata. Continuing the above
example, after hiding mutations the main window will appear as:
The info window at Automata | Info (⌘I)
displays a summary of the
current automata.
Most of the displayed values should be self-explanatory. The most useful display here is the "Codons" value. This value shows an expanded list of the automata's incantation as it will be executed in-order from top to bottom. In the above example, this should be interpreted as
Syll Codon Meaning
go PushA Push all cells onto the stack
u Intersects Pop top 3 values and push 1/0 if/not middle value is between
do Duplicate Duplicate top values
ro3 Skip Pop and discard top 3 values
ko Rotleft Bitwise-rotate using top 2 values, i.e. v1<<v2
ki PushO Push all surrounding cells
zu Nonzero Remove all 0 values from the stack
ri MaxN Push the greatest value of the top N stack values
It should be noted that this particular incantation was generated at random, so doesn't have any specific meaning.
Basic automata parameters are set with Automata | Parameters ... (⌘ K)
.
This can be used to set lattice width, height, and depth (if appropriate).
It can also set prelude, which is the number of iterations to evaluate
before rendering the initial visualization.
Depth is interpreted differently depending on the dimensionality of the automaton and the configured rendering mode.
For 2D automata, depth is used to retain some number of prior lattice states. Then, if the main window is in 2D view mode, the current and all prior states of each lattice cell are projected into a single pixel in the visualization based on the rendering mode (see Rendering Modes for details). If instead the main window is in 3D mode, then the current and all prior states are rendered as a 3D rectangle, with current state at the "top" of the Y (vertical) axis.
For 3D automata, depth is simply the 3rd dimension of the automata's lattice space, rather than a collection of prior states as with 2D automata. Other than that difference, view rendering follows the same process as with 2D automata.
Automata metadata is set with Automata | Metadata ... (⌘⇧K)
.
This window also allows you to set a "name" and "description" for the
automaton. This is arbitrary, optional descriptive text and does not
in any way affect computation or visualization. If provided, they will
be included in the auto-generated text in the Info window. Name is also
used to autogen a filename on save if one has not been provided.
The rule editor window at Window | Show rule editor (⌘G)
displays
(or hides) the current automata's rules, as described in Rules.
To commit to using the edited rule, position the cursor at the end of the rule and hit enter. To discard any changes, simply close the window.
Important: Be sure the cursor is positioned at the end of the rule(s) before hitting enter to set the new rules, otherwise rule(s) will be truncated (this window will be improved in a future release).
The Test
area allows you to enter a pattern to see how the edited rule
will interpret it. Enter each cell value in the pattern space row-by-row, with
each value separated by a space. For example, for a discrete two-value
automata with a Von Neumann neighborhood of size 1, you might specify
0 1 0 1 1 1 1 0 0
The palette editor window at Window | Show palette editor
displays
(or hides) the current automata's color palette. Click on a color to
change it.
Implementation note: The palette editor should only be used with a
small numbers of colors; there is no hard limit, but selecting invididual
colors by hand only really scales when there are less than, say, 100 colors.
For larger palettes, use one of the commands under the Palette
menu
instead, which are designed to deal with huge palettes.
Most of the options on the File menu should be self-explanatory.
- New, Open, Save: Operate on automata and automata serialized as
.ca
JSON files. More details on the New option are provided below. - New from image: Creates a new automata based on characteristics in the chosen PNG or JPEG file, including size, palette, etc.
- Export generated image: Saves the currently-displayed lattice as a PNG file.
- Export generated data: Saves the currently-displayed lattice as a JSON file containing a Base64-encoded string of raw lattice values.
Creates a new automata. The current automata is discarded.
- Dimensions: 1, 2, or 3 depending on number of lattice dimensions (i.e., a line, a square, or a cube).
- Neighborhood Size: Size of surrounding lattice cells that are considered "neighbors" and therefore available during incantation computation.
- Compute: "Machine Elf" allows rules to be expressed in the Machine Elvish language. "Full Target" is the traditional indexed method of referencing automata rules.
- Language Variants: Defines the syllabary for incantations. "Universal" contains all known syllables. "Classic" only contains those syllables necessary to build automata that can be defined by the "Full Target" compute type (e.g., no coordinates, randomness, etc). "Circular" is universal and also includes some compound syllables for building lattices with circular characteristics. "Fractal" contains syllables that can be used to generate fractals. Multiple variants may be selected, and doing so includes the union of all selected variants in the automata. See Language variants for more details.
- Neighborhood: Type of neighborhood. See Neighborhoods for details.
- Kind: Type of lattice to use. See Value Kinds for details.
- Value Colors: Number of allowable values for the lattice. For discrete
automata, this is the color count, i.e. a value of
2
corresponds to an automata that creates lattices with values in [0,1]. For continuous automata, this is the upper bound for the value range. For RGB and RGBA automata, this is fixed at 16777216 (2^24^). - Palette Colors: For continuous automata, number of colors in the palette. Has no effect on other kinds of automata, because in discrete automata the palette colors are equal to the value colors, and in RGB[A] automata the palette is implicit in the cell value itself.
The Automata menu provides options for configuring the current automaton.
Initial state is the starting values of the lattice at time step 0, before any updates are applied. There are several different modes of setting initial state, described below.
This mode sets each value of the lattice to a random value. Options:
- Zero weight: Value between 0 (completely random) and 1 (all values set to 0)
that determines how often a lattice value is set to 0 rather than a random
value. Can be used to create "sparse" lattices. For example, a value of
0.5
causes approximately half of all lattice values to be set to 0 rather than a random value.
This mode sets a single block of lattice values to a specified value. Options:
- Color: Value to set
- X, Y, Z: Lattice coordinate to set. Use
-1
to indicate center. - Size: Size of block to set values, with
1
indicating a single coordinate.
This mode should not be used at present; it needs to be rewritten or removed.
This mode sets lattice values from an image. Options:
- Image: PNG file to use
- Method: "Center" centers the image on the lattice. "Tile" repeats the image across the lattice. "None" simply places the image in the upper-left corner.
- Scale: If set, the image will be scaled to the lattice dimensions.
This mode creates one or more points and sets lattice values around them in a Gaussian distribution. Options:
- Zero weight: Similar to Random Initial State, determines how often a value
is set to
0
rather than a random value. - Max points: Maximum number of points to create distributions around.
- Max radius: Maximum size of distributions around points.
- Density: Real-valued coefficient that determines number of values to set within each point. For example, 0.5 would cut the number of values in half, while 2 would double it.
Similar to Gaussian Initial State, this mode creates one or more points and sets lattice values around them in a Gaussian distribution. However, it also "skews" values created around each point such that each point is "clustered" around part of the automata's value range. For example, if the automata has 100 value colors and there are 3 points, then point 1 would have values 0-33, point 2 would have values 34-66, and point 3 would have values 67-99.
- Zero weight: Similar to Random Initial State, determines how often a value
is set to
0
rather than a random value. - Max points: Maximum number of points to create distributions around.
- Max radius: Maximum size of distributions around points.
- Density: Real-valued coefficient that determines number of values to set within each point. For example, 0.5 would cut the number of values in half, while 2 would double it.
- Skew: Currently unused. Might be used in the future to provide some sort of overlap so that value ranges are not entirely exclusive to each point.
This mode sets the initial state based on a lattice produced by another automata. The automata must be compatible with the current automata in terms of value space (i.e., number of colors). The purpose of this mode is to allow automata to be "chained" together. This is currently only supported for discrete (indexed) automata, not continuous (real) automata. Options:
- Automata: Automata
.ca
file to use - Iterations: Number of iterations to run to produce the lattice that will be used to set the initial state
This mode allows the initial state to be defined using a script written in the Groovy language. The following pre-populated variables are available:
- a: An instance of an org.excelsi.nausicaa.ca.Archetype for the automata
- i: An instance of an org.excelsi.nausicaa.ca.Painter
- r: An instance of a java.util.Random
Lattice values can be set using methods on i
.
Update mode determines how and when values in the lattice are updated.
- Synchronous: All cell updates occur as a single, atomic operation.
- Asynchronous: Cell updates occur at the specified probability in range (0.0-1.0), with 1.0 being equivalent to Synchronous update mode.
- Local Asynchronous: Like Asynchronous mode, except cell update probability is determined by inverse distance from the center of the lattice.
- Energy Asynchronous: Like Asynchronous mode, except cell update probability is determined by the color value of the current cell. Cells whose values are closer to the maximum possible value are more likely to update.
- Variable: Similar to Energy Asynchronous, but uses values drawn from adjacent planes instead of current cell value. Requires a 2D automata with depth > 1.
- Toroidal: The edge "wraps around", that is, the top/bottom and left/right edges are considered to be contiguous to each other.
- Zero: All cells outside the visible area are considered to be 0.
- Constant: All cells outside the visible area are considered to be the specified value.
- None: Lattice cell values are determined solely by the update rule.
- Random: Randomly-valued "snow" is introduced to the lattice at the specified frequency.
- Reroll: Sets a new seed value for this automata's random source and resets the lattice.
- Configure parameters: Displays a dialog for setting lattice width, height, depth, and prelude (number of iterations to run before displaying initial lattice)
- Variables: Displays a dialog for setting variables, if any have been defined. See Variables for details about how to use variables.
- Translate to Universal: If the automata's language (as chosen at creation)
was not
Universal
, then this translates the automata's genome into the universal language. It's not very useful, really, and might be removed in the future.
Animation for both 2D and 3D automata can be started/stopped with the
Animation | Animate (⌘A)
command. Animation iterates through successive
evaluations of the automaton's rule. (1D automata cannot be animated because
successive rule evaluations are simply displayed on the vertical axis.)
The amount of resources consumed by animation is configurable with the
Animation | Configure animation ...
command. At present, only the
Compute cores
option is used; Render cores
is unused but may be used
in the future.
"Compute cores" is the number of concurrent threads used to compute successive lattice values. It should be set somewhere between 1 and the number of cores on your machine, depending on how much CPU you want NausiCAä to be able to consume.
The Animation | Generate to disk (⌘D)
command can write individual
animation frames to a directory as separate PNG files, or it can generate
an entire animation as a single animated GIF file.
- Width & Height: Override currently-configured automata size values. (TODO: add similar for depth.)
- Animate: If checked, each individual frame, or an animated GIF, will be written to disk. Otherwise only the final frame will be written.
- Framerate: Framerate for GIFs. Has no effect when individual frames are written.
- Scaling: Scale factor for frames, e.g., setting this to 0.5 will downscale generated frames by 50%.
- Cores: Number of compute threads to use in animation pipeline.
- Skip frames: Skip over some number of frames during generation. The frames are still computed, but are not written to disk. This can be useful to reduce the size of generated data for slowly-evolving automata. Affects both frame generation and animated GIFs.
- Create GIF: If checked, output will be a single animated GIF file.
- Reverse: Generate frames in reverse (i.e., if generating 100 frames, then frame 0 will be numbered 99, 1 will be 98, etc.).
- Big Bounce: Generate frames from the middle out. This results in a wrap-around kind of effect.
(Note: for the tasks of GIF post-processing and making movies from frames,
the author recommends the excellent gifsicle
and ffmpeg
. Of course
you can use whatever programs work for you.)
The Palette menu provides a number of pre-configured palette options, as well as an option for defining a custom palette, and an option for creating a palette from a source image.
The Palette | Custom Spectrum ...
command creates a random palette based
on the configured options. Note that the exact colors used in the spectrum
change on successive uses of this command. The spectrum is constructed around
some number of "anchor colors". Colors between each anchor color and its
neighbors are then linearly interpolated to create a smooth transition.
Options:
- Number of colors: Number of anchor colors to use
- Density: Currently unused
- Black zero: Always use black for lattice value
0
- Invisible %: Set this percentage of anchor colors to RGBA value
(0,0,0,0)
- Wrap: Make the spectrum "wrap-around". That is, the left-most anchor color is equal to the right-most anchor color.
Mutations can be applied in several ways:
- By selecting one of the randomly-generated mutations in the main window (shown with ⌘Y).
- By using the
Mutations
menu to specifically select a type of incantation mutation. - By enabling other kinds of mutations like Weight variations,
Hue variations, Parameter variations, and Initializer variations,
which are found under the
Mutations
menu. When enabled, these mutations will also show up as randomly-generated mutations in the main window.
- Jumble: Randomly shuffles some number of codons in the incantation.
- Decimate: Removes approximately 33% of codons in the incantation at random.
- Chomp: Removes the entire first third of codons in the incantation. This can be useful in reducing computational cost by identifying "junk" sections of the incantation that no longer have an impact on the final produced value.
- MakeDeterministic: Removes all non-deterministic codons from the incantation.
As of this writing, the only non-deterministic codon is
ze
, which produces random values. - Symmetry: Currently unimplemented; does nothing.
- Transmute: "Transmutes" some number of random transmutable codons in the incantation,
if there are any. Certain sets of codons are transmutable into each other. For example,
mu
(multiply) andho
(divide) are such a pair. The full list of transmutable sets is:be
(greater than),bu
(less than)bi
(cos),de
(tanh),re
(sin),ru
(sigmoid)kya
(coordinate),jya
(relative coordinate)mu
(multiply),ho
(divide)ni
(square root),nu
(cube root)
- Bond: Randomly takes an adjacent set of codons in the incantation and bonds
them into a compound codon. Note that
Allow bond mutations
on theMutate | Parameters...
option must be set to enable bond mutations. - Unbond: If the incantation contains any compound codons, has a chance
of unbonding one or more such codons. Note that
Allow bond mutations
on theMutate | Parameters...
option must be set to enable bond mutations. - Adjust: "Destabilizes" some number of random unstable codons in the
incantation, if there are any. An unstable codon is one that can be modified
in some way without changing the codon syllable itself. Any codon whose
syllable includes a numeric suffix can be modified. For example, the
a
(constant) codon could be modified froma8
toa42
. - Add: Adds a new random codon to the end of the incantation.
- Remove: Removes a codon from the incantation at random.
- Replace: Replaces a codon in the incantation at random, with a new random codon.
- Repeat: Copies a random portion of the incantation and adds it onto the
end. For example, given the incantation
go mi ya mu
, a repeat mutation might copy theya mu
portion, resulting in the new incantationgo mi ya mu ya mu
. - Insert: Inserts a new random codon at a random location in the incantation.
- Duplicate: Duplicates a codon in the incantation at random. The duplicate is inserted adjacent to the original codon.
- Swap: Swaps the locations of two codons in the incantation, at random.
Recall that a Sequence is a series of Stages composed of Rules which execute one after the other, then repeat from the beginning.
Stages can be added or removed using the Mutate | Add rule stage
and
Mutate | Remove active rule stage
commands. By default, the
active rule stage becomes the most-recently added stage. This may be
configured under Mutate | Parameters...
(Mutation stage), with the
first stage being numbered 0. If the mutation stage is set to -1,
then all stages will be subject to mutation.
When an automata has been defined as either of type RGB or RGBA, this option can be used to determine the way lattice cell values are interpreted during next-value computation. For indexed (discrete) or real (continuous) automatons, this option doesn't make sense, though it can still be toggled.
- Combined: The incantation is computed on the lattice cell value. Mapping the value to a palette color occurs elsewhere.
- By channel: Each lattice cell is presumed to hold an RGBA value. Each channel (R, G, B, and optionally A) is extracted from the value and the incantation is computed for each channel, then all values are recombined into the new RGBA lattice cell value.
TBD.
Depending on how composition is configured, the same automata may be visualized
in different ways. For example, here is the same 200x200x40 2D automata
with prelude 20 rendered first with Render | Composition mode | Nearest only
and then as Render | Composition mode | Weighted average
:
These and other composition modes affect how the "depth" dimension is rendered to the two-dimensional visualization. (TODO: Not all composition modes are currented supported at all dimensions.)
- Nearest only: Use only the first non-zero cell value in range (depth-1,0).
- Farthest only: Use only the first non-zero cell value in range (0,depth-1).
- Weighted average: Use an average of all cell values, weighting those with higher depth (i.e., more recent iterations) higher.
- Weighted average reverse: Use an average of all cell values, weighting those with lower depth (i.e., less recent iterations) higher.
- Average: Use an average of all cell values, weighed equally.
- Channel: Depth must be set to 3 or 4. With depth 3, renders packed RGB values using depths (0,1,2). With depth 4, renders packed RGBA values using depths (0,1,2,3).
- Multiply: Uses a value computed from cells at all depths multiplied together, normalized between (0,255).
- Difference: Uses a value computed from the total difference between each successive cell value at all depths, normalized by depth.
- True Nearest: Uses only the cell value at the highest depth.
NausiCAä is packaged with a number of custom functions written in the
Groovy language. These functions operate as a kind of scripting language.
Sources for all functions can be found in the etc/functions
directory
under the application's root directory. New functions can be added here
as well (and eventually a location outside the distribution will be
supported).
Brief descriptions of the currently-packaged functions follows.
- Directory Index: Builds a visual index from a directory of CA source files
- Weight Walk: Generates a series of images by linear adjustments to the chosen CA's weight parameter.
- Random Walk: Generates a series of images by randomly modulating variables defined for the current automata.
- Jfx Screen Capture: Periodically captures screenshots of the current JFX scenegraph.
- Directory Visualizer: Use Directory Index instead
- Param Generator: Generates a series of images by linearly modulating a single variable between arbitrary starting and ending values.
Most options on the View menu should be self-evident. The one which
requires some explanation is Toggle animations
. This option only applies
to 3D render mode, and toggles whether or not the rendered lattice is
spun about or shown from a static angle.
This menu is a repository for incomplete features.
This menu controls which windows are displayed and their display modes.
- Show/hide mutations: Controls whether or not mutations are displayed in the Main Window. Refer to that section for more information about how to use mutations.
- Show/hide palette editor: The palette editor can be used to modify individual colors in the current palette. Note that this is only feasible when the automata contains a small number of colors. When the colorspace is large, it is more effective to modify the palette using one of the options on the Palette Menu. See Palette Editor Window for more information on using the palette editor.
- Show/hide rule editor: The rule editor can be used to modify all aspects of the automata's generation process, including the sequence, weights, and incantations. See Rule Editor Window for more information.
- Show/hide language editor: The author needs to refamiliarize himself with this part of NausiCAä before writing documentation on it.
- Toggle console: Toggles the interactive Groovy console window.
Here is a brief list of a few of the more often-used GUI commands.
File menu: Handling automata files
- ⌘N - Create a new automata
- ⌘S - Save current automata
- ⌘O - Open a previously-saved automata
Automata menu: Basic automata parameters
- ⌘K - Set lattice width, height, and depth (if appropriate). Also sets prelude, which is the number of iterations to go through before rendering the initial visualization.
- ⌘I - Display an informational window describing the current automata.
Automata menu: Setting initial lattice state
- ⌘B - Use a random initial state; the lattice is set to random values within the value space weighted toward 0 based on the zero weight as set between (0.0,1.0).
- ⌘F - Use a "fixed" initial state; the specified coordinate is set to the specified value (or -1,-1,... for center) and all other coordinates are set to 0.
- ⌘G - Gaussian initial state; one or more clusters of values are created based on specified attributes.
- ⌘L - Clustered Gaussian initial state; similar to Gaussian initial state, but values for each cluster are pulled from different value ranges; i.e., with 2 clusters, one cluster may have value ranges 0-9 and the other may have value ranges 10-19.
Animation menu: Animating 2D and 3D automata
- ⌘A - Start/stop iteration animation.
- ⌘D - Write animation frames to disk so they can be used within a video editor, or write an animated GIF to disk.
Render menu: Configuring visualization rendering
- ⌘⇧V - Toggle between 2D and 3D rendering modes
View menu: Viewing visualizations
- ⌘= - Zoom in
- ⌘- - Zoom out
- ⌘0 - Actual size
Window menu: Automata windows
- ⌘Y - Show/hide mutations in main window
- ⌘G - Show/hide incantation editor window
NausiCAä can also be used as a Java library completely independent from the GUI.
All relevant classes are under the org.excelsi.nausicaa.ca
package.
Syntax: a*Value*
Pushes Value onto the stack, where Value is any integer or real value. Note that discrete automata may only use integer values.
Syntax: ba
Pushes the bitwise-left-rotated value of the top stack value rotated by the next top stack value. Note that this is only supported for discrete automata. For continuous automata, the top stack value will simply be pushed back on the stack.
Syntax: be
Pushes 1
if v1>v2
, else 0
. where v1 and v2 are the top two stack values.
Syntax: bo
Pushes the negation of the top stack value. For example, if the stack is [5 3 1], the new stack will be [5 3 -1].
Syntax: bu
Pushes 1
if v1<v2
, else 0
. where v1 and v2 are the top two stack values.
Syntax: chi*Value*
Pushes the minimum value of the top Value values onto the stack. Value is optional; if not specified, all values on the stack are considered (i.e., the entire stack).
Syntax: cho
Uses the top three stack values as up
, low
, and mid
to determine if
mid
falls between low
and up
, inclusive. If true, pushes mid
, otherwise
pushes 0
.
Syntax: da*Data*
TBD.
Syntax: de
Pushes the hyperbolic tangent of the top stack value. This codon only works with continuous automata. For discrete automata, it does nothing.
Syntax: do
Peeks at the top stack value and pushes it again. For example, if the
stack is 1 2 3 4
, then the result is 1 2 3 4 4
.
Syntax: e
Pushes the average of the last N values onto the stack, where N is the top
value on the stack, and not included in the average. For example, if the stack
consists of 4 2 1 3
, then N is 3 and (4+2+1)/3
will be pushed.
Syntax: ga
Pushes Self and stops evaluation.
Syntax: ge
Pushes all Neighbor cell values including Self onto the stack, "rotated" by the top stack value. For example, if the top value is 4, pushes cells beginning at index 4.
Syntax: gi*Value*
Pushes the average of the top Value values onto the stack. If Value is not specified, then the entire stack is considered.
Syntax: go
Pushes all Neighbor cell values including Self onto the stack. Self is always pushed last.
Syntax: gu
Counts the number of values in the pattern that are equal to the top stack
value and pushes the count. Note: Does not actually do this, use pu
instead.
Syntax: ha
Pushes N!
, where N is determined by the top stack value. Note 1: This
can be quite expensive to compute for large values. There are no guardrails
and no overflow check.
Note 2: For continuous automata, this does nothing.
Syntax: he
Pushes a value computed by summing and multiplying parts of the pattern and the stack.
Syntax: hi
Computes a histogram of all values in Pattern and pushes it to the stack
in size order. For example, if the pattern is 1 5 7 2 5 7 7 7 1
, then
it will push 1 2 2 4
.
Syntax: ho
Pushes the division of the top two values onto the stack. In the case of division by zero, simply pushes the top value back.
Syntax: hu
Pushes the value that is "opposite" to the top stack value and the middle value, based on the number of colors in the automata. For example, if the automata has 4 colors, then color 1 is opposite color 2, and color 0 is opposite color 3.
Syntax: i
Pushes v1^v2^ onto the stack, where v1 and v2 are popped off the stack. Note that for discrete automata, if v2 is less than 0 it will be replaced by 0.
Syntax: ja
"Jumps" forward or backward a number of codons determined by the top stack value. This can allow evaluations to loop (by jumping backward), or to skip (by jumping forward). There is a maximum number of codon evaluations allowed per cell, so infinite loops are impossible. This is currently set to 1000. In such cases, the evaluation is forcibly terminated, with the evaluation result being whatever value was at the top when the loop was broken.
Syntax: ji
Pops N values off the stack, where N is determined by the top stack value (which is popped before the skip and thus not counted as part of the skip).
Syntax: jo
Pushes the minimum of the last N values onto the stack, where N is the top
value on the stack, and not included in the minimum. For example, if the stack
consists of 4 2 1 3
, then N is 3 and 1
will be pushed.
Syntax: jya[0|1|2]
For continuous automata, pushes either the relative x
, y
, or z
cell
coordinate, depending on which numeric argument is used. If no numeric
argument is specified, pushes all available coordinates, depending on the
dimensionality of the automata. Relative coordinates range from -1.0 to 1.0,
with 0.0 at the center of the lattice. For discrete automata, functions
the same as kya
.
Syntax: ka
Pushes the bitwise-or value of the top two stack values. Note that this is only supported for discrete automata. For continuous automata, the top stack value will simply be pushed back on the stack.
Syntax: ke
Pushes 1 or 0, depending on whether v1>=v2
, where v1 and v2 are the top two
stack values.
Syntax: ki
Pushes all surrounding cells values onto the stack. The definition of "surrounding" depends on two factors: (1) Neighborhood type (Moore, von Neumann, or Circular), and (2) Neighborhood size.
Syntax: ko
Pushes the bitwise-left-rotated value of the top stack value rotated by the next top stack value. Note that this is only supported for discrete automata. For continuous automata, the top stack value will simply be pushed back on the stack.
Syntax: ku
Pushes the bitwise-right-rotated value of the top stack value rotated by the next top stack value. Note that this is only supported for discrete automata. For continuous automata, the top stack value will simply be pushed back on the stack.
Syntax: kya[0|1|2]
Pushes either the x
, y
, or z
cell coordinate, depending on which numeric
argument is used. If no numeric argument is specified, pushes all available
coordinates, depending on the dimensionality of the automata.
Syntax: ma
Pushes 1 or 0, depending on whether v1=v2
, where v1 and v2 are the top two
stack values.
Syntax: me
Pushes the sum of the top N values onto the stack, where N is the top
value on the stack, and not included in the sum. For example, if the stack
consists of 4 2 1 3
, then N is 3 and 4+2+1
will be pushed.
Syntax: mi*Value*
Pushes the sum of the top Value values onto the stack. Value is optional; if not specified, all values on the stack are summed (i.e., the entire stack).
Syntax: mo
Pushes v1%v2
, where v1 and v2 are the top two stack values. If v2 is 0,
simply pushes v1.
Syntax: mu*Value*
Pushes the product of the top Value values onto the stack. Value is optional; if not specified, all values on the stack are multiplied (i.e., the entire stack).
Syntax: mya
Pushes the Mandelbulb Set value using the top five values on the stack, defined
in order as scl
(scaling factor), z
(iterations), x
, and y
, and z
(coordinates). For safety, iterations is capped at 100. While this codon is
intended to be used with 3D automata, it can be used with any dimensionality
since the coordinate values are popped from the stack. Note that this produces
a discrete approximation of the fractal, as lattices are discrete in nature.
Syntax: na
Pushes 1 or 0, depending on whether v1<=v2
, where v1 and v2 are the top two
stack values.
Syntax: ne
Pushes 1 or 0, depending on whether v1!=v2
, where v1 and v2 are the top two
stack values.
Syntax: ni
Pushes the square root of the absolute value of the top of the stack.
Syntax: no
Pushes the Nth pattern value, where N is determined by the top value on the stack. The pattern contains both neighbor cells and self.
Syntax: nu
Pushes the cube root of the top of the stack.
Syntax: nya
Pushes the Mandelbrot Set value using the top four values on the stack, defined
in order as scl
(scaling factor), z
(iterations), x
, and y
(coordinates).
For safety, iterations is capped at 100. While this codon is
intended to be used with 2D automata, it can be used with any dimensionality
since the coordinate values are popped from the stack. Note that this produces
a discrete approximation of the fractal, as lattices are discrete in nature.
Syntax: o*Neighbor*
Pushes Neighbor onto the stack, where Neighbor is the index of any cell in the set of neighboring cells. Index values wrap around, so attempts to push indeces greater than the size of the set of neighbors are "safe".
Syntax: pa
Pushes all cells lying in cardinal directions from the main cell.
Syntax: pe
Pushes the absolute value of the top stack value.
Syntax: pi*Value*
Bugged
Syntax: po*Value*
If an entire array up to length Value is equivalent to a compared array, returns 1, else 0.
Syntax: pu
Counts the number of values in the pattern that are equal to the top stack value and pushes the count.
Syntax: ra
Pops the top three stack values as cond, tr, and fl (condition, true case, and false case). If cond is non-zero, pushes tr, otherwise pushes fl.
Syntax: jo
Pushes the maximum of the last N values onto the stack, where N is the top
value on the stack, and not included in the maximum. For example, if the stack
consists of 4 2 1 3
, then N is 3 and 4
will be pushed.
Syntax: re
Pushes the sine of the top stack value. This codon only works with continuous automata. For discrete automata, it does nothing.
Syntax: ro*Value*
Pops Value values off the stack.
Syntax: ru
Pushes the sigmoid of the top stack value. Specifically, 1/(1+e^-v^), where v is the top stack value. This codon only works with continuous automata. For discrete automata, it does nothing.
Syntax: sa
The top of the stack is popped, and if 0 stops evaluation.
Syntax: se
Pushes 1 if the top stack value is 0, otherwise pushes 0.
Syntax: shi
Pushes the current position (i.e., size) of the stack. For example, if the stack is "5 3 3 1", then pushes 4.
Syntax: so
Tests if mid<low || mid>high
, where all three values are popped off the stack
in the order high, low, mid. Pushes 1 (true) or 0 (false).
Syntax: su
Pushes v1-v2
, where v1 and v2 are the top two stack values.
Syntax: ta*Value*
Pushes the maximum value of the top Value values onto the stack. Value is optional; if not specified, all values on the stack are considered (i.e., the entire stack).
Syntax: te
Pushes the current iteration count, starting from 0. Note that for animated automata, this value will only be consistent over the duration of a single animation execution. If the animation is stopped and started again, time will reset to 0. For step animation, the value will always be 0.
Syntax: to
Pushes the bitwise-and value of the top two stack values. Note that this is only supported for discrete automata. For continuous automata, the top stack value will simply be pushed back on the stack.
Syntax: tsu
Pushes the bitwise-xor value of the top two stack values. For continuous automata, real values are converted bitwise to integers, then bitwise back to reals after the xor operation.
Syntax: wa*Value*
Pushes the value that occurs the most of times in the pattern.
Syntax: wo*Value*
Pushes the value that occurs the least of times in the pattern.
Syntax: u
Tests if low<=mid<=high
, where all three values are popped off the stack.
Pushes 1 (true) or 0 (false).
Syntax: ya
Pushes the current cell value onto the stack.
Syntax: yo
Tests if low<=mid<=high
, where all three values are popped off the stack.
Pushes mid
if true, or 0 if false.
Syntax: yu*Value*
Fork skips over a variable number of stack values based on a Neighbor value, specified by index using the optional Value. If Value is not specified, Self is used. This can also be used to effectively branch evaluation within the incantation if used in tandem with Stop codons for each branch. Further description TBD as this works in mysterious ways and I'm tired.
Syntax: za
Stops evaluation. The evaluation result is whatever value is currently the top stack value.
Syntax: ze
Pushes a random value between 0 and N, where N is determined by the top stack value. If N is negative, pushes a random negative value between 0 and N. If N is 0, pushes 0.
Syntax: zu*Value*
Filters all non-positive values from the stack for the top Value values. If Value is not specified, the entire stack is considered.
Bug: This should probably not filter negative values, but alas.
Some examples of the kinds of automata you can make with NausiCAä are reproduced below.
You can also find more complex automata videos created with NausiCAä on the channels:
- YouTube: https://www.youtube.com/@excelsiorg5126/videos
- Vimeo: https://vimeopro.com/jkwhite/explorations-in-automatic-spaces
Incantation:
ki mi a2 a3 u ki mi8 a3 ma ya ra
This is the classic Game of Life (Conway's Life) automata, which has two colors and a Moore neighborhood of size 1.
We can go through the incantation to understand how it operates.
ki PushO
mi Sum
a2 Constant
a3 Constant
u Intersects
ki PushO
mi8 Sumn
a3 Constant
ma Equals
ya PushS
ra If
The first two syllables, ki mi
, computes the total number
of "living" cells (value of 1) in the surrounding neighborhood,
excepting the self cell, which we'll call N. The next two syllables,
a2 a3
, pushes those the two constant values 2 and 3 onto the stack as well.
So our stack now consists of 3 2 N
. Next, we apply an intersection
test with u
, and push 1 or 0 depending on whether 2 <= N <= 3. (This
could also be done with a combination of conditionals and boolean logic
syllables.) The stack is now [0|1]
, depending on the result of the test.
Next, we repeat the first two syllables with ki mi8
, with
the '8' value being necessary to avoid consuming the entire stack. (This
could have alternately been done with a du
(duplicate) syllable earlier
in the incantation, which would have been more efficient because it avoids
a second memory copy, but I'll leave that as an exercise for another time.)
The next two syllables, a3 ma
, determine whether exactly 3 cells are alive
and push either 1 or 0. Next we push the self cell with ya
.
The two branches of the conditional and the condition itself are now all set
up on the stack, and finally, with ra
(If), we branch to the final result
based on the self cell value, in accordance with the Life rule. This isn't
a particularly efficient implementation, but it is straightforward. There are
other possible implementations that would be more efficient, like I mentioned
above with the du
syllable, and we could also avoid computing the unused
branch by using ja
(jump) and za
(halt) syllables instead.
A few additional 2D automata.
"Infrastructure Building"
136/0.7266794730647169;1.177500966682681:kya kya bo ge ta ge to
"Fractal Bubbles and Growing Chiralities"
90/0.06062264974050879;1.2621854231957927:ki u ki su ya ge bu ro4 ra nya e zu9 mi6 mi5 mi5
"Flower of the Sun"
127/0.4275963042584565;1.011692219854403:ze mi kya0+kya0+mi2+kya1+kya1+mi2+mi2+ni kya0+kya0+mu2+kya1+kya1+mu2+mi2+ni mi11 kya1 yu pa go gi yu ko
Selected examples of 2D circular neighborhoods of sizes 3-5.
"Slippery"
88/0.5;0.9:jya0 pa wo o30 ke ke ki
"Nitelite"
0.62;1.21:bu ki kya0 bo pa wo ke ke ki o30 ta2
"Ringu"
0.16;0.95:ma chi1 chi1 sa pa ko ma o16 o14 ru sa bo pa jya jya0 pe gi pe chi mi
These examples use Sequences.
"Plasmoria"
8/0.10699023686190517;0.9:ki hu hu ki ki zu8 hu o12
8/0.02103008643143056;1.2770407481000805:ki ki no o12 ki do do zu o12
8/0.007479068112474223;1.0344350114269145:ki no hu do zu6 zu ki
"Bioluminous Glitch"
5/0.45819994332545555;1.2032942437605973:kya0 wo wo mi ku mi mi o4 pa ya ko kya1 wo wa
4/1.0;0.9562614045563055:jya go ne go ri
Simple discrete mappings of the Mandelbulb fractal.
"Mandelbulb"
98:kya0 kya1 kya2 a100 a100 mya
"Mandelbulb Animated"
98:kya0 kya1 kya2 a10 a100 mya a-1000 a0 cho
"Bulb slice in 2D"
"The Desert Stars Are Bright Tonight"
81/0.7079684605220907;1.2319639843877077:a-2.0188958644866943 pu jya1 kya0+pe+kya0+pe+mi2+kya1+pe+kya1+pe+mi2+mi2+ni to i kya0+pe+kya0+pe+mi2+kya1+pe+kya1+pe+mi2+mi2+ni wa ho wa a24 ho hi ji
-
This documentation is incomplete.
-
Building from source is probably not possible right now for anyone but me. The problem is with dependencies on other projects that I own that are not on github or in maven central etc. I need to get this worked out ASAP. I don't think it will take a lot of engineering effort, it's mostly about mapping projects hosted on a private SVN server for many years to something that works for the public modern world.
-
There are way too few sanity checks around reasonable limits. For example, can you create a 3D automata in 1024^3 size? Maybe, maybe not. Or an automata with 1MM palette colors? I honestly don't know. The only sanity check that exists currently is with the Machine Elvish execution--where it's limited to a certain number of evaluations per cell. This is a simplistic way of avoiding infinite loops. So it's not possible to consume infinite processing time, but it is possible to (try to) consume infinite memory.
-
Speaking of limits, the JavaFX 3D renderer dies above a few hundred thousand points. The renderer uses an algorithm to combine cells into larger blocks to minimize the vertex and face counts, and this helps somewhat, but there's a lot more that can be done.
-
Updates in the GUI that fail get reported through the console logger rather than proprer GUI reporting.
-
3D mode is quite brittle. It works fine at low limits, but pretty much anything can set it off. I am looking at alternatives to JavaFX screengraphs.
-
The Histogram codons use the library GNU Trove. Trove has a bug that causes its hashtables' internal data structures to become inconsistent, and this manifests in the 'hi' codon failing in otherwise-normal circumstances. I need to determine whether to keep this codon, or find a different way to use Trove that avoids the bug, or replace Trove altogether.
+++ATH0