SC Programming Guide

There are several versions of the systemic computation programming language. Here we describe the latest version as used by the most recent OpenCL version of Systemic Computation, and partially supported by HAoS, the hardware version of SC.

Overview

Every SC program is a simple text file and must strictly follow the structure below.

// SC programs must begin with the starting keywords
#systemic start

// comments are added one line at a time by beginning with the double slash, whitespace is ignored
// the first section is function definitions - here we list the functions and their binary values
// these must be the correct values - the programmer can add new functions in C which are referenced here
#function NOP       %b0000000000000000
#function ADD       %b1000000000000000
#function PRINT     %b1000100000000000

// following the list of functions, we define labels to make programming easier
// labels are simply constants to be used later in the program
#label zero       %b0000000000000000
#label one        %b1000000000000000
#label dontcare   %b????????????????

// we next define the systems in our SC program
// each is defined by giving a name and then providing the (schema function schema) triplet in parentheses
// systems used for data may only contain numbers:
main (%d0 %d0 %d0)

data1 (num %d0 %d23)
data2 (num %d0 %d83)
data3 (num %d0 %d98)

// systems designed to behave as contexts, which determine how the other systems will interact, can be defined in more detail
// we define the systems that each schema can match by spelling out the triplets inside square brackets
// we define the function that will be executed when matching systems interact with this context by using the name of the function
// we can define multiple copies of a system using the array identifier [0:n]
output     ([dontcare dontcare dontcare] PRINT(0,0) [dontcare dontcare dontcare])
[0:2]sum     ([num zero dontcare] ADD(0,0) [num zero dontcare])

// we can optionally chain one context system to others
// to give each context system in the chain the option of causing the next context system in the chain to execute
// instead of relying on purely random ordering
// this is written using the #chain command to define the first context
#chain sum
{
     // we then define the chain within curly brackets {}, each chainlink in a chain is joined with a +
     // the chainlink is given in parentheses, with the original left and right schemata denoted by $L and $R
     // new random schemata are denoted by ?name, and these schemata may be passed to later chainlinks in the chain by passing the same name
     ($L output $R) + (?A sum $R) + (A sum $R)
     // the same first context may have more than one chain hanging from it; the context has the choice which chain it triggers
     // if the final system in the chain is itself chained, then the new chain will start; in this way loops can be created
     (?A sum ?B)
}

// finally, we define the membership of systems within each others' scopes using the #scope identifier
// two systems can only interact with a matching context if all three are within the same scope (comprising a valid triplet)
// scopes can be members of themselves; both context and scope can be the same system
// again the array identifier can be used to define the membership of multiple copies of systems
#scope main
{
      data1
      data2
      data3
      [0:2]sum
      output
}

// SC programs must end with the ending keywords
#systemic end

Comments

Comments are added one line at a time by beginning with the double slash:

// example comment

Note that all whitespace in programs is also ignored.


#systemic start

Every SC program must begin with the #systemic start command:

#systemic start

#systemic end

Every SC program must end with the #systemic end command:

#systemic end

#function

After the #systemic start command, functions are defined by the #function command:

#function  NAME  %b<binary value>

Each #function must have a text NAME followed by a binary code written as %b00000000000000000000000000000000, where the length of the binary value must be the same as SCALEFACTOR*32. (SCALEFACTOR is defined in scp.ini). It is also possible to specify the number in decimal following the %d symbol, e.g. %d13 but normally binary is used as it makes programming easier.

Important: The textual names for each function and the binary codes should match the names and codes used by the compiler (files sc_functions.c and sc_functions.h and in any user-defined function files) otherwise the wrong functions may be called.

All functions used in the program must be declared using the #function command. Not all functions declared must be used.

The first 22 functions are built-in system functions such as ADD and COPY. See below for a standard list of functions and their binary codes:


function names and codes

#function NOP               %b00000000000000000000000000000000
#function ADD               %b10000000000000000000000000000000
#function ADDe              %b01000000000000000000000000000000
#function SUBTRACT          %b11000000000000000000000000000000
#function SUBTRACTe         %b00100000000000000000000000000000
#function MULT              %b10100000000000000000000000000000
#function MULTe             %b01100000000000000000000000000000
#function DIV               %b11100000000000000000000000000000
#function DIVe              %b00010000000000000000000000000000
#function MOD               %b10010000000000000000000000000000
#function MODe              %b01010000000000000000000000000000
#function AND               %b11010000000000000000000000000000
#function OR                %b00110000000000000000000000000000
#function EOR               %b10110000000000000000000000000000
#function ZERO              %b01110000000000000000000000000000
#function ESCAPE            %b11110000000000000000000000000000
#function CAPTURE           %b00001000000000000000000000000000
#function PRINT             %b10001000000000000000000000000000
#function COPY              %b01001000000000000000000000000000
#function ISZERO            %b11001000000000000000000000000000
#function ISEQUAL           %b00101000000000000000000000000000
#function CAPTUREINHERIT    %b10101000000000000000000000000000

