Unusual features of Numipulator
Unusual features of Numipulator

Numipulator has a number of unusual, interesting features. These are ones concerned with the numipulation boxes.

Item-by-item handling and cycling

In many types of numipulation box, lists are handled item by item. This makes Numipulator very convenient for handling many numbers when you wish to carry out the same operation on each. So, for example, the Items Operation numipulation box carries out the same operation on corresponding items in two lists to give the resulting list, as shown in the first example below. If the second list consists of just one item, it will carry out the same operation using this number on each of the items in the first list, as shown in the second example below.

Items Operation
Items Operation

Now, for a true item-by-item operation, the two lists should have the same number of items to work on. But, in fact, as seen in the second Items Operation example above, we can have several items in the first, but only one in the second. This is because Numipulator allows cycling of items, as explained next.. Note: the labels for these item lists are generally shown with square brackets around them, e.g. [a] and [b]

The first list is treated as the primary item list (denoted here by the single quote after the [a]). If there is more than one list of items, one of these - and it's always the top one - is treated as the primary item list. The second list, and maybe others, are treated as secondary item lists, denoted by the double quote after the [b]. The primary item list determines the number of operations carried out, since the operation is carried out on each of its items in turn. The secondary items are taken one at a time to be used in these operations; if the end of a secondary item list is reached but there are still items in the primary list to be dealt with, items are selected from the beginning of the secondary list again. That is, the secondary items are cycled to match the primary items.

To demonstrate, suppose the primary list, has values 2, 4, 6, 8 - that is, 4 items. Let's look at what happens if a secondary item list has 1, 2, 3, 4 or 5 items in it.

  • if the secondary list has one item = 10, then it is treated as the list 10, 10, 10, 10
  • if the secondary list has two items = 10, 20, then it is treated as the list 10, 20, 10, 20
  • if the secondary list has three items = 10, 20, 30, then it is treated as the list 10, 20, 30, 10
  • if the secondary list has four items = 10, 20, 30, 40, then it is treated as the list 10, 20, 30, 40
  • if the secondary list has five items = 10, 20, 30, 40, 50, then it is treated as the list 10, 20, 30, 40 - i.e. any surplus items are ignored

The common cases, where there is just one item in a secondary item list or the same number as in the primary item list, can be seen to be special cases of this general approach to handling more than one item list.

Handling tables

Although lists and numbers are the only core object types in Numipulator, some numipulation boxes are designed to perform operations on or transformations of a table. In such cases, the input table is always defined by two inputs: a list and a number (a positive integer).

  • The list (given the identifier la) always represents the values in the cells of the table, laid out along the rows (starting at the top row and always going left-to-right).
  • The number (given the identifier ncols) always represents the number of columns in the table;

So, the input table

1 2 3 4
6 3 2 7
8 9 0 1

would be represented by la=1, 2, 3, 4, 6, 3, 2, 7, 8, 9, 0, 1 and ncols=4

The number of rows in the table is, of course, implied by la and ncols.

Because the only core object types in Numipulator are lists and numbers, a table cannot be the result of a numipulation box. However, the list of cell values can, of course, be given as the result. So, for example, if the above input table had its rows and columns transposed in an operation, giving the table

1 6 8
2 3 9
3 2 0
4 7 1

the result would be given as the list of cell values (starting at the top row and always going left-to-right):

1, 6, 8, 2, 3, 9, 3, 2, 0, 4, 7, 1

Note: Numipulator uses the number of columns as a parameter (rather than number of rows) because tables of data in spreadsheets are generally designed to have a fixed number of columns, but a variable number of rows, so, when handling a table, the number of columns is generally a given. Numipulator bases its handling of a table where la is an empty list accordingly, i.e. treating the input table as still having a given number of columns, but no values in these (i.e. 0 rows). So, if la=L0 (this is the Numipulator for an empty list, with no items on it) and ncols=3, the sums of its columns would be 0, 0, 0 (3 columns, each with a sum of 0), while the sums of its rows would be L0 (an empty list, as there are no rows).

Handling numerical expressions

The Number Operation numipulation box handles just one operation between two numbers. Strictly, this is adequate for all operations you might need to perform, but linking several of these to evaluate a more complex expression, e.g. 2 x 3 + 4 / 2, can be tedious. Numipulator therefore provides a feature that allows some more complex expressions to be evaluated in one numipulation box.

