Here we are at the last article in this series. In the previous article we looked at modeling what could vaguely be called nouns and adjectives. In this part we will go into much more detail about modeling complex states and we will also model changes over time and discuss models that constrain such changes. In the process we will also go into more detail about how such models can be composed to describe complex situations.
The example for this paper is a rubix cube. But the topic is not about a rubix cube. Rather, it is about the general principles of how to use Proteus to model anything. In the process of modeling a rubix cube we will look at many different generalizable aspects of a rubix cube including it’s state at an instant, and events that can change its state over time. We will also delve into modeling it’s state at various levels. For example, on an abstract level, turning a face of a cube is digital - you turn it clockwise or counterclockwise. But on a more physical level you can actually rotate it smoothly through a near continuum of positions. And while an abstract cube may not have a ‘disassembled’ state, a physical one does. Each new level adds new states and transforms. We will briefly look at how we could represent how a material level adds transforms like burning or melting or being smashed or crushed.
Our description of a cube should eventually include that it is a puzzle or toy, what the solved state is and perhaps some tricks and moves that can be used to solve it. Near the end we will briefly look at how a slightly more advanced engine could figure out how to solve it without being given hints by, for example, searching for its commutators.
In this chapter we will develop a very basic level-1 state model of a rubix cube. It will be a bit simplistic in order to not distract from the concepts. In the next chapter we will make some improvements to it. Nevertheless, the model of this chapter will be enough for the Slipstream engine to display the cube in 3D.
Let's talk about some different ways we could package up the state of a rubix cube. None of them are wrong. And in fact, we could do all of them and connect the various perspectives. The choice depends on what initial use you have for the model. I say “initial use” because as new uses come up, the original models need not be discarded. So a final model may have many different perspectives to fit almost any purpose.
One perspective is that a rubix cube has 54 color squares that can each be one of 6 colors. Another: a rubix cube has 6 faces, each with 9 such colored squares. These views may be fine for a digital rubix cube that is only used in the abstract or displayed on a screen.
Another view is that a rubix cube consists of 26 physical cubelets with colors on each side. We can be more detailed and say there are 6 center cubes, 8 corner cubes and 12 edge cubes. The relative location and orientation of these cubelets stores the state of the whole rubix cube. In a more physical model we will also want to include the central mechanism that holds it all together.
Let us use the model with center, corner and edge cubes. Remember, we are going to use models defined in previous sections. Especially the object/thing and color models.
As with the rubix cube itself, there are choices in how we describe the individual cubelets. After all, they are not actually cubes but cubes with an appendage to connect them to the central mechanism. The current Slipstream engine has a hard-coded ability to draw a cube and several other shapes. Purpose drives the choice of how to model a system and since part of the purpose here is to be able to view the results of changes to the cube, let us make them cubes with 6 sides, each with a single color.
concepts = {
@side = {color}
@edge-cube = {
thing,
*6+{side| ... }
}
@corner-cube = {
thing,
*6+{side| ... }
}
@center-cube = {
thing,
*6+{side| ... }
}
}Looking at these definitions it is clear that this temporary definition of a side as a list of one color will have to be updated eventually. But it serves the purpose for this series. Remember, the engine can draw cubes if it can find a color of the sides.
Next we define the three types of cubelet: edge cubelets, center and corner cubelets. Notice they are all three a thing with 6 sides. A more complex definition would use a geometric description of cubes. But we are keeping it really simple here and shortly we will need to specify the colors of the cubelets anyhow so for here it would just add more text.
Here is a tedious way we could set the colors. Let’s just look at an edge cube.
edge-cube:{
{red}
{blue}
{gray}
{gray}
{gray}
{gray}
}That is a bit verbose. Before using it let’s tidy it up by parameterizing the colors of the sides. Let us assert that edge cubes have a front color and a top color. Then we can reference those in describing the cubelet:
@edge-cube = {
thing,
front-color,
top-color,
base-color,
*6+{ side|
{%.front-color}
{%.top-color}
{%.base-color}
{%.base-color}
{%.base-color}
{%.base-color}
}
}
We could similarly map the base color to the parent color.
Now we can declare an edge-cube like this:
edge-cube:{
front-color:red,
top-color: blue,
base-color: gray,
}After doing the same for center cubes and corner cubes, we can define a rubix cube. I will leave out repeated detail so that this is readable on a phone. Also notice that we make this a T list to denote that it changes over time — at the bottom you can see it ends with “| …” signifying that the previous state description is a ListSpec (like a template) that applies to the cube at every state change.
@Rubix-cube = {T
*8+{edge-cube|
edge-cube:{
Front-color:red,
Top-color: blue,
Base-color: gray,
}
edge-cube: ....
// repeat 6 more times
}
*6+{center-cube|
center-cube:{ .... }
center-cube:{ .... }
center-cube:{ .... }
center-cube:{ .... }
center-cube:{ .... }
center-cube:{ .... }
}
*12+{ corner-cube |
// you get the idea
}
| ...
}The “…” at the end signifies that we don't know any of the actual states of the cube over time. So now let us discuss how to describe some important states. Two important states or range of states are the solved state and the assembled states.
The simplest, yet least interesting way to specify the solved state is to enumerate each cubelet's location and orientation relative to the parent rubix cube.
Note that these definitions should be in the same scope as the rubix cube definition so that they don't apply elsewhere.
Also, notice something important here. This rubix cube does not have a “T” after the opening curly brace signifying that it is not a T list. Therefore, this represents a single, const state when instantiated. It can be used to describe the state of a cube at an instant. The important part to notice here is that we are setting the location and orientation (position) of each cubelet to where it would be in the solved state.
@solved-state = rubix cube:{
// Set the position of all cubelets
*12+{edge-cube|
thing:{
orientation:{x:3.14,y:0,z:0},
location:{ax:0, ay:-1.1, az:0}}
}
// And so on for each cubelet
}Though this way of specifying the states of the cube is tedious, it is foundational in the sense that ultimately, the state is about the positions of the cubelets. Improvements are merely definitions that let the engine calculate the positions based on assertions about the colors of the faces. And for this example, that is how we want it. By specifying the low-level state in terms of positions we can also define disassembled states as well as smooth transitions from state to state as we rotate a face through the intermediate positions. Of course a better high level definition will map color squares on each side to cubelet positions then assert that all the colors on a side are the same. We will get closer to that later.
Here is how to represent a cube that starts out in the solved-state but may evolve after that:
rubix-cube:{T solved-state …}Viewing the cube
Let us use the Slipstream Browser to view a cube like that.
If we
open the Slipstream browser and make sure the definition of a rubix cube is loaded, then
add a cube to the “my stuff” infon,
and lastly display “my stuff” in the windows, we get the following screenshot. You can also see a Proteus modeled kanban demo and a Proteus CLI.
The < and > controls let you step through time. In this case there is only one state given.
It would be nice to be able to distinguish between when a rubix cube is assembled or disassembled. Unfortunately, this would take some definitions we have not written yet and that go beyond the scope of this series. But we can talk about it.
The cube is assembled when all the parts are attached to the whole in the way that makes the cube work. You might ask why not describe how the cublets attach to the whole and then assert, in Proteus, that “assembled” means all the parts are attached. The problem for now is that the description of things or objects that we have defined in our little standard library does not assert that two objects cannot occupy the same space. So, not only can cublets share the same corner or edge but they will also not hold each other in place. So, for now, we cannot assert that holding together in a stable configuration is part of being assembled.
Another way we might define “assembled” (other than listing all the possibilities) is to say that the cube has “slots” or “connection points” and it is assembled when all the slots are full. This becomes more complex when we try to model the intermediate states when a face has been rotated only partially.
All will be easier when the thing model contains more information about how materials work.
Ultimately, we need to define “assembled” more generically. This can be done by describing how a part, of any system, is “supposed” to be attached. When “supposed” is defined and applied we can merely assert that assembled means all the parts are where they are supposed to be.
It may be hard to visualize at this stage, but this illustrates one of the cool ways that the information view lets you model reality. Namely that is does not usually need linguistic categories like noun or adjective. Once we have defined assembled and disassembled we will be able to use them as adjectives or verbs: “The cube is disassembled.” Or “The assembled cube is solved.” But also, “I assembled the cube”. In fact, with the requisite definitions, it will be able to infer the meaning of “was the assembly process quick?” without having to model “assembled” for every kind of thing.
In this chapter we describe the cube in terms of the six cube faces. Then we use those descriptions to describe how turning a face changes the cube's state: our first verb-like descriptions.
If we want to define a list of changes to a cube's state that conform to turning a face clockwise or counterclockwise we need to describe the 6 faces.
Add the following into the rubix cube model; and add definitions into the same scope as the model. Note that these additions do not add totally new states since the added states are mapped to the old states. So we are adding new ways to refer to the old states.
The following definition of a rubix cube face is similar to the definition of a whole cube. But with a face color, only one center cube, 4 edges and 4 corners. We label the attached cubelets according to the compass points.
// Add into same scope as rubix cube:
@face = {T
face-color,
center-cube:
{Top-color=%.face-color},
*4+{ edge-cube | n, e, w, s},
*4+{ corner-cube | ne, se, nw, ne}
}
// Add to rubix cube model:
*6+{ face |
{%.face-color: red},
{%.face-color: blue},
{%.face-color: purple},
{%.face-color: green},
{%.face-color: yellow},
{%.face-color: orange}
}Above we have described the parts of a face and asserted that rubix cubes have 6 faces of varying center color.
Next we need to assert that some of the parts on one face are also a part of other faces. For example, the cubelet currently on the n edge of the red face is actually the same cubelet as the e edge of the white face. To do this, recall how we can refer to a specific part:
// A reference starting from inside the rubix cube definition:
%.face:{face-color:red}.corners.ne
// A reference from outside the definition:
%ctx.rubix-cube.face:{face-color:red}.corners.neAnd remember, that as the library grows we will be able to reference things with natural languages like this:
The red face’s north-east corner cubeletSo our next task is to assert all the cases where the 6 faces have a cubelets in common. There are 8 “3-way” identities where three faces share a corner, and 12 “2-way” identities for the shared edges.
In this case, there are only 20 identities to assert so it is easy to just list them — which is what we end up doing here. However, the underlying purpose of this part is not to describe how to model a rubix cube but to look at how to model things in general. So in the next few sub-sections I want to discuss some aspects of asserting collections of identities in general.
Don't use indexing when it is artificial
If you, like me, are from a programming background, it would be natural to think about using ordered lists for the cubelets and faces and then using an index to assert patterns of identity. But in Proteus that is not the best way to do it. That is because the cubelets and faces do not have an inherent ordering. So every time you want to apply the definition to a real cube you would have to specify the ordering of the cublets and faces for that type of cube. Instead, think about how you would explain the identities in English. We would refer to each cubelet by its colors or type and to each face by its color or relative position. So below we will refer to the faces by their colors and to the cubes at each location in a face by their relative compass point position.
Here we define both a 3- way and a 2-way identity:
// ─── Corners (3-way identities)
// (red ↔ white ↔ green)
%.face:{face-color:red}.corners.ne =
%.face:{face-color:white}.corners.se =
%.face:{face-color:green}.corners.nw
....
// ─── Edges (2-way identities)
// red ↔ white
%.face:{face-color:red}.edges.n =
%.face:{face-color:white}.edges.e
....But when the library grows there will be better ways to do this. For example, with a more geometric definition of a cube and with a definition of thing that doesn't allow two things to occupy the same space, the identities could merely be inferred rather than explicitly stated. Also, with more words modeled we could construct natural language statements that expand out into the 20 assertions.
Next we want to define turning a face clockwise, leaving counterclockwise as an exercise. As we have seen, a high level description could be made that uses definitions of “turn” and “clockwise”. However, here we will use a low-level description. The low level description will be important even with the higher level descriptions but with higher level descriptions they would be inferred rather than explicit.
Now that we are ready to model state changes over time, I need to mention a rule for the notation. In a T-list, the Right-Hand-Side (RHS) of an identity assertion refers to the previous value of what it refers to. That makes these identity assertions act like declarative assignment statements.
Here is a description of turning a face clockwise. Notice that this definition has an argument, which is the face to turn.
@turn-clockwise face = {
face.corners.nw = face.corners.sw,
face.corners.ne = face.corners.nw,
face.corners.se = face.corners.ne,
face.corners.sw = face.corners.se,
face.edges.n = face.edges.w,
face.edges.e = face.edges.n,
face.edges.s = face.edges.e,
face.edges.w = face.edges.s
}Notice that we used an unordered list. This means that these state changes logically happen at the same time. So even though the n cubelet was asserted to become the new w cubelet, the next line of code moves the n cubelet to the e slot. This is not the “new” n — which was w. That might sound confusing, but essentially, the rotation works as expected.
Now we can apply that definition like this:
Rubix-cube:{T
solved-state
%.faces.red = turn-clockwise
...
}Let's review that. We have a rubix cube in T mode, so it is a list of states it goes through. It starts in the start state. For the next state we refer to the faces list and rather than explicitly specifying that we want the face:
{face-color: red}we rely on the engine to search for the most obviously red one with just “.red”. If there is a chance for ambiguity we should use a more specific reference.
Next, we need to make sure that references inside the RHS can be found, though it may need to analyze the LHS to do so. In this case, it is the red face that is changing.
Specifying multi-part state changes
Notice how the above state changes just changed one face. But it is possible to rotate multiple faces at once. We can do that be giving an unordered list and using the & operator:
&{
%.faces.red = turn-clockwise,
%.faces.blue = turn-clockwise
}Since we used an unordered list, the state changes are assumed to independent. So it works to move opposite faces at the same time. However if we moved two connected faces at the same time there would be some cubelets with two contradictory locations and thus it would be an error.
Instead of an unordered list we can include an ordered lists of actions which, of course, means they happen sequentially. This applies to lists with a listSpec as well. Thus, if we put changes in a listSpec it means that they occur for each item in the list. So here is how we can specify that we turn the red face 4 times:
& *4+{T faces.red = turn-clockwise |
...
}This is a Time list with 4 events in it. All of them are turning the red face clockwise.
Notice how the rule that, in a T list, the RHS has a slightly more complex way to dereference, namely it refers to the previous state, changes the semantics in a way that matches up to how programming languages use sequences, loops and conditionals.
There are a few new features though. For example we can use “…” to specify sequences when we do not know the states. For example we could specify a rubix cube that starts in the solved-state then possibly undergoes some unknown state changes, then the red face is changed using “…” between the state changes.
However, so far we have only specified the contents of a T list from inside it. Let us look at how we can inject events into a T list by referring to it from the outside.
Suppose we have declared that a person named Alma exists. Assuming all the relevant models are written, that might look like this:
Human:{T name: “Alma” | … }Of course we can go into this definition with a text editor and add all kinds of details about Alma's life. The … covers from her birth to her death. We haven't talked about measuring time or space yet, but by using a metric we can specify that during different years different events happened to her. A sub-T-list might assert that during that time she was in college. Another, perhaps overlapping, sub-T-list might be when she is married to someone. And when she had a child.
But we are editing her infon from a detached position. This is fine if we are, for example, an historian describing the life and times of Aristotle. Because we are detached from that time and person. But what if we want to be more interactive? What if we want to say “Alma is walking to the store”? Or “I'm going to walk to the store when she gets back”?
We need three features. The first feature we already have defined in previous chapters. Namely, the ability to refer to or inject parts of a list from outside that list. The second we technically defined but an example wasn't given: the ability to refer to a sub-list. In a T-list this is used to refer to an interval in time. Lastly, and this has not been described yet since we have barely discussed how a Proteus engine works, we need a “now” cursor in an infon that points to the current time in an infon. Or at least, the engine should be able to find “now”.
Walking
Without making a huge definition, think about how we might define walking for humans. More specifically, walking “to” somewhere. Think about walking to the store. The definition would be a T list of something that could walk. The ListSpec would likely consist of two simultaneous loops, one would be take a step (which could, simplistically, be step left followed by step right) and the other process would be something like adjust balance and direction. Each step would alter the walker’s location in space with the final location being within a range of values that matched “at the store”.
Choosing a time interval
We have the whole parsing tool kit with which to select a time interval. It could start “now” or it could be in the range before or after now. Or we could search for an event. We could search for an event before or after now. We could estimate how long the interval is or we could select an interval between two events. We could use named intervals like “the 80's” or “yesterday”. Events could be after now like “when Bob gets back from the park”.
How ever we select an interval of Alma's life infon, we inject into that interval the event “walk to the store”.
In English, and many languages, we often select a time-interval by changing the form of the verb being injected. A Proteus language module could use forms of a word to combine selecting an interval with using a time word. As of this writing, our reference implementation of the English-to-Proteus language module does some such conversions but it does not yet convert phrases like “walked” or “will have walked” or “is walking” into the appropriate model from the model of “walk”. We could define it without the language model. For example, an infon could take a verb model and a word like “past tense” and produce the corresponding model that selects the “before now” time interval, with ‘ walk’ injected into it. However, by hard-coding an English-to-Proteus language model we can speed processing up significantly.
If the first layer of a model is the essential description of information structure with no details on how it works, then layer 2 might be the physical layer. But to be clear, the use of the word “layer” is pragmatic not precise. Our layer 1 description of the rubix cube included some physical aspects, after all. A “pure” layer 1 model might just consist of 6 faces of 9 colored squares and no reference to cubelets. So while the concept of layers is interesting, getting dogmatic about what entails a “layer n” model will just be annoying. Nevertheless, the concept of layers is important. And each layer provides opportunities for new verbs and nouns. So let us look at how to model that turning a face isn't a discrete action but that there are intermediate states as we rotate it through a quarter turn.
The first step is already done. Namely, we already defined the positions of faces as continuous over 360 degrees via the “thing” model. So what we really need to do is specify that the “normal” states are those where the faces are at multiples of 90 degree rotation. And turning a face means rotating it through 90 degrees. Similarly, even though the cubelets can be in a continuum of positions, there are only 2 normal positions for edge-cubes and 3 for corner-cubes.
Carefully defining each part’s position
Defining the continuous updating of the cube's state requires that we be careful about where we define each part’s position, that is, its location and orientation. In our first model we defined the parts of each cubelet relative to the whole cube. Now, however, we want to talk about updating their positions based on rotating a face. We can solve this by describing the hierarchy: the rubix cube model is where we will define the positions of its 6 faces and each face will describe the positions of each of its cubelets. This does mean that cubelets will have their positions described relative to multiple faces. However since Proteus is declarative, and since past states are not necessarily valid in the middle of a transition, this will not cause a contradiction. Yes, turning two intersecting faces at the same time would cause a contradiction, but that is how the engine knows it isn't possible without breaking it.
Let's look at the outline of our an updated rubix cube description. You can see the full text file at rubixCube.pr
The rubix cube definition asserts that it is a thing, then we list the 6 center cubes, the 12 edge cubes and the 8 corner cubes (see the previous examples). Next we describe the 6 faces and the identities telling how the faces intersect. Lastly we have the description of rotating a face in terms of how doing so changes the positions of its cubelets. We also need to define the solved-state in order to ensure that the cubelets in the faces are the same cubelets listed for the cube as a whole.
Here is the parts we haven't seen before. Here we describe the 6 faces (only the red one is shown here). Notice two things. First, the face's location coordinates are left unknown. They will be given in the rubix cube description. And second, their orientation’s z coordinate is asserted to be one of 4 possibilities. Each possibility corresponds to a 90 degree angle. This is telling it that the valid states require the faces to be rotated into one of those positions. Doing it this way allows that there are or can be intermediate states but they are not included in the list of rubix cube T states.
// New part of rubix cube description
*6+faces:{
red-face:{
thing:{
location:{x:0, y:0, z: 1},
orientation:{
x:0,
y:0,
z = *_+[0,90,180,270]
}
}, face-color:red
},
// Repeat for the other 5 faces
....
}Now let us look at the new description of a face. Here we give more information about the cubes in each slot. Again, we only include the north edge cube for brevity but you can see the whole thing using the link above.
The important part here is similar to the important part in the new description of the whole cube we just looked at. Namely, we give the specific location of this cubelet relative to the face. But for the orientation we give two options corresponding to both positions the edge cubelet can be in.
// Description of a face
@face = {
thing,
face-color,
center-cube:{face-color: %.face-color},
edge-cubes:{
n :{ thing:{
location:{x:0, y: 1, z:0},
orientation:*_+[{x:0,y:0,z:0} {x:90, y:0, z:180}]},
sides:{face-color, _}
},
e :{ .... },
s :{ .... },
w :{ .... }
},
corner-cubes:{
// Do the same for ne, nw, se, sw
....
}
}With that we have a definition where the faces and cubelets can move continuously but we have also specified the positions that count as valid states of the cube.
There are several different ways we can represent how an actual transition occurred. It might be tempting to represent a continuum of linear state changes for a face where the end state is the new normal one. But actually, we do not always rotate a face linearly. We “could” rotate it a half-way, pause, then go back a bit before finishing.
So we want to represent such evolution by having a T list with a start state (given by the previous state), followed by a list of intermediate states. These states can be pseudo-continuous. Then ending the T list with the desired final state. The intermediate state list can be left empty: “…”. Or it can have detail added as needed. By using listSpecs in the intermediate list we can say things like the change is smooth or it accelerates or pauses.
In the examples so far, we have just asserted that, for example, the cube is in the solved state. But, what if we need to assert that it was in that state for 1 second? Assuming we have defined units, such as a second, we could have a sub-T-infon like this:
& *(1*second) +{T solved-state | …}Presumably, second represents the number of Plank time units in a second. Its a huge number but that doesn't have to matter since the logic is done by substitution of identicals toward a normal form. We will rarely care about how many Plank units there are.
Before looking at how to model continuous movement, consider this example where the red face is rotated 90 degrees in six, 18 degree increments.
// ——— Example: state changes ending in a normal state ———
// A reusable verb that rotates *any* face through a six-step turn:
@rotate-face-in-steps face = {T
// Six intermediate states: add 18° each step (0→18→36→…→90)
*6+{T
face.thing.orientation.z = face.thing.orientation.z + 18
| … }
// Final “snap” into the exact 90° normal state
face.thing.orientation.z = 90
}
// Apply it to the red face of a cube that starts solved:
rubix-cube:{T
solved-state
// this injects the six-step animation and final alignment
%.faces.red = rotate-face-in-steps
| …
}Now to make this pseudo-continuous for 1 second we assert a second's worth of rotation through 90 degrees with the final state being exactly 90 degrees like this:
*(second) +{T
face.thing.orientation.z =
face.thing.orientation.z +
(90 / second)
face.thing.orientation.z = 90
}There are a number of ways to represent such changes more generally. For example, we can refer to a parent's length or a state's position in a sequence.
However, consider that for a real situation we do not know in advance if a turn of a face will proceed linearly. A turn could stop or turn around. Thus the best model for the definition of a face turn simply does not specify the intermediate states:
{T
// There are many states changes
& *_+{T
face.thing.orientation.z += _
| ...
}
// The final state is +90 degrees
face.thing.orientation.z = 90
}Ultimately, much of the boilerplate, such as ensuring that a continuous movement goes through states without skipping any, can be added to the thing model and a model for the verb “turn”. In particular, allowed verbs controlling updates to the position should require that if going from position A to position B, all the intermediate states must be used.
The result is that, we can query a model at its various levels. At the face level we get a continuum of states. But at the rubix cube level we get its states in full quarter turns. At this level the states could, for example, be mapped to one or more rubix cube notations like “{M-R4, T-R3} R2 U S'(I2) U2' S(I1) U R2”. How? First use the techniques described much earlier for defining a syntax. Next, map the syntax to a sequence of face rotations. Then you can inject those rotations into a model of a cube. Or, do it backwards: given a Proteus model of a sequence, query for it to be in the notation you want. With both a rubix cube model and a notation model, the engine only needs substitution-of-identicals to parse or write the notation to thus learn the state of a cube or to communicate a particular sequence. Essentially, the new notation has become part of Proteus.
As the model library grows there will be a better “thing” model that captures the fact that matter cannot overlap in space with other matter. Also we will have more geometric concepts defined. With those two features, many aspects of the model could be inferred rather than given explicitly as we have done here. For example, the identity statements telling which cubelets in one face are the same as a cubelet in another face can be inferred. After all, if we know that two faces intersect in space and that objects cannot share the same space, then we can infer that the two face's references to a cubelet in a shared spot point to the same cubelet.
We defined a semi-logical level for a rubix cube and added verbs for rotating faces. Because it is only semi-logical — we defined physical cubelets — we also have verbs for assembling and disassembling a rubix cube. With a little more work we could express the geometry and materials of the cubelets and of the central core that holds it all together. We could describe some plastic 3d shapes, vinyl stickers, metal screws and springs, etc. Each of these would have corresponding verbs. So now we could talk about taking the stickers off and reapplying them as a cheat to solve the puzzle.
To go a level deeper we could describe the structure of the materials we use. For example, we could describe various metals as different atomic lattices. This would let us calculate verbs like smashing and melting the rubix cube.
On hearing that, it can seem like declaring a lattice of many trillions of atoms would be unweildy. But not as much as you might think. First, just because we declare an infon with many trillions of atoms or molecules does not mean the engine has to process all of them. Remember, we do not need to simulate atoms. We only need to know how information is contained in and flows through the lattice. It may be able to infer the properties of a material from a representation of a lattice. That isn't my field so I don't know. But I do know that if it is possible Proteus can represent it and process it.
I have seen hints of a physics theory that represents fundamental particles and their interactions in terms of how information is exchanged between the particles. For example, what information goes into an electron when a nearby charge is accelerated? Other than seeing a reference to this in a video I have not been able to learn more about this technique. But it would a good way to model particles in Proteus.
In addition to these descriptions of how an artifact can change and how it works and what it is made of, it can be useful to go up another level to describe how the artifact interacts with other objects. For example, a bike sprocket and a bike chain may have their own descriptions but there can be a “level 0” description of how they work together.
Many level 0 models will be about how a human uses something and why. For example, how does a bike / rider system work to update the rider’s location? Why would a person want to ride a bike?
For the rubix cube we might make models of a toy or puzzle that persons can use for entertaining learning.
Here is how we might do that in terms of state:
We can assume part of the state of a person is a store of knowledge. And for humans it isn't controversial to say that we have a state “having fun”. It will be great to someday get models of the lower layers of that state!
We could nievely specify that an increase in the knowledge store is “learning”. Then we can define a human activity of “having fun and learning”. An object that facilitates having fun and learning can be defined as a toy or a puzzle.
Now we can model the context or layer 0 of a rubix cube as being a toy or puzzle.
It may seem that definitions involving people, or more specifically humans, might be too hard to make. Not so. In fact, this is another case where the information structure paradigm really shines. Humans have states called “intensional states” these are states that have a meaningful piece of information attached to them. Common example of intensional states are beliefs and desires. The classic example is 1. Bob desires to drink a coke. 2. Bob believes there is a coke in the nearby fridge. Therefore, Bob gets up, goes to the fridge and gets the coke to drink.
Notice that the action drinking a coke or the state of a coke being located in a refrigerator are easy to represent in Proteus.
Assuming we have the requisite models we can thus make infons like:
Bob’s beliefs: {
The time is after 5:00,
Alma will be home soon,
There is a coke in the fridge
...
}
Bob’s desires: {
Someone is in a "loves Bob" state
To see Alma soon
To drink a coke
...
}
Bob's dreams:{
Live with Alma in the cute house she likes,
..
}Then we could possibly model the complex interplay that produces actions from beliefs and desires. (Of course a realistic model would need much more detail; for example, the amygdala has states that affect behavior, and so on.)
In another article, not in this series, I can provide more concrete examples of modeling intensional states and show how the engine can work with them.
With the ability to work with models at one level and compare how they correspond to the same model at a different level, we can calculate whether one way of making a system is better than another for a specific purpose. For example, we could model a rubix cube made of plastic and see how it works as a puzzle. Then we could model one made of thick wet clay. Or model one where the shapes don't fit well and come apart easily. Each could be analyzed for how it provides learning and entertainment. Or whatever purpose we define.
The main way that the Proteus engine uses models to deduce knowledge or to answer queries or to plan actions is through a process of substituting a piece of information for an identical one. If the engine is given instructions for solving the rubix cube, for example, a sequence of conditional substitution steps and loops terminating in turning faces, it could do it. It could also be given different patterns of actions for solving parts of it. For example, a sequence for moving a cubelet from the bottom face into the right position on the top face. With enough such patterns a good Proteus engine could piece together how to solve the cube. But instead of giving such steps to it explicitly, we could model experimenting by doing a few moves, turning a face, then reversing the first sequence of moves and observing what, if anything, changed. As long as the engine can cache the “commutators” it finds, it could then learn to solve the cube, and many other puzzles, from scratch.
It has been mentioned several times that, ultimately we need models for doing geometry. As of this writing they are not written. But there are several ways it could be done. In the end, all the methods should be done; we need not pick one. An obvious method would be to translate the equations and definitions defining algebraic geometry into Proteus identity statements. Alternatively, a fun and historical way to add geometry would be to define a pencil, a compass and straight edge and use assertions about how they can change the state of a writing surface by drawing lines and circles.
These methods would not only work, but by embedding the concepts in history at the time they were discovered, and by whom, they could be used to record the history of geometry.
But the reason I have not done this yet, is that I am hoping, admittedly against all odds, that there is a more information-centric way to do it. If you read part 2 of this series you know that Proteus is based on a mathematical structure of information called an infon. The structure of infons isn't specified in terms of axioms and theorems but by asking questions about a constant sized infon and determining the answer by querying whether the various possible answers to the question would result in the system under question gaining or losing states.
Infons store state, but because different ways of connecting to them cannot add new information, they end up having, not only a numerically ordered state, but also a sort of “phase”. It is my wild speculation, and current area of research, that this phase acts like an imaginary part and that large infons, therefore, are like complex numbers. If so, we should be able to map the location and orientation of the “thing” model to an almost naturally occurring quaternion, octonion, or higher level infon. Indeed, because parts of such infons cannot be each other — they have an identity — we may automatically get a type of infon lattice that entails matter pieces cannot occupy the same space as other matter. This would greatly simplify the thing model as well as the geometry models.
Again, that is wild speculation. It almost certainly will not work out.
The reader may have noticed while reading through this series that the expressiveness for making models as well as the complexity of what models can be made goes up as more “foundational” models exist.
Here are some models that will increase the usefulness of Proteus:
Geometric models
A good Thing model
Models of the SI units such as meters, seconds, and so on.
A good model of simple personhood so we can talk about WHY we need different things. And perhaps models of, for example, Maslow’s Hierarchy of Needs and Kohlberg’s Levels of Moral Development.
A model of how we use money
Basic models of our situation: We live on the surface of a planet, there is a sun, there are land masses and oceans, countries with governments; we have a 24 hour day…
Once those basics are modeled we need a system for validating new models that each person can apply to incoming information as they wish. With such a fast way of collecting and validating theories and news, we can work together more easily to rapidly advance different fields like medicine or social living or achieving consensus in politics. And because these models are text files and are human readable, AI based on them will be an order of magnitude safer.
As of this writing, software to safely coordinate all this across the planet is designed and about 90% written. Our reference Proteus engine needs some bug fixes and there are some inferences it does not yet make. If you think this is cool, read about it on https://theslipstream.com. And if you believe in open source software and open models, pick a task and/or chat with us about how to contribute!

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.