#label

Labels are equivalent to the #define in C. They allow a text name or word to be used in the place of a number in the code:

#label  one               %b10000000000000000000000000000000

Numbers may be specified in binary using the %b format or decimal using the %d format. Note that the wildcard symbol is also accepted in the binary definitions, allowing fuzzy values to be represented:
#label dontcarefirst4    %b????0000000000000000000000000000

The frequent use of labels is strongly recommended for readable code in SC programs.

system definitions

In the simplest form, systems are defined by specifying a name followed by a triplet of symbols in parentheses:

molecule (num %d0 %d23)

In this example, the system is named "molecule". It has no function, a left schema equal to the value of label "one" and a right schema equal to the decimal value 23.
As the example shows, the triplet of symbols can be numbers and/or labels. The first defines the value for the first schema. The second defines the value for the function - if zero this typically corresponds to NOP, meaning this system will not behave as a context system and so may be used for data storage alone. Note that the name of the system must not be the same as any existing system (function name or label) declared earlier.
In the more detailed form, systems are defined by specifying a name followed by a triplet of symbols in parentheses, where the first and third symbols may themselves be written as triplets of symbols within square brackets, and the second symbol may be written as a reference to a function declared earlier:
output     ([dontcare dontcare dontcare] PRINT(0,0) [one dontcare dontcare])

In this example the system is named "output". The first schema is defined as a triplet of values, all equal to the label "dontcare". The second schema is also defined as a triplet of values, with the first schema equal to the value of label "one" and the other values all equal to the value of label "dontcare". The symbol in the middle defines the function - in this case PRINT - with two matching threshold values of 0. Thus, we have defined a system which will match any other system on the first schema and all systems with a value of exactly "one" on their first schema and any other value for their function and second schema. The result of the interaction will be that the PRINT transformation function will be executed. Note it is possible to mix the forms of system definition as required - any schema may be defined as a binary or decimal value, as a label, or as a triplet of binary or decimal values or labels within square brackets. The functional part may be defined as a binary or decimal number, a label, or a function name.
Finally there is a third method of defining systems - the use of the array identifier. In this method we place a number range before the name of the system. This has the effect of producing a set of systems with the same name, differentiated by a number. For example:
[0..4]output     ([dontcare dontcare dontcare] PRINT(0,0) [one dontcare dontcare])

When compiled, this example system definition will create five systems with the names:
output0
output1
output2
output3
output4

This means that it is possible to create many identical systems with a single definition. It also means that individual systems may be referred to by their names above and may be placed in different scopes, despite being created en mass. Note that the compiler treats the systems as separately named systems so the programmer may not use the names: output0, output1, output2, output3, or output4 for any other system definitions.

#chain

The #chain command enables the SC programmer to chain context systems together in a sequential and deterministic manner so that as soon as one has finished executing its function, the next in the chain will be executed. Chains are powerful ways to cause a fast sequence of transformations to occur to the same systems or even to different systems in the same scope. Conditional chains enable different branches of a chain to be executed depending on the result of a transformation function. Chains may even behave as loops. All systems in the #chain command must have been previously declared or the compiler will produce an error.
The following example shows the simplest form of a chain:

#chain sum
{
     ($L output $R)
}

In the example the #chain command identifies the system named "sum" as the head of the chain. The curly brackets (which must be placed alone on a line as shown) enclose the systems that are chained to "sum". In this example a single system called "output" is chained to "sum". The two schemata to be passed to output are the same left $L and right $R schemata that "sum" transformed. The definition of schemata and system is enclosed by parentheses. Now every time "sum" transforms two systems, this chain will cause "output" to transform the same two systems immediately after. The only exception will be if one or more of the two systems passed to a chained context (and/or the chained context itself) are not in the same scope, in which case the chain will be broken and the systemic computer will resume its normal parallel interactions.
A variant of the above example is given below:
#chain sum
{
     ($L output $R) + ($L sum $R)
}