The Calculator function (found in the List Function to Number numipulation boxes) has as its single input a list that is treated as a combination of numbers and operator codes: codes representing Number Operations, e.g. +, -, x and /. The codes that represent the number operations are found by pressing the Codes link in Numipulator, but, in brief, 1 means add, 2 means subtract, 3 means multiply and 4 means divide, 5 means % - these are the order in which the operations are found in the drop-down list of Number Operations. The list starts with a Number, which is followed by any number of Operator code, Number pairs, i.e. Num, Op, Num, Op, Num... The list is evaluated from left to right, as if the numbers and operators were being entered into a standard calculator. So, 2 3 3 1 4 4 2 is treated as the Number/Operator list: 2 x 3 + 4 / 2, which means ((2 x 3) + 4) / 2, i.e. 5.

Alternatively, the Expression function takes the same input list, but instead of evaluating the operations from left to right, like a calculator, standard arithmetic operator precedence is employed (BODMAS/PEMDAS), where multiplication and division are carried out before addition or subtraction. So, the input list 2 3 3 1 4 4 2 is again treated as the Number/Operator list: 2 x 3 + 4 / 2, but this time it is taken to mean (2 x 3) + (4 / 2), i.e. 8.

As well as including operators in these expressions, number functions can also be included, through the use of the mock operator code 100. In this case, the number following 100 is treated as a number function code, similar to operator codes: 1 means square, 2 means square root, 3 means +/-, and so on. So, 4 100 1 1 pi means 42 x pi, as 4 100 1 means 4 squared.

Clearly, neither reading nor writing such expressions is easy. However, use may be made of Mappings for inputs, whereby symbols or words (with some exceptions) can be mapped to numbers and used instead of those numbers in inputs, if desired. So, if Mappings are defined as follows:
+ 1
- 2
x 3
/ 4
% 5
100 f
square 1
sqrt 2
then the list 2 3 3 1 4 4 2 may be entered as 2 x 3 + 4 / 2, while the list 4 100 1 1 pi may be written as
4 f:square x pi. These are much more readable/intuitive. Remember to put the spaces (or other separators) between the numbers and operators.

List Function to Number

Handling logic expressions

The Number Operation numipulation box also includes a number of Check (1/0): operations. The (1/0) here indicates that the output can only be 1 or 0. So, the operation Check (1/0): a<b has the result 1 if a (the first input) is less than b (the second input), otherwise it has the result 0. Numipulator has no normal Boolean values (TRUE/FALSE), but uses 1/0 instead. In addition, the Number Operation box has a number of Logic (1/0): functions, such as Logic (1/0): a AND b and Logic (1/0): a OR b functions. These again produce results of only 1 or 0. Logic (1/0): a AND b produces the result 1 if both a and b are 1 or any non-zero value, or 0 otherwise. Logic (1/0): a OR b returns the result 1 if either a or b is non-zero, or 0 if both a and b are zero.

The Expression function can include these in the expressions it handles, again using certain integers (14-19 for the Check operations and 20-25 for the Logic operations) to specify these operations. As with the numerical expressions, the built-in Input Mappings may be employed to make these expressions more readable, so that the expression A1 < A2 AND A1 > 1 OR B1 = 5 OR 4 x B2 > 25 would be a valid expression. Note that arithmetic operations are carried out first, using BODMAS/PEMDAS precedence, followed by Check operations (<, =, >, etc.), then AND operations, and finally OR operations. The full meaning of this expression is therefore: ((A1 < A2) AND (A1 > 1)) OR (B1 = 5) OR ((4 x B2) > 25).

Numbers and lists - syntax and interchangeability

Numbers and lists of numbers are inherently different types. In most computing languages, they would be treated differently, and you would need to be careful to distinguish the two. In Numipulator, however, you may freely mix numbers and lists of numbers.

To explain what we mean by this, consider the following list input to a numipulation box:

Now, A1 is a reference name that refers to a number output (from a Number Operation), while L2 refers to the output from a Findall operation, which produces a list output. To determine what this input represents, we simply replace the reference names with the number or list of numbers that they represent. So, if A1 evaluates to the number 4 and L2 evaluates to the list of numbers 6, 7, then the list would have the value 1, 2, 3, 4, 5, 6, 7, 8. If A1 evaluates to 60 and L2 evaluates to the list with just one number, 70, on it, then the value of the input would be the list 1 2 3 60 5 70 8. One more option to consider is when A1 evaluates to 4 but L2 returns an empty list; in this case, the input has the value 1 2 3 4 5 8, as there are no numbers to insert between the 5 and the 8.

