A cellular automaton, or CA, is a computational model made up of a grid of cells in any number of dimensions that dynamically changes state in response to the states of the cells around it. This project describes the Mutate and Sort algorithms that I developed to convert any 1D CA into another 1D CA and any 2D CA into another 2D CA, given that all CAs are executed for the same period of time, as well as explain the basics of 1D and 2D Cellular Automata. 

Introduction to One-Dimensional Cellular Automaton

1D Cellular Automaton(Elementary Cellular Automaton) is the most basic type of CA. It contains a 1D grid of cells that only have 2 possible states, 1 or 0. 1 is represented as a black cell and 0 as a blank cell. In the grid, a cell and its two neighbors form a neighborhood and the CA rule contains all the 8 combinations of a neighborhood. Each combination of a neighborhood is assigned a 1 or a 0, determining the current cells future state.
We can access Rule 30 and the rule icon for Rule 30
In[]:=
ResourceFunction["ComputationalSystemRules"][CellularAutomaton[30]]​​RulePlot[CellularAutomaton[30]]
Out[]=
{{1,1,1}0,{1,1,0}0,{1,0,1}0,{1,0,0}1,{0,1,1}1,{0,1,0}1,{0,0,1}1,{0,0,0}0}
Out[]=
We can easily visualize Rule 30 as well, for 15 steps. Each row represents a new step.
Rasterize[ArrayPlot[CellularAutomaton[CellularAutomaton[30],{{1},0},15]],ImageResolution->200]
Out[]=
It can be observed that an Elementary Cellular Automaton is essentially an array of associations between an array and an integer. In order to mutate a rule, it is necessary to be able to access the basic rule without any visualizations and tinker with the values of the association.

Mutate and Sort Algorithms for Elementary CA

Show Rule Function

I first created a simple function that would visually show a given rule for 15 steps when ran.
In[]:=
showrule[rule_]:=​​Module[{},​​Rasterize[Show[ArrayPlot[CellularAutomaton[rule,{{1},0},15]],ImageSizeTiny],ImageResolution->200]​​]

Mutation Function