In this example there are two systems chained to "sum": "output" and "sum". This chain will behave like a loop, with first sum, then output, then sum being executed, which will trigger the same chain of output and sum, and so on. The same left and right schema are used throughout for all functions. Again, all systems must be in the same scope for the chain to be valid.
The third variant of the chain command enables conditional chaining. Every transformation function returns an integer value to the systemic computer. This is used to define which branch of the chain should be executed, where 0 is the first, 1 is the second, and so on:
#chain cond_calculate
{
     ($L add $R)
     ($L subtract $R)
}

In the example above, if the return value from the chain head "cond_calculate" is 0, then the "add" system will be executed next. If the return value is 1, then "subtract" will be executed next. If the return value is greater than 1 in this case then the chain will be broken and the SC will return to normal parallel interactions. A return value of -1 forces a chain break after the chain head.
The final variant of the chain command enables the programmer to create and use temporary variables in chains. This addresses the need for chains to operate on schemata that may be different from the original two schemata $L and $R of the chain head. A variable is declared using the syntax: ?name and is reused by using the name alone. On declaration of a new variable the systemic computer searches for a random matching schema to attach to that variable. The same schema will then be used for all subsequent uses of that variable.
#chain variable_passing_chain
{
    ($L output $R) + (?A sum $R) + (A sum $R)
}

In the example above, after execution of the chain head "variable_passing_chain", the two systems from the head $L and $R are passed to "output". After execution of "output", a new random system matching the left schema of "sum" will be found, named "A", and used, together with the original $R system. After execution of "sum", the same system "sum" will be executed using the same systems "A" and $R. In all cases the systems must match the schemata of the context and share the same scope for the chain to be valid, otherwise the chain will be broken. In this way chains may use the original two systems from the chain head or may use and reuse any other systems. Note that all variable names are temporary and discarded at the termination of the chain (even if the chain then call itself in a loop).
It should be noted that chains are not recursive. A chain with links to other chained systems will only cause those other chains to be executed if the chained system is the last link in the current chain.
#chain sum
{
    (?A sum ?B) + (?C sum ?D) + (A sum D)
}

In the example above, after execution of the chain head "sum", all three subsequent "sum" executions will take place, with only the final "sum" then causing the chain to start again. Chained systems can only initiate new chains if they are the chain head, or chain tail.

#scope

The #scope command enables the programmer to specify where the previously declared systems reside, i.e. which systems lie in the scope of which other systems:

#scope main
{
     data0
     data1
     sum
     output
}

In the example above, system "main" has four systems within its scope: "data0", "data1", "sum" and "output". The #scope command must be written exactly as shown, with curly brackets denoting the beginning and end of the set of systems, each curly bracket on a separate line, and each system on a separate line. All systems in the #scope command must have been previously declared or the compiler will produce an error. Note that scope memberships are independent from each other and may be set entirely at the discretion of the programmer. For example, system A can be within system B and system B can be within system A. Systems can also be members of themselves. There can also be spatially impossible memberships, e.g.
#scope systemA
{
     systemB
}

#scope systemB
{
     systemC
}

In the example above, systemC is within the scope of systemB, and systemB is within the scope of systemA. However systemC is not within the scope of systemA, for the programmer has not defined this relationship. (When depicting these relationships using SC graph notation it is often necessary to draw partially overlapping systems.)
Finally, it is also possible to use the array notation within the #scope command to specify the membership of many systems at the same time:
[0..9]data (%d0 %d0 %d0)

#scope systemA
{
     data0
     [1..3]data
     data9
}

#scope systemB
{
     [0..9]data
}

In the example above, systems "data0", "data1", "data2", "data3", and "data9" are all in the scope of systemA. All data systems are in the scope of "systemB".

Built-in SC function set:

The low level function set for the systemic computer follows. Every function must take two systems as input, and transform those two systems as output. Each function returns an integer value to the SC for use in chaining. Note that each function must be declared in the program and must be specified by a context system, operating on the two systems that are chosen by the SC because they match the schemata of the context.

NOP

No operation. Systems with this function will not behave as contexts for other systems.

Function name:                  NOP
Function value:                 %b00000000000000000000000000000000
Function:                       No operation.
Interacts with:                 S1[x x x]  S2[x x x]
Transformation Result:          S1[x x x]  S2[x x x] (no change)
Returns:                        0

ADD

Adds binary values of S12 and S22, placing results in S12 and zeroing S22; overflow is ignored, other characters are ignored.