A reference name to a list numipulation box may also be used as an input when a single number is expected, e.g. to a Number Operation. In this case, the first or only number on the list is treated as the input number. This makes Numipulator very flexible, as it means that any numipulation box that has a list output with only one number on it may be used exactly as if it had a number output. So, given the Items Operation discussed above, if the first input were the single-item list 2 and the second input were the single-item list 3, then the output would be the single-item list 6, which could be used exactly as if it were the number output from a Number Operation. This means that in theory we could have omitted Number Operation boxes and Number Function boxes from Numipulator altogether, and just used the Items Operation and Items Function boxes instead. In practice, however, it was felt that the Number ... boxes were important, as single-number operations would be familiar to users. Likewise, we could have combined the List Function to Number boxes and the List Function to List boxes into a List Function box, with some outputs being always being single-item lists, but chose not to do so. As you will see in the next section, on If-Then-Else boxes, the outputs are always lists. Because these can be used as if they were number outputs, where appropriate, we chose not to include separate number output versions of these.

This flexibility means that inputs to lists are always simple, syntactically. In Numipulator, the programmer does not need to explicitly join (concatenate) two lists with a concatenation function; the programmer merely writes one after the other in an input, so that they are implicitly concatenated, e.g. L1 G4, which effectively means L1 concatenated with G4.

Because a list of numbers is written in the list box as simple numbers, it might be thought that an empty list would be specified as an empty box. However, the system checks for syntax errors before carrying out any calculations, and it is important that the system can determine which numipulation boxes are being used or are incompletely specified. A blank list box is taken to indicate that this input is not specified (deliberately or accidentally). Therefore, we enter the term L0 (meaning list of 0 length) to indicate that the input is an empty list. Likewise, L0 is written by Numipulator as the output if the result is an empty list, rather than just leaving the output field blank.

If-Then-Else numipulation boxes and Case functions

If-Then-Else boxes are an essential feature of Numipulator, as your program must be designed to produce new states and graphical output for all possible states and user interactions, and these provide the functionality to generate alternative outputs for the various input states and user inputs. There are four different types of If-Then-Else box. Each has four inputs: the first two are numbers or lists involved in some form of comparison defined in the drop-down list, while the last two define alternative outputs based on the results of the comparison.

If-Then-Else (Simple)

The first two inputs (a and b) are simple numbers, and the comparisons are just <, <=, =, <>, >=, >. The last two inputs (lc and ld) are alternative list outputs.
e.g. if a < b: lc, else ld (other comparisons similar)
Example: a=3; b=4; lc=25; ld=50: Result=25 (as 3<4 the result is lc)

If-Then-Else (All)

The first two inputs ([a] and [b]) are item lists, with the usual item cycling. The comparisons are as above, but in this case the check is whether every comparison between the two corresponding items succeeds. The last two inputs (lc and ld) are alternative list outputs.

e.g. if all a < b: lc, else ld (other comparisons similar)
Example: [a]=2, 5, 4, 3; [b]=4; lc=25, 26, 27; ld=50, 51: Result=50, 51 (ld is the output as two of the comparisons fail)

If-Then-Else (Items)

The first two inputs ([a] and [b]) are item lists, with the usual item cycling. Comparisons are <, <=, ... > as before. The last two inputs, [c] and [d], are also secondary item lists. In this case, the output list is made up of items from either [c] or [d], depending on whether the corresponding comparisons between the items on [a] and [b] succeed.

e.g. if a < b: c, else d (other comparisons similar)
Example: [a]=2, 5, 4, 3; [b]=4; [c]=25, 26, 27, 28; [d]=0: Result=25, 0, 0, 28 (Two of the comparisons succeed, so the results for those are taken from [c], and two fail, so the results are taken from [d])

If-Then-Else (List)

The first two inputs (la and lb) are lists, and comparisons are made between la and lb as a whole, e.g. la=lb, or all la on lb (i.e. la is a subset of lb). The last two inputs, lc and ld, are alternative list outputs.

e.g. if la=lb, lc, else ld
Example: la=2, 5, 4, 3; lb=5, 2, 3, 4; lc=25, 26, 27, 28; ld=0: Result=0 (The lists are not equal, so the result is ld)

Probably the most useful of the available functions in this box is if exp(la)=lb, lc, else ld. A simple use of this is to permit a complex logic expression to be specified in la, with lb being specified as 1 (to indicate that the expression should be true), or 0 (to indicate that it should be false). So, if la=A1 < A2 AND A1 > 1 OR B1 = 5 OR 4 x B2 > 25, lb=1, lc=20 and ld=30, then if A1 < A2 AND A1 > 1 OR B1 = 5 OR 4 x B2 > 25 is true (result = 1), then the result is 20, otherwise it is 30.

Numipulator also includes Case... functions in the List Function to Number numipulation boxes. These are useful if you wish to make a series of simple number comparisons and to have, as output, a single number based on these comparisons. There are six similar Case functions, e.g. Case: <, Case: <=, Case: =, and so on. The input is a single list of numbers, which should be considered in groups of three, leaving one additional number. If the selected comparison between the first and second items of the three succeeds, then the output is the third. If it fails, then the second group of three is checked likewise, until a result is found. If no result is found by checking the groups of three, then the additional number, the default, becomes the output.

