Hey all, Jonathan here. Today, I'm going to show an example of how you might go about making your very own elementary cellular automata hereafter referred to as ECA in NetLogo. This exercise in particular asks us to homebrew an asynchronous ECA which you'll see happens quite naturally in this program, since NetLogo, by default, likes to call agents in random order. Alrighty, so, as you saw from this unit, ECAs being one-dimensional are simulated row by row, one row at a time. First time step is simulated on the top row. Second time step plays out in the second row. Third iteration on third row, etc., etc. So it might behoove us to set up the coordinate system in such a way that facilitates this logic. Here, notice I set the origin at the top, so that the first row counts as py coordinate of zero and counts down minus one, minus two, minus three, and so on from there. Due to starting on the top left corner, px coordinate integers also can be (inaudible) count from zero, one, two three, etc. which could also be nice if you later decide to expand the width of the rows. Now for the big questions. You want to ask: What are the essential features of the ECA model? Fayal (???) or automatas are made of cells, of course, which in NetLogo codes, are the patches. The main properties of patches in the ECAs are the current states, of which they have zero or one, and neighborhood configurations, used to determine the cell's subsequent state. Another important feature of the model are the rules, which, as you know, is simply a list of states telling the cells which neighborhoods produce which states. As we have seen from the various Wolfram classes, different rules can produce radically different behaviors on the large scale, while individual cells can have their own states, and see different neighborhoods, the rule set itself isn't specific to the individual cells, but rather the model as a whole. So, I list is as a global variable. We also don't want to forget the obligatory Setup and Go procedures to make the model run and stuff, so I'm putting that in right now. For the Setup, it's generally good practice to write "clear-all", since we want to be able to reset these models and replicate results independently, without interference from previous runs. Particular to the way I set up this model, I'm also resetting such initializing ticks, since ticks can be useful for keeping track of which time step we're at. Finally, we want the patches to sort themselves, to an initial random configuration so I'm going to ask the patches albeit with a specific qualifier, patches with pycor equal zero, to start with, since, as you know, we want cells on the top row in the beginning. Now these patch cells just seem to have those states randomly set. Recall that each cell can be in one of two states: zero or one. So for our current purposes, we want a random decider variable, with an equal chance of returning a state of zero or one to the cells. I'm going to call this one "draw" just because I like the analogy of drawing cards although naming isn't really consequential here. So, let the temporary variable, "draw", be random float one, which is just any random quantity between zero and one that the computer can conceive of. So for this random "draw", we can say if a number picked between zero and one is below 0.5, which as you know, is a fifty percent chance, then set "state" zero, and you want an "else" clause in there too, so if the "draw" number happens to be bigger than .5, which occurs the other fifty percent of the time, then set "state" to 1 instead. Keep in mind that "state" is a variable that's stored inside the patch, that currently is not visible to the human user. So we want to mark up through a new functional procedure called changeColor, which is pretty straight-forward. So, to change color, it might be convenient to use another "ifelse" statement. If the cell state is zero, we get one color. Otherwise, if it is a different state, ergo one, we get a different color to distinguish these cells from each other. Beyond that, it's obviously up to personal taste which colors we want to use. I'm going to say that white cells are zeros, that is, set pcolor to white, if patch's state is zero. Conversely, if the state is one, let's make it look green instead. I personally like using these lighter colors for this, mostly because it helps us separate the rows of cells that are done from the darker ones that aren't done yet. With that, we end the procedure, and check that nothing is broken yet. I'm going to put up some buttons, just to test the model so far, and see if we're on the right track. We have a Setup button to run our setup procedures, and a Go button. The Go button shouldn't do anything just yet, but it will eventually need to be there. Setting up the model now. See, so now we have about half white cells and half green cells in the starter row, reflecting our fifty percent chance of the cells turning white, and fifty percent chance the cell is seeded green in random sequence. Initial conditions are re-set each time using this procedure, which you see, are completely random each time, but roughly speaking, you'll have fifty-fifty greens and whites on average. Go, surprise, does nothing yet, because I didn't put anything out in the Go procedure, yet. Next thing, we want the cells to actually interact with and respond to cells around them, and change according to specific rules, regarding their neighborhood configuration. Right? So far, I haven't defined what the rule sets are. So just to quickly see that in action, I'm going to initialize the model for now, with one of my favorite rule sets. This is one of those rules with the interesting properties of the somewhat orderly yet chaotic behavior characteristic of, you know, complex structures. With this rule set, as a temporary place-holder, let's specify the Go procedure, where the CA rules come into play. Remember, the rules dictate which state the cells change to for each neighborhood configuration, which require each patch cell to detect the state of their two immediate neighbors, as well as their own state. Sticking to the top patches for now, we're going to have each patch update and record its neighborhood configuration. That is, the three state combination that includes the cell's left neighbor, itself, and its right neighbor. Since neighborhood is defined by a combination of cell states, you want to create a list, which is just another vector. In this vector, you want to include as the first entry, the binary state of the left cell. So a little bit of NetLogo vocabulary for you guys. "patch-at" refers to the cell patch in a position relative to the current cell calling it. The first number is the x distance to the left, or right. The second number, y distance, up or down. So patch-at -1 0 refers to the cell to the immediate left of the current cell. Now, add in the state of the current patch calling this procedure which is just "state" by default and finally the state on the right cell, patch-at 1 0 because now we're looking to the right. With that, we have a cogent command block, which I'll just close up for now. Whoops, my bad, So, to recap, each cell is looking to its left, and right, and within itself, for the current set of states updating at each time step. The cells are hence merely storing information each time, not actually doing anything with it, and changing their states in accordance. Hence, the model's apparent behavior hasn't changed yet. As you can see, clicking these buttons, Obviously there are several factors here that are required to make the model run properly. For example, we can't see the manifestation of the cell's new state without a changeColor procedure But more fundamentally, the model is currently missing an application of the rules, when they supposedly direct cell behavior. In fact, the initialist rule vector I picked out isn't really doing anything currently. So we need a way for the cells to refer to those rules in the vector. Now, there's many, many ways to program this part, and as I'm sure the computer scientists among you will quickly realize, the one I'm showing is by no means the most efficient. But some of you will at least hopefully appreciate the syntactic simplicity of my approach here. So far, we have the patches looking at the neighborhood states and keeping track of them at each time step. Now we want them to update their state as a function of these current configurations. So we're going to have to have our patches check these states, and look up the appropriate corresponding response state from the rule vector. For instance, ask the patch if its neighborhood configuration was zero zero zero. This corresponds to a neighborhood of all white cells on the left, center, and right cells here. If the cell in question sees this state, we want this cell to set the state corresponding to item zero from the rule set list. This causes the focal patch to change its state to the first item in the rule vector While we know off-hand that this would currently to set the state to zero we ultimately want the patch to respond to any arbitrary binary rule vector the user specifies. That's the one above I made up. Checking for the next possible configuration, zero zero one, ergo, a white, white, green, we want the cell to change states to the second output state on the list, item 1. Similarly the third configuration corresponds to item 2. Fourth configuration, three, and, you get the idea. In an effort to save some time, I'm just going to copy and paste here, to set up the remaining six possible permutations. Again, this is not the most expedient algorithm. For you code-savvy folk, there's definitely ways, if we use "foreach" loops, that count up and generate any full set of neighborhood configurations under Wolfram's ordering scheme, to align those configurations with the rule vector. We're keeping it simple right now, so at least you have a template to play around with. In the meantime, I'm just checking and filling in the remaining possible configurations in the cell's next state, corresponding with the respective items from the rule set. And looks good. Quick Setup and Go. Now we see some interaction between cells in the first row. Notice how every time I'm doing this, it's updating the patches based on their prior neighborhoods, and even without us doing the drop down CA runs, we're eventually going to get in the next couple of code revisions, one might formulate hypotheses, about the pattern upon casual observation. Is there a specific set of repetitive cycles present? Or the emergence of more complex tortuous meta cycles, characteristic of chaos? Or is it mostly random noise, playing tricks on our brain? However, to see that bigger picture time evolution in one visualization, we actually want to enable the target cells to drop down, so we can see this row get filled, this row, this one, and so forth. Happily for us, NetLogo already has its own native means of keeping track of time steps called "tick". As you should already be familiar with, "tick" is a built-in function that tallies the total number of times its passed through the code keeping count of the current iteration we're at. So this is what our coordinate scheme from the beginning comes in handy. Since both the ticks counter and this p-y coordinate system start at zero, we can literally use the number of ticks to determine which row we want to display the pertinent cell states. Keep in mind, the p-y cor values count down negative one, negative two, negative three. Since downward represents the negative direction on the y axis, so we want p-y cor to be the negative of the current tick count. For future reference, let's refer to cells in these given rows as the current patches. With these current patches, we first want to copy the last row onto the new one, so the cells at the current time step can interact along the new row without losing their previous history. To do this, set state for each of the current patches the same as their former cells directly above, with patchAt 0 1 Now in this new row, we can ask the cells to scan their neighborhoods, and update their states accordingly, just like they were doing before, only now in a separate row. All right! This is awesome. We finally get to see a little bit of temporal evolution in action. In our first official run of the model, you can see the cells moving down a row each time step. And slowing it down a little, you can see they are doing this asynchronously, in random order, as we intended them to while we get fragments of familiar clusters, popping up at various frequencies, the overall distribution pattern of green is too sparse to manifest the same complex behaviors as the synchronous deterministic version of this rule. In fact, a more thorough analysis of these so-called clusters might reveal that they are not actually occurring at much higher frequency than one would expect by mere chance, telling us randomness, not structure, might be the dominating factor for this rule set under the stochastic ECA. But to have a true general ECA, synchronous or not, we obviously need to have the capacity to change the rules, and compare them, within the same interface. Furthermore, we want to compact these long binary based rule vectors into the shorthand base 10 rule numbering system for the user, with designations like Rule 30, Rule 212, or for what we just did Rule 129. So we' like the user to see these colloquial rule numberings, that are readily translated into rule sets this program can directly use. To have a rule set that always updates, based on what the user changes the number to, a reporter can be really useful. So first off we want an Arabic numeral input from the user. So it's probably convenient to put a slider here to adjust the rule number. We know this model has a total of 256 rules. So it's numbered from 0 to 255. To try out another potentially interesting rule that exhibited rich complexity in the original ECA, I'm going to put in Rule 90 here. So let's get rid of the variable in this line, which is redundant with our new rule set slider parameter. And likewise, we don't need the initial rule set and setup any more, thus leading us back to the task of converting base 10 numbers to binary. So, using digit-by-digit counting approach, let remainder start off as the current rule number base ten. So in our case, the 90, and since remainder is actually a reserved name for a mathematical operation in NetLogo, I'm just going to call it remainer Kinda makes sense I hope. So again, let remainer be the user specified rule number. And then, here's a good place to use the foreach function. This is where we methodically go through the binary digits in the rule vector, where each carry equivalent base ten value is from greatest to least. So the first significant digit is two to the seventh power, ergo 128. Next one is 64, 32, 16 etc Again there's probably countless ways to derive and generate this vector without manually putting in everything, but I'm just being pedagogical-ish. Oh yeah, one more thing here. Let there be a temporary variable, RuleList. This is just a stand-in for a rule set variable, which starts out as an empty list, but collects zeros and ones, until it has eight binary digits and reports a complete list as the rule set. For each of these binary digit values, we're going to run a comparison test. So I'm going to say, for remainer, ifelse remainer less than the current binary digit, set this digit to zero. For example, for a rule number of 90, the leading digit is zero since anything with one in the front is going to be 128 or greater which we add to the rule list with LPUT. LPUT appending the value to the latest item on the current list. We get to use Set for these funtions which has to do with the way NetLogo updates lists, since they can't edit existing lists directly. So if rule number is less than current place value, set binary digit to zero, but otherwise, if it is equal to or greater than this place, as in the case of the second significant digit, where 90 is greater than 64, set this digit to one. However, we have to account for the fact that a value of 64 is now included in the current rule vector. So we deduct that from 90, leaving us with a remainder, or in this code, remainer, of 26. This algorithm continues running through each of the following significant digits in the same manner, running a similar comparison test, and recording the appropriate binary digits and subtractions. And finally with the 8 digit list completed, we report the final output, allowing NetLogo to store it in our rule set variable. And this variable is automatically being referenced and updated by the program at every step. So you don't need to set it anywhere else. I'll even create a monitor of the actual rule set so you can see what the rule vector NetLogo is actually using, and how instantaneous this conversion process is. Running Rule 90 in the asynchronous ECA we some semblance of emergent macro structure. I'll leave it to you to explore the rest of what the asynchronous ECA has to offer: what differences it has, what properties does it preserve from the ordered synchronous ECA. Of course, there a bunch of other features you can add to this model at the drop of a hat. For example, we started with a default number of patches along each row, which is 33 here, but we can decrease or increase this number by teaming up the max px cor with another slider for instance, to change perspective, maybe get a broader birds eye view of the patterns. Along those same lines, you could also change the maximum py cor, and/or even make the pixels smaller. It may be convenient to have a Go button that runs automatically and views evolution at different speeds. We might not necessarily even want to have 50-50 starting conditions for the patches, so you can adjust the probability in the code, or slider, or ???est level of max, or highest ECA model, have an edit mode that lets you choose the patches individually. All right folks Hope this demo was illuminating and helpful i hope you have fun with everything. See you later.