Function name:                  ADD
Function value:                 %b10000000000000000000000000000000
Function:                       addition
Interacts with:                 S1[x x  S12]       S2[x x S22]
Transformation Result:          S1[x x (S12+S22)]  S2[x x %d0]
Returns:                        0

ADDe

Performs the ADD function followed by the ESCAPE function.

Function name:                  ADDe
Function value:                 %b01000000000000000000000000000000
Function:                       addition + escape (implicit chain)
Interacts with:                 S1[x x  S21]       S2[x x S22]
Transformation Result:          S1[x x (S12+S22)]  S2[x x %d0]
                                scope(S1) = scopes(parent(S1))
Returns:                        0

SUBTRACT

Subtracts binary values of S12 - S22, placing results in S1 and zeroing S2; underflow is ignored, other characters are ignored

Function name:                  SUBTRACT
Function value:                 %b11000000000000000000000000000000
Function:                       addition
Interacts with:                 S1[x x  S12]       S2[x x S22]
Transformation Result:          S1[x x (S12+S22)]  S2[x x %d0]
Returns:                        0

SUBTRACTe

Performs the SUBTRACT function followed by the ESCAPE function.

Function name:                  SUBTRACTe
Function value:                 %b00100000000000000000000000000000
Function:                       subtraction + escape (implicit chain)
Interacts with:                 S1[x x  S12]       S2[x x S22]
Transformation Result:          S1[x x (S12-S22)]  S2[x x %d0]
                                scope(S1) = scopes(parent(S1))
Returns:                        0

MULT

Multiplies binary values S12 * S22, placing results in S12 and setting S22 to 1; under/overflow is ignored, other characters are ignored

Function name:                  MULT
Function value:                 %b10100000000000000000000000000000
Function:                       multiply
Interacts with:                 S1[x x  S12]       S2[x x S22]
Transformation Result:          S2[x x (S12*S22)]  S2[x x %d1]
Returns:                        0

MULTe

Performs the MULT function followed by the ESCAPE function.

Function name:                  MULTe
Function value:                 %b01100000000000000000000000000000
Function:                       multiply + escape (implicit chain)
Interacts with:                 S1[x x  S12]       S2[x x S22]
Transformation Result:          S1[x x (S12*S22)]  S2[x x %d1]
                                scope(S1) = scopes(parent(S1))
Returns:                        0

DIV

Divides binary values S12 / S22, placing results in S12 and setting S22 to 1; under/overflow is ignored, other characters are ignored

Function name:                  DIV
Function value:                 %b11100000000000000000000000000000
Function:                       multiply
Interacts with:                 S1[x x  S12]       S2[x x S22]
Transformation Result:          S1[x x (S12*S22)]  S2[x x %d1]
Returns:                        0

DIVe

Performs the DIV function followed by the ESCAPE function.

Function name:                  DIVe
Function value:                 %b00010000000000000000000000000000
Function:                       divide + escape (implicit chain)
Interacts with:                 S1[x x  S12]       S2[x x S22]
Transformation Result:          S1[x x (S12/S22)]  S2[x x %d1]
                                scope(S1) = scopes(parent(S1))
Returns:                        0

MOD

Finds the remainder of S12 / S22, placing results in S12 and setting S22 to 1; under/overflow is ignored, other characters are ignored

Function name:                  MOD
Function value:                 %b10010000000000000000000000000000
Function:                       modulus
Interacts with:                 S1[x x  S12]       S2[x x S22]
Transformation Result:          S1[x x (S12%S22)]  S2[x x %d1]
Returns:                        0

MODe

Performs the MOD function followed by the ESCAPE function.

Function name:                  MODe
Function value:                 %b01010000000000000000000000000000
Function:                       modulus + escape (implicit chain)
Interacts with:                 S1[x x  S12]       S2[x x S22]
Transformation Result:          S1[x x (S12%S22)]  S2[x x %d1]
                                scope(S1) = scopes(parent(S1))
Returns:                        0

AND

Applies bitwise AND to S11 and S21, and also S12 and S22, placing results in both; ignores non-binary characters

Function name:                  AND
Function value:                 %b11010000000000000000000000000000
Function:                       logical AND
Interacts with:                 S1[S11 x  S12]             S2[S21 x S22]
Transformation Result:          S1[(S11&S21) x (S12&S22)]  S2[(S11&S21) x (S12&S22)]
Returns:                        0

OR

Applies bitwise OR to S11 and S21, and also S12 and S22, placing results in both; ignores non-binary characters