e.g. Case: <
Example: Input=4, 3, 1, 4, 4, 2, 5. Result=5 because the check 4<3 failed and 4<4 failed, so the default result 5 becomes the result.
Example: Input=4, 3, 1, 4, 4, 2, 4, 5, 6, 5. Result=6 because the first two checks failed, as above, but the third check, 4<5 succeeded, so the result is 6.

Note: it can be useful to employ different separators to make these more readable, e.g. 4, 3: 1; 4, 4: 2; 4, 5: 6; 5

Other more complicated Case functions are also available.

Lack of features found in most other programming languages

The simplicity of Numipulator (particularly its simple syntax for input lists) comes at a price: Numipulator lacks many of the features and functionality found in most other languages or systems.

a. Numipulator does not provide special syntax to allow access to particular elements of lists, as you might in other languages where you might write A1[2] to return the 3rd element of list A1 (in many languages, the first element of a list has index 0). Instead, you must use the Item p1 operation (a List Operation), and make the first input A1 and the second 3. Using normal indexing (starting at 1) is clearly easier to understand, and you can put in several numbers in the second list, e.g. 3, 5, 7, which would have as its output a list with the 3rd, 5th and 7th items on the list.

b. Numipulator does not let you include mathematical expressions to be evaluated within a wider list, e.g. 1, 2, 18x2/12, 4, to yield the list 1, 2, 3, 4. You can, as described above, use the Expression or Calculator functions to evaluate and output such expressions.

c. While Numipulator provides a wide array of built-in numerical calculation and manipulation functions/operations, it does not provide you with the possibility of adding new or customized functions.

d. Numipulator does not provide variables that can be used to store values. It does offer Memory numipulation boxes that can effectively be used to remember values from one cycle to the next. These are quite different from variables, as the value of variables can be modified at any time during the running of a program in a procedural language. In contrast, the output of a Memory box is taken only after Function Evaluation has been completed for the cycle, and used to replace the input specification of the Memory box ready for any future cycle. Overall, with Numipulator, in any single Function Evaluation cycle every numipulation box and every internal value such as now and click has one value only.

e. Numipulator provides no procedural statements at all, such as print() or display(). The processing engine does, of course, print and display output, but it follows the same procedure every time; the programmer can influence this through settings and through values that are evaluated as part of the Function Evaluation, which influence the procedure: these values act as parameters for the procedure. The simplified steps of this procedure are as follows for a program that uses the Graphics Formatter, after the Start button has been tapped to start a set of repetitions with a specified terminating condition:

1. Any non-empty init fields specified in Memory boxes are copied into the mem fields. The init fields for the row and column settings are also copied into their respective specification fields (Graph1 and Graph2).
2. All numipulation boxes with text in their inputs are analysed to yield the numbers contained within them, and any other significant text. The input specifications are checked for any syntax errors, e.g. text that is not a constant (such as pi), a reference name or defined in Mappings, and, if found, a syntax error is thrown. Missing inputs are also identified.
3. The dependencies of numipulation boxes are determined, and an appropriate evaluation order is determined. This may throw up further errors, such as circularity or dependencies on numipulation boxes that are not themselves fully defined. The cycle number is initialized (set to 0).
4. Start of an evaluation cycle: The values of now, and click are determined, in case they are required in the evaluation (and the click monitor is reset to 0). The cycle number is incremented. The graphical input bar is changed to red, to show that no clicking is accepted during function evaluation.
5. The values of all inputs and results are determined by the Function Evaluation procedure, based on the evaluation order determined,. This may throw further runtime errors.
6. At the end of an evaluation cycle, a check is made to see whether further cycles are required according to the termination condition. If not, including if the Stop button has been pressed, step 8 is followed. If further cycles are required (terminating condition not met), step 7 is followed.
7. Repetition required: If the Graphics Display setting is undefined or has a non-zero value, the Graphics Formatter display is updated, otherwise it is left unchanged. The graphical input bar is changed to green (assuming a delay > 0). User clicks, if any, are accepted until the end of the delay time. Clicking changes the value of click to 1, as well as setting the row and column number inputs. For each Memory numipulation box, the values determined for the next fields are assigned to the values for the corresponding mem values. Step 4 is then followed again.
8. After the final cycle: All results are put into the appropriate result output fields and the Graphical Formatter display is updated based on the final results. When results are put into the result fields, the values are displayed following output rounding, according to the user-defined settings.

Copyright TopAccolades Limited, 2023