# Basic functions

There is a large number of functions stored in SA Engine's in-memory
*object-oriented database*. For example, the following function call
returns the version of SA Engine you are running.

`system_version()`

Run the function by clicking the play
button *play_circle*

Documentation of functions and other SA Engine artifacts are stored in
the database as well. You can **query** the database about the
documentation of a function named `myfunction`

by evaluating
`doc("myfunction")`

. The `doc()`

function returns the documentation of
the function as a string.

*Example:*

`doc("sin")`

You can edit the examples in the tutorial. Try changing `sqrt`

to `sin`

!

You can enter several OSQL statements by separating
them with a `;`

.

*Examples:*

`doc("heartbeat");`

doc("euclid")

If you don't know exactly the name of a function you can also pass a
*string pattern* to `doc()`

to return all functions matching the
string pattern in their names. In a string pattern a `*`

matches any
sequence of characters while a `?`

matches a single character.

*Example:*

`doc("atan*");`

The function `sourcecode("fn")`

where `fn`

can be a function name or
a string pattern returns the definitions of the matching functions.

*Example:*

`sourcecode("tan");`

sourcecode("atan*")

The *signature* of a function is a string denoting its arguments and
results.
You can get the signature of function or string pattern `fn`

by calling
the system function `signature(fn)`

, for example:

`signature('tan')`

Functions may have different definitions depending on the types of
their arguments. Such functions are said to be *overloaded* on their
types. Overloaded function have several signatures, for example:

`signature('range')`

Some functions have corresponding *infix operators*. For example, the
function `plus`

has the infix operator `+`

, so both these calls return
the same result:

`1+2;`

plus(1,2)

You can call `signature(op)`

to get the functions corresponding to
the infix operator `op`

, for example:

`signature('/');`

signature('.*')

Visit Documentation functions for a list of functions used for documenting the system.

## Math functionsâ€‹

There is a large library of basic mathematical functions built into the system and the usual arithmetic operators are available.

*Example:*

`sin(3.14/2)*cos(3.14)`

To learn more about basic math functions go to Math in the OSQL reference documentation.

## Session variablesâ€‹

During sessions with SA Engine it is often practical to temporarily
save values of expressions in **session variables** prefixed with `:`

by using the `set`

statement, e.g.:

`set :pi = asin(1)*2;`

sin(:pi/2)*cos(:pi)

The session variable `:pi`

is first assigned the value of `asin(1)*2`

.

Session variables disappear when you exit
SA Engine. To permanently save values in the built-in database you
must use **stored functions**, as explained next.

## Stored functionsâ€‹

Analysis *models* are defined in terms of a number of OSQL
functions. OSQL functions are created and stored in the database by
evaluating a `create function`

statement. There are functions of
different kinds, depending on how they are used.

**Stored functions** are functions that hold tabulated
function values permanently in the built-in database. They are created
by a `create function ... as stored`

statement.

*Example:*

`create function const(Charstring c) -> Real`

as stored

The above statement creates a tabulated function called `const`

taking
a string `c`

as argument and returning a real number as
result.

You are recommended to document your functions by a *master comment*
preceding the `as`

.

*Example:*

`create function const(Charstring c) -> Real`

/* The value of the math constant named `c` */

as stored;

doc("const")

Stored functions can be *populated* using the `set`

statement.

*Example:*

`set const("pi") = 3.14;`

set const("e") = 2.71;

const("pi");

ln(const("e"));

sin(const("pi")/2)*cos(const("pi"));

You can also *update* stored functions using `set`

, for example:

`set const("pi") = asin(1)*2;`

set const("e") = exp(1);

ln(const("e"));

sin(const("pi")/2)*cos(const("pi"))

Functions may have no arguments at all.

*Example:*

`create function mypi() -> Real`

/* The constant PI */

as stored;

set mypi() = asin(1)*2;

mypi()

## Derived functionsâ€‹

A **derived function** is a function defined by an OSQL expression.

*Example:*
The following function converts Celsius degrees to
Fahrenheit:

`create function ctof(Real c) -> Real`

/* Convert a Celsius degree `c` to Fahrenheit */

as c * 9 / 5 + 32;

ctof(10)

The head of the function, e.g `ctof(Real c) -> Real`

, specifies
the function's signature.

## Temporal functionsâ€‹

The function `local_time()`