The mutation function essentially takes in a rule and mutates the values of the association in the rule given a certain probability. I set the probability to 0.4 meaning the mutation function randomly mutates a given rule with less than a 40% chance. The lower the mutation probabiity, the more iterations the algorithm has to do, therefore increasing the runtime. This mutation function will be run several times to give the computer a wide range of mutations to choose from.
In[]:=
mutateRule[rule0_]:=Module[{rule=rule0},(​​(Keys[#]->​​If[RandomReal[]<=mutationProbability,RandomChoice[{0,1}],​​Values[#]])&/@rule​​)​​]

Sort Function

The sort function takes in a list of the images of the mutated rules, a list of the mutated rules and the target image. The reason why it needs to take in a list of the mutated images and the mutated rules is because the function creates an association, using Thread, between each image and rule and then sorts them out based on how close the image is to the target image.
In[]:=
sortedrules[imageofrules_,listofrules_,trgtimg_]:=​​Module[{imgrul=imageofrules,rules=listofrules,target=trgtimg},​​SortBy[​​Thread[imgrul->rules],​​(​​ImageDifference[​​ColorConvert[​​ImageResize[Rasterize[Keys[#]],ImageDimensions[target]],"Grayscale"​​],​​target​​]​​)&​​]​​]
This association is necessary because the optimal approach for the sorting algorithm would be to only sort out the mutated rules based on how close it is to the target rule and then run showrule on the closest rule. We can simulate this with the mutated rules of rule 186 and the target rule of rule 30. The code and errors would be as shown.
In[]:=
fakesortedrules[listofrules_,trgtrule_]:=​​Module[{mutated=listofrules,target=trgtrule},​​nearestrul=Part[Nearest[mutated,trgtrule],1];​​]​​fakesortedrules[ResourceFunction["ComputationalSystemRules"][CellularAutomaton[186]]&/@mutatedRules,ResourceFunction["ComputationalSystemRules"][CellularAutomaton[30]]]
Nearest
:mutatedRules is neither a list of real points nor a valid list of rules.
Unfortunately, this approach does not work because you cannot find use Nearest between two lists of associations.

Automate Function

During each iteration, the automate function runs the mutate and sort functions, extracts the closest rule to the target rule, runs show rule on the rule and then call itself while passing in the new rule. It does this until both the initial rule and the target rule and the initial image and target image are the same. The automate function takes in a rule and a population. The population is a number that determines the amount of mutations of that rule. A large population creates more mutations of the rule which gives the algorithm a wider range of rules to work with. The wide range of rules decreases the number of iterations but increases the amount of time of each iteration since it has to produce more mutations and sort more rules. I found 20 to be a population number not small enough to substantially increase the number of iterations but also not large enough to substantially increase the length of each iteration.
In[]:=
automate[rule_,population_]:=​​Module[​​{},​​mutatedRules=Table[mutateRule[rule],population];​​​​​​While[​​UnsameQ[initialrule,finalrule]&&UnsameQ[showrule[initialrule],showrule[finalrule]],​​rulesimages=ArrayPlot[CellularAutomaton[#,{{1},0},15]]&/@mutatedRules;​​initialrule=Values[​​First[​​sortedrules[rulesimages,mutatedRules,targetimage]​​]​​];​​Print[showrule[initialrule]];​​count+=1;​​automate[initialrule,20];​​];​​]

Rule Picker Function

In order to test out the the algorithm, I decided to randomly pick out an initial rule and a target rule out of a list of all possible 1D rules, and try mutating the initial rule to be the target rule. I did not want the two rules being the same, so I added in an If statement to check if they were the same and then run the function again.
In[]:=
rulepicker[rules_]:=​​Module[{},​​finalrule=rules[[RandomInteger[{1,255}]]];​​targetimage=Rasterize[ArrayPlot[CellularAutomaton[finalrule,{{1},0},15]]];​​initialrule=rules[[RandomInteger[{1,255}]]];​​If[​​SameQ[finalrule,initialrule],​​rulepicker[rules],​​Null;​​]​​]

Initialization and Execution

The code below, when run, initializes the list of all possible rules, the variable count which stores the amount of iterations of automate, and the mutation probability. It also runs rulepicker and the automate function.

Introduction to Two-Dimensional Cellular Automaton using Substitution System

We can visualise this System for 4 steps
We can also easily extract any step of the Substitution System, which will be important later.
We can visualize the first 10 Substitution Systems through 5 steps
The main idea here is that in order to mutate the rule, we need to change the elements inside the 2D array associated with the integer in the rule.

Mutate and Sort Algorithms for Two-Dimensional CA

Show Rule Function

Just as I did in the Elementary CA, I first created a show function that visually shows the rule through 5 steps.

Mutate Function

The two mutate function takes in a rule and a mutation probability. It iterates through the rule picking a random real number each time and randomly changing the value if the random real is less than or equal to the mutation probability.

Sorted Rules

The sorted rules function is the exact same as the Elementary CA sorted rules function and performs the same function; returning an sorted association of the CA images and their rules.

Automate Function

The automate function is also similar to the Elementary automate function, the only adjustments being the different variables: twoDmutatedrules, twoDmutatedimages, twoDinitialrule, twoDcount.

Initialize and Execution

I first randomly initialized the target rule and initial rule. Then I initialized population to 10 because 20 would take hours to run, twoDcount to 0, mutationprobability to 0.4 and then ran automate. I also stored the closest images for each iteration in an array called ans because there were too many iterations to consecutively print the closest rules. I then printed the first two and last two closest rules in ans.

Comments and Future Ideas

Comparing the 1D and 2D Cellular Automaton iteration count

Clearly the total amount of iterations for 2D CA is greater than for 1D CA. This is because the 2D CA is larger than the 1D CA over during their respective time frames. We can prove this by getting the length of the rows and columns of twoDinitialrule over 5 steps and get the length of the rows and columns of rule 30 over 15 steps, and then get the total amount of elements in each CA.
The computer has to go through 1024 elements for the 2D CA whereas for the 1D CA it only has to go through 496 elements, less than half the amount for the 2D CA!

Getting "Stuck"

Often when finding a rule in both the 1D and 2D CA, the algorithim gets "stuck" at a rule, meaning it prints out the same rule several times in a row, not mutating it. This is able to be fixed by increasing the mutation probability, but the iteration count increases as well, thus increasing the overall runtime.

Future Directions

In the future, I would like to optimize the mutate and sort functions for both 1D and 2D CA so that it finds the target rule quicker, and gets "stuck" less often while having a small iteration count. I would also like to apply this to the real world, specifically modeling oil spills. In my WELP project, my group had developed a rudimentary 1D mutate and sort algorithm to represent the progression of an oil spill, and show the uncertainties and behavior changes in an oil spill. I would like to extend that project further using the 2D Cellular Automaton mutate and sort algorithm that I have developed, to more accurately model an oil spill.

Acknowledgements

I would like to give thanks to Nicolò Monti for his inspiration of the mutate and sort algorithm for Cellular Automaton and his continuous support since I embarked on this project. I would also like to give thanks to my WELP group, Lakshmi Agarwal and Sharon Frid, who helped me develop the basic 1D algorithm during our time at WELP.

CITE THIS NOTEBOOK

Creating mutate and sort algorithms for one-dimensional and two-dimensional cellular automatons​
by Mich Obia​
Wolfram Community, STAFF PICKS, March 12, 2024
​https://community.wolfram.com/groups/-/m/t/3139639