Function name:                  OR
Function value:                 %b00110000000000000000000000000000
Function:                       logical OR
Interacts with:                 S1[S11 x  S12]             S2[S21 x S22]
Transformation Result:          S1[(S11|S21) x (S12|S22)]  S2[(S11|S21) x (S12|S22)]
Returns:                        0

EOR

Applies bitwise XOR to S11 and S21, and also S12 and S22, placing results in both; ignores non-binary characters

Function name:                  EOR
Function value:                 %b10110000000000000000000000000000
Function:                       logical XOR
Interacts with:                 S1[S11 x  S12]             S2[S21 x S22]
Transformation Result:          S1[(S11^S21) x (S12^S22)]  S2[(S11^S21) x (S12^S22)]
Returns:                        0

ZERO

Applies zeroing function to S11, S12 and S21, S22 placing results in both;
Zeroes all ones in schemata sections but ignores everything else (to protect codes if used)

Function name:                  ZERO
Function value:                 %b01110000000000000000000000000000
Function:                       Zero 1s
Interacts with:                 S1[111 x 111]    S2[111 x 111]
Transformation Result:          S1[000 x 000]    S2[000 x 000]
Returns:                        0

ESCAPE

Removes S1 from the scope of its S1 and S2 are otherwise unchanged.
Puts S1 into all the scopes that the parent is in.
Assumes parent(S1) exists (i.e., that S1 is not a root system) and that it actually has systems in its scope

Function name:                  ESCAPE
Function value:                 %b11110000000000000000000000000000
Function:                       Escape from current scope
Interacts with:                 S1[x x x]    S2[x x x]
Transformation Result:          S1[x x x]    S2[x x x]
                                scope(S1) = scopes(parent(S1))
Returns:                        0

CAPTURE

Adds S1 to the scope of S2; S1 and S2 are otherwise unchanged
Removes S1 from the scope of parent scope for this interaction

Function name:                  CAPTURE
Function value:                 %b00001000000000000000000000000000
Function:                       Capture system into scope
Interacts with:                 S1[x x x]        S2[x x x]
                                S1parent(S1)     S2
Transformation Result:          S1[x x x]        S2[x x x]  (unchanged)
                                S1parent()->S1   S2(S1)
Returns:                        0

PRINT

Prints the contents of S1 and S2 to screen; note: may be disabled by compiler directive for speed

Function name:                  PRINT
Function value:                 %b10001000000000000000000000000000
Function:                       Print systems
Interacts with:                 [x x x]      [x x x]
Transformation Result:          [x x x]      [x x x]  (unchanged)
Returns:                        0

COPY

Copies S2 over S1, including both schemata and functional parts

Function name:                  COPY
Function value:                 %b01001000000000000000000000000000
Function:                       Copies S2 to S1
Interacts with:                 [S11 SF1 S12]      [S21 SF2 S22]
Transformation Result:          [S21 SF2 S22]      [S21 SF2 S22]
Returns:                        0

ISZERO

Checks if S12 == 0, placing Boolean result in last bit of S11 and returning 1 if TRUE or 0 if FALSE for conditional chaining purposes

Function name:                  ISZERO
Function value:                 %b11001000000000000000000000000000
Function:                       Is S12 == 0?
Interacts with:                 [xxx x S12]      [x x x]
Transformation Result:          [xx1 x S12]      [x x x]      if (S12 == 0)
                                [xx0 x S12]      [x x x]      if (S12 != 0)
Returns:                        1      if (S12 == 0)
                                0      if (S12 != 0)

ISEQUAL

Checks if S11 == S21 && S12 == S22, returning 1 if TRUE or 0 if FALSE for conditional chaining purposes

Function name:                  ISEQUAL
Function value:                 %b00101000000000000000000000000000
Function:                       Does (S11 == S21 && S12 == S22)?
Interacts with:                 [S11 x S12]      [S21 x S22]
Transformation Result:          [S11 x S12]      [S21 x S22]   (unchanged)
Returns:                        1      if (S11 == S21 && S12 == S22)
                                0      if !(S11 == S21 && S12 == S22)

CAPTUREINHERIT

Put all systems in S2 into scope of S1; also place S2 into scope of S1

Function name:                  CAPTUREINHERIT
Function value:                 %b10101000000000000000000000000000
Function:                       capture S2 and its contents into S1
Interacts with:                 S1[x x x]      S2[x x x]
                                S1()    S2(S[0..n])
Transformation Result:          S1[x x x]      S2[x x x]   (unchanged)
                                S1(S2)  S1(S[0..n])
Returns:                        0

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License