Introduction

Main idea

What happens if every person in society becomes like commonest in environment?​
We must consider that person is also part of the surroundings of others,
so it’s a dynamic process, a type of cellular automaton.
​
Consider the simplest model. The socium consists of cells of N types-"colors".
The universe is closed like a torus, and the environment of each cell
is considered to be a Moore neighborhood (3х3 block).
The candidats are Commonest of neighborhood;
if there are several, one is chosen at random and the central cell takes it's color.

​ We can implement this algorithm with CellularAutomaton:
numStates=5;numIters=300;size=40;​​init=RandomInteger[{1,numStates},{size,size}];​​​​result=CellularAutomaton[{​​{{n1_,n2_,n3_},{n4_,_,n5_},{n6_,n7_,n8_}}:>​​RandomChoice@Commonest@{n1,n2,n3,n4,n5,n6,n7,n8,_}​​},init,numIters];
In[]:=
Animate[​​ArrayPlot[result〚k〛,ColorFunction->"DarkRainbow",ImageSize->150],​​{k,1,numIters,1},AnimationRunningFalse,SaveDefinitions->True]
We can see that in some cases society self-organizes into groups and stabilizes:​

​Whereas in other cases one type-color sooner or later conquers the whole world:​



​​It depends on the parameters of simulation, but also on randomness.

Advanced algorithm

There are many ways to generate a new type for a cell using the neighbors array.
From the simplest, like above, to the most complex, recursive.
I found that a very interesting and diverse behavior is demonstrated by a relatively simple algorithm.
​
Besides the basic data of our "country" (size and number of types),
uses two threshold parameters limits.​
We select those neighbors whose relative frequencies are within these thresholds.
If there are any, the cell becomes one of these types, randomly chosen.
If there are none, the cell remains itself.
​
This strategy is considered to be a balanced one - avoiding being either too typical or too unusual.​
We also add the possibility to choose the size of the neighbors block.

Code

Parametric multi-state cellular automaton is difficult to implement with corresponding built-in.
But ArrayFilter provides the necessary features.
​
Two methods are proposed:
- Dynamic: real-time parameter management, no data storage.
It is convenient for general review and search of interesting combinations of parameters.
​
- Cumulative: for statistical analysis of the data obtained.

Utilites

Color palettes as evenly divided hue circle:
In[]:=
Clear[myPaletteSingle,myPalettePoly];​​myPaletteSingle[m_]:=Table[Lighter[Blue,σ],{σ,0,1,1/(m-1)}];​​myPalettePoly[m_]:=Table[Hue[1. k/ m,RandomReal[{0.4,0.7}],RandomReal[{0.7,1}]],{k,m}];
Core function.
​neighbs is an array of neighbors in matrix form,
​r is volume of neighbors (2r+1)·(2r+1) block,
​testQ is test function for select neighbors by their multiplicities.
If there are no neighbors that satisfies testQ, central element (cell as itself) is returned.
In[]:=
Clear[newCellLims];​​newCellLims[neighbs_,testQ_,r_]:=​​ With[{sel=Select[Tally@Flatten@neighbs,testQ@Last@#&]},​​ If[sel=={},neighbs〚r+1,r+1〛, RandomChoice@sel〚All,1〛]​​ ];

Dynamic

For improved performance some functions placed inside the module.
In[]:=
DynamicModule{board,colorRules,plot,testQ,newCell,​​controlOpts=Sequence[Appearance->"Labeled",ContinuousAction->False],​​animRate=4,imgSize=200},​​SeedRandom[];​​Manipulate​​board=RandomInteger[{1,numStates},{size,size}];​​​​colorRules=MapThread[#1->#2&,{Range@numStates,​​If[palette==1,myPaletteSingle,myPalettePoly]@numStates}];​​​​plot=ArrayPlot[#,ColorRules->colorRules,ImageSize->imgSize]&;​​​​testQ=IntervalMemberQ
2
(2sizeNeighbs+1)
Interval@limits;​​​​newCell[neighbs_]:=With[{self=neighbs〚sizeNeighbs+1,sizeNeighbs+1〛,​​arr=Select[Tally@Flatten@neighbs,testQ@Last@#&]},​​If[arr=={},self,​​RandomChoice@arr〚All,1〛]​​];​​​​Dynamic@plot@board,​​​​{{limits,{0.2,0.6},"Limits "},0,1,0.01,ControlTypeIntervalSlider,​​Method"Push",controlOpts},​​{{size,20,"Size "},10,100,10,controlOpts},​​{{numStates,3,"Num states "},1,10,1,controlOpts},​​{{sizeNeighbs,1,"Neighb size "},1,6,1,controlOpts},​​​​Item["\n"],​​{{steps,1,"Play"},1,Infinity,1,​​​​TrackingFunction(steps=#;​​(*Ifstable!!!*)​​board=ArrayFilter[newCell@#&,board,sizeNeighbs,Padding->"Periodic"];&),​​​​Appearance->Large,ControlTypeTrigger,AnimationRateanimRate​​},​​Item["\n"],​​Button["Reset",​​board=RandomInteger[{1,numStates},{size,size}]],​​Item["\n"],​​{{palette,1,"Palette "},{1->"Mono",2->"Poly"},ControlTypePopupMenu},​​TrackedSymbols{steps,limits,size,numStates,sizeNeighbs,palette},​​SaveDefinitions->True,DeployedTrue​​
Out[]=
​
Limits
{0.19,1.}
Size
40
Num states
6
Neighb size
2
Play
Reset
Palette
Poly

Collect data

All parameters are set manually.
Sowing of the simplest data (the size of each type’s population) is added to main loop.
One can add any custom Sow.
In[]:=
numStates=5;size=40;sizeNeighbs=2;​​colors=myPalettePoly@numStates;​​init=RandomInteger[{1,numStates},{size,size}];​​limits={0.19,1.0};numIters=300;​​testQ=IntervalMemberQ
2
(2*sizeNeighbs+1)
Interval@limits;​​​​result=Reap[Nest[(f=Flatten@#;Sow[Table[Count[f,k],{k,numStates}]];​​ArrayFilter[newCellLims[#,testQ,sizeNeighbs]&,#,​​sizeNeighbs,Padding->"Periodic"])&,​​init,numIters]][[2,1]];
In[]:=
ListLinePlot[Transpose@result,PlotStyle->colors]​​

Some interesting results

Example 1

Example 2

Example 3

CITE THIS NOTEBOOK

Simple model of society as cellular automaton​
by Denis Ivanov​
Wolfram Community, STAFF PICKS, July 29, 2024
​https://community.wolfram.com/groups/-/m/t/3236624