returns the current wall time as an ISO
time stamp.

While `local_time`

returns the current wall time as a string, the
function `now()`

returns the wall time as an object of type `Timeval`

,
which is the internal representation of time points.

*Examples:*

`local_time();`

now()

The function `ts(Object o)->Timeval`

returns a **time stamped object**,
which represents a timestamped value `o`

.

*Examples:*

`ts(1);`

value(ts(1));

local_time(ts(1))

For more about functions over time visit Time in the reference documentation.

## Vectorsâ€‹

So far the function calls were made over single values and sets of
single values. Building mathematical models, e.g. to identify
interesting properties of streams, also require **vectors** with the
usual `[...]`

notation.

*Example:*

`[1,4,3,2]+[1,5,6,7]`

Change visualization of the vector to `Bar plot`

by adding `//plot: Bar plot`

before the query.

The mathematical operators `+,-,*,/,^`

can be used for whole vectors
or mixes of vectors and scalar values.

*Example:*

`[1,4,3,2]-[0,2,3,4]+1`

How would it look as text?

A `.`

in front of an operator indicates element-wise application of it
on each element of the vectors. For example, for multiplication the
`*`

operator over vectors returns the scalar product while `.*`

returns element-wise multiplication.

*Examples:*

`[1, 2, 3, 4] * [5, 6, 7, 8];`

[1, 2, 3, 4] .* [5, 6, 7, 8]

*More examples:*

`"Addition";`

[1, 2, 3, 4] + [5, 6, 7, 8];

"Scalar times vector";

5 * [1, 2, 3, 4];

"Element-wise power of two";

[1, 2, 3, 4] .^ 2

There are many built-in **vector functions**, e.g.:

`"sum";`

sum([1, 2, 3, 4]);

"mean";

mean([1, 2, 3, 4]);

"standard deviation";

stdev([1, 2, 3, 4]);

"median";

median([1, 4, 2, 3]);

"max";

max([1, 4, 2, 3]);

"dimension";

dim([1, 3, 2])

Often vectors are used in derived function definitions. For example,
the following function computes the Euclidean distance between vector
`v`

and `w`

:

`create function dist(Vector v, Vector w) -> Real`

/* Compute the Euclidean distance between `v` and `w` */

as sqrt(sum((v - w) .^ 2));

dist([1,2],[3,4])

The built-in function `euclid(v,w)`

does the same.

The general Minkowski distance computation function `minkowski(v,w,r)`

is
also built-in. This example shows Manhattan distance ($L_1$), Euclidean
($L_2$) and Chebyshev ($L_{infty}$) distance expressed in terms of
`minkowski(v,w,r)`

.

*Examples:*

`minkowski([1,2],[3,4], 1);`

minkowski([1,2],[3,4], 2);

minkowski([1,2],[3,4], +inf);

## Arraysâ€‹

An **array** or a **tensor** is a multi-dimensional cube of
numbers. It is represented by type `Array`

. Arrays can be created
with the function `array(Vector data)->Array`

, where the (nested)
vector `data`

contains its elements.

For example:

`array([1,2,3]);`

array([[1,2],[3,4]])

As for vectors, you can apply a number of arithmtic oparators and functions on arrays, for examle:

`array([[1,2],[3,4]]) + array([[2,3],[6,7]]);`

array([[1,2],[3,4]]) .* array([[2,3],[6,7]])

The elements of an array have a **format**, which specifies their
binary representations in memory. For example, elements of type
`Integer`

are represented as 64-bits integers having the format `I64`

and type `Real`

has the format `F64`

. The first argument of the
function `array(Charstring fmt,Vector data)->Array`

specifies the
elements' format.

For example:

`array("f64",[1,2,3,4])`

When called with one argument, `array(Vector data)->Array`

will return
an array having the format of the most general type in `data`

, where
real numbers are considered more general than integers,

For example:

`array([1,2,3,4]);`

array([1.0,2,3,4])

An array also has a **shape** being the number of elements in each of
its dimensions, computed by the function ```
shape(Array a)->Vector of
Integer
```

.

For example:

`shape(array([[1,2,3],[4,5,6]]))`

The function `dot(Array u, Array v)->Number`

computes the scalar
product of the elements in the arrays `u`

and `v`

.

For example:

`dot(array([1,2,3]),array([4,5,6]));`

The function `matmul(Array a, Array b)->Array`

computes the array
multiplication of `a`

and `b`

.

For example:

`matmul(array([[1,2,3]]),array([[1,2],[3,4],[5,6]]));`

Visit Arrays and tensors for a detailed description of arrays.

## The Fast Fourier Transformâ€‹

The function `rfft(a)`

computes the real number Fast Fourier
Transform
(FFT) over a one-dimensional array of real numbers.

*Example:*

`rfft(array([1.0, 2, 3, 4]))`

You can also apply `rfft()`

on vectors of numbers, even though this is
much slower. For example:

`rfft([1.0, 2, 3, 4])`

The inverse real FFT is computed with `irfft(a)`

.

*Example:*

`irfft(rfft(array([1.0, 2, 3, 4])));`

The later tutorial section Querying the microphone shows how user-defined functions over vectors and FFT can be used for filtering audio streams in real-time.

## Vectors of objectsâ€‹

So far the vectors contained only numbers, as required by math functions and operators. Unlike arrays, vectors can contain any kind of objects including strings and numbers. For example, the following vector contains both a number and a string:

*Example:*

`["Tore", 1234]`

In general vectors of objects are used for representing ordered finite
sequences of objects. By contrast, a **stream** can be seen as a
possibly infinite growing sequence of objects. Vectors can be used to
group elements in streams, as will be explained later.

Go to Vectors in the reference documentation for documentation of vectors.

## Sets and bagsâ€‹

Functions can also produce sets of objects where the order is not
guaranteed as with vectors. For example, the function `range(n)`

returns the set of numbers from 1 up to `n`

.

*Example:*

`range(10)`

Here `range(10)`

produces the set of all integers from 1 to 10.

*Example:*

`sin(range(200)*0.2)`

The function call `range(200)`

returns a bag of numbers. Here the sine
function is applied one each element in the set of all integers from 1
to 200.

Applying other functions, such as `sin(x)`

on a set means that the
function is applied on **each element** of the set.

Try visualizing the result as a line plot by inserting the row `//plot: Line plot`

before the query!

In general sets in OSQL may contain duplicates.

*Example:*

`floor(range(200)/2)`

The term **bag** is used rather than **set** to indicate sets with
possible duplicates.

Apply `sin(x)`

on the result of `floor`

!

Explicit bags can be create as using the $bag(e_1,e_2,...,e_n)$ notation, for example:

`set :mybag = bag(1,2,2,3);`

select i from Integer i where i in :mybag

As for vectors, **aggregate functions** over bags are applied on
entire bags, rather than on each element of the bag as, for example
`range(n)`

returns a bag of number and `sum(Bag of Number)->Number`

sums the elements of a bag of number.

*Example:*

`sum(range(200)/2)`

See Aggregate functions in the reference documentation for more on aggregate functions.

## Boolean and null valuesâ€‹

The constant `null`

is used to represent unknown or missing
values. For example, the last element of the vector `[1,2,null]`

is
unknown.

A Boolean value `null`

value is regarded as false. Thus, the query
`2<1`

returns `null`

, while `2>1`

return `true`

. The only object of
type Boolean is `true`

. The constant `false`

is `null`

casted as a
Boolean.

`null`

values in bags are regarded as missing values that are ignored
by aggregate functions.

Passing `null`

as argument in a function call will return `null`

without calling the function. For example:

`sin(sqrt(-1));`

An OSQL query variable bound to the value `null`

is regarded as
unbound and therefore `null`

cannot be regraded as a regular
value. Instead, to test that an expression `x`

is `null`

, use the
`notany(x)`

function that returns `true`

if `x`

is `null`

.

Often it is practical to use a default value instead of null. For this
the $coalsece(x_1,x_2,...,dlft)$ expression can be used that returns
the first $x_i$ not being `null`

and `dlft`

if all

For example:

`coalesce(sqrt(-1),ln(-1),1)+1`

Tests in `case`

statements succeed unless they return `null`

. For
example, the following query returns one:

`case when sqrt(-1) then 1 else 0 end`

To replace all `null`

s in a vector use
`whennull(Vector v, Object dflt)->Vector`

.

For example:

`whennull([1,2,null,3],0)+2`

The next part of the tutorial will show how to
make general **queries** that selects collections of objects from the
database.