Data types

We'll show you how it's done!

Numeric variables and strings

In the previous sections we already had numeric variables (my_var) and strings (my_name). Variables are automatically generated when a value is assigned to them. Unlike many other dynamically interpreted languages, in NumeRe numeric variables cannot be converted to strings or vice versa, i.e., variables remain for the current session in the type in which they were created.

However, it is possible to convert numeric variables from pure real values to complex values and back again. To do this, it is only necessary to add an imaginary component or remove it by setting it to zero.

What is of course also possible is to convert the variable values to other types. This can be done either with the #, or by using one of the functions to_string(), to_value(), valtostr(), where their behavior differs partly strongly.

<- to_string(my_var)

-> ans = "my_var"

<- to_value("1+2+3")

-> ans = 6

<- valtostr(my_var)

-> ans = "4.712389"

Tables

The notation of the following, more complex, data types is based on the principle: What is different, should also look different. One recognizes special data types in NumeRe accordingly directly by their call.

Tables are addressed by the expression TABLE(), i.e. with parentheses. So they have a similar syntax as functions. To create a table you use the command new:

<- new my_table()

Tables are used to manage associative data sets, i.e. multiple data series to which one or more properties can be assigned. These can be simple numerical values, e.g. the measured current I at an applied voltage V across a resistor R. They can also be more complex data series that can contain numerical values and character strings mixed together, such as a register of persons with names, age, address and body size.

Tables represent data series in rows, so that the properties are available in columns. Each column can contain a different data type. As an example, here is a data series from the aforementioned person register:

Name Age Address Height

"Erik" 99 "Third rock from the sun, 123" 1.88

[...]

To extract a column from the dataset, my_table(:, 4) can be used. In the example above, this would then return the fourth column, i.e. the heights of all persons. To extract a data series, you simply reverse the logic and write my_table(1, :). This will return the entries of the first row of the table (headers do not count as rows). Of course you can also restrict the other dimension in both cases, e.g. my_table(1, 1:3) to read only name, age and address of the first row.

<- my_table(:, 4)

-> ans = {1.88, 1.46, 1.85, 1.23, ...}

<- my_table(1, :)

-> ans = {"Erik", 99, "Third rock from the sun, 123", 1.88}

<- my_table(1, 1:3)

-> ans = {"Erik", 99, "Third rock from the sun, 123"}

Just as you read data from the table, you can also write new data into it:

<- my_table(1, 2:4) = {88, "Fourth rock from the sun, 11", 2.12}

-> ans = {88, "Fourth rock from the sun, 11", 2.12}

You can also read and write the column headers if you use # as row index:

<- my_table(#, :)

-> ans = {"Name", "Age", "Address", "Height"}

A few final pieces of information:

  • Tables have an autosave function. They are regularly stored in the numere.cache file and are therefore, unlike all other data types, automatically available again on restart.

  • To remove tables and free the memory again, you use the command remove my_table(). If you only want to delete the contents of the table, use clear my_table() (or delete my_table(:, :) if you only want to delete parts of the table). To suppress the confirmation you can append the parameter -ignore: clear my_table() -ignore

Cluster

Clusters are, as the name suggests, unstructured data. In expressions, they are referred to by using CLUSTER{}, i.e. the name with curly braces. A cluster can contain numeric values and strings mixed together, and is therefore well suited to represent the contents of a data series of a table. In fact, the read data of a data series is internally already a cluster. To create a cluster, it is sufficient to assign one or more values to an identifier with curly braces. An explicit command to create is not needed:

<- my_cluster{} = {_pi, "Hello, World!", 42}

-> ans = {3.141593, "Hello, World!", 42}

A cluster is one-dimensional, meaning it can only use one index to be read or written:

<- my_cluster{2:}

-> ans = {"Hello, World!", 42}

In this example, you have output all elements in the cluster starting with element two.

Tables as matrices

We see NumeRe first and foremost as a spreadsheet with a greatly expanded range of functions. The main data type is therefore tables, which are organized in columns. Primarily, you will then process rows and columns individually. But of course the elements of a table can also represent a matrix and be processed accordingly. The only thing you need is the matop command (for "Matrix Operations"). If you pass an expression to this command, it will be processed with matrix algebra. So you can easily create matrices with this command:

<- matop my_mat() = {{1,2,3}, {4,5,6}, {7,8,8}}

/ 1, 4, 7 \

-> | 2, 5, 8 |

\ 3, 6, 8 /

The (in this case automatically generated) table my_mat() contains the generated 3x3 matrix. You can then, for example, determine the determinant and subsequently also the inverse of the matrix using the function invert():

<- matop det(my_mat())

-> (3)

<- matop invert(my_mat())

/ -2.666667, 3.333333, -1 \

-> | 2.666667, -4.333333, 2 |

\ -1, 2, -1 /

You can then verify that it is the inverse of the matrix by performing a matrix multiplication with the operator ** (the normal multiplication operator * performs a component-wise multiplication):

<- matop my_mat() ** invert(my_mat())

/ 1, 1.776357e-015, 0 \

-> | -8.881784e-016, 1, 0 |

\ 0, 0, 1 /

As you can see, rounding errors occur here. However, these are in the order of magnitude of the relative accuracy of the underlying double data type and therefore cannot be avoided completely. You can also use the ** operator to write a matrix-vector multiplication. For example, if we wanted to rotate the vector {1,2,3} by 22.5° around the z-axis, we could write:

<- a = radian(22.5)

-> ans = 0.3926991

<- matop {{cos(a),sin(a),0}, {-sin(a),cos(a),0}, {0,0,1}} ** {1,2,3}

/ 0.1585127 \

-> | 2.230442 |

\ 3 /

In addition, there are a larger number of other matrix functions, such as the calculation of eigenvalues with eigenvals() or the eigenvector system with eigenvects().