# Algebra of Zedfuncs

Within Envision, the term *zedfunc* is used to define a function $f: \mathbb{Z} \mapsto \mathbb{R}$. Zedfuncs are usually intended to represent the economic reward - or loss - associated to a numeric decision. For example, zedfuncs allow you to represent unit-dependent quantities such as the buy price determined by price breaks and the incremental reward function.

- The zedfunc datatype
- Plotting a zedfunc
- Generating zedfuncs
- Point-wise operations
- Transforming zedfuncs
- Evaluating zedfuncs
- Aggregating zedfuncs

## The zedfunc datatype

Zedfuncs are a native datatype of Envision. Similarly to ranvars, a zedfunc corresponds to a whole function rather than a single value. For example, below, we generate an affine function $f(x) = 2x+1$.

```
z = linear(2) + 1
y = valueAt(z, 3) // y = 7
```

The function `valueAt`

takes a zedfunc as the first argument `z`

and a number `x`

as the second argument. This function returns the value of the zedfunc function at `x`

. There are plenty of other ways of generating zedfuncs, which will be discussed in the following.

As zedfuncs are defined over $\mathbb{Z}$ - integers both positive and negative - a single zedfunc could hold, in theory, an arbitrarily large amount of information. However, computations over zedfuncs would become unbearably slow as the amount of data would increase. Thus, Envision has an internal upper bound on the amount of data that can be carried by a single zedfunc.

When an operation generates a zedfunc that exceeds its storage quota, the zedfunc is *compressed* (with loss) in order to fit under the storage quota. If $f^{*}$ is the compressed version of $f$, Envision attempts to minimize the loss function:

$$\mathtt{loss}(f, f^{* }) = \sum\limits_{k \in \mathbb{Z}} w(k) |f(k) - f^{* }(k)|\mathsf{.} $$

Where $w$ is a special weighting factor introduced to ensure the convergence of the sum. Intuitively, the lossy compression attempts to preserve the sharp edges of the original zedfunc.

Zedfuncs can be exported to Ionic files but not in flat text files. Due to the compression algorithms internally used by Envision, there is no “simple” representation of zedfuncs to be exposed in a plain text.

## Plotting a zedfunc

The graph of a zedfunc can be obtained using a `scalar`

tile:

```
x = (linear(1) - 1) * (linear(1) - 2) - 20
show scalar "F(x) = (x - 1) (x - 2) - 20" a1d6 tomato with x * uniform(-5, 10)
```

Here, we are defining `x`

as a second-degree polynomial expression. `linear(1)`

returns the identity function $f: x\mapsto x$. Thus, the expression `x`

, as defined can be interpreted as the polynomial $F: x \mapsto (x-1)(x-2)-20$.

Finally, as a zedfunc is defined over the segment $[-\infty, +\infty]$, the default display of a zedfunc tends to be unsatisfying, as the zedfunc appears typically highly zoomed-out. Thus, we multiply by `uniform()`

which zeroes out the zedfunc beyond the right and left boundaries passed as argument to `uniform()`

.

## Generating zedfuncs

The simplest forms of zedfuncs are the *parametric* ones; that is, zedfuncs that are generated based on a formula. As such we have:

`constant(a)`

: which returns a constant function $x \mapsto a$.`linear(a)`

: which returns a linear function $x \mapsto ax$.`uniform(a, b)`

: which returns 1 over the segment $[a,b]$ and zero elsewhere.`uniform.left(a)`

: which returns 1 over the segment $]-\infty, a]$ and zero elsewhere.`uniform.right(a)`

: which returns 1 over the segment $[a, +\infty[$ and zero elsewhere.

Beyond parametric zedfuncs, specific Envision functions allow you to generate parametric zedfuncs of the type identity and uniform. Zedfuncs are also the result of Envision functions such as stock reward and price breaks. In this case, the zedfunc is built based on the ranvar representing the demand forecast.

However, in practice, most of the zedfuncs are generated by *combining* existing zedfuncs through operators and transformations.

## Point-wise operations

Envision supports *point-wise* operations on zedfuncs. For example, let $f$ and $g$ represent two zedfuncs $\mathbb{Z} \mapsto \mathbb{R}$. Then, we can define the addition as $f+g: k \mapsto f(k) + g(k)$.
Within Envision, this is simply written as:

```
U = V + Z
```

It must be noted that in this example a vector zedfunc is created. Within Envision we are not typically processing a single zedfunc at a time, but a whole vector of zedfuncs at once, one for each item. However, the same operation can also be performed on scalar zedfuncs:

```
U = V + Z
```

Many basic operations on numbers have their native point-wise counterpart over zedfuncs:

```
U = V - Z // point-wise subtraction
U = V * Z // point-wise multiplication
U = max(V, Z) // point-wise max
U = min(V, Z) // point-wise min
```

Finally, when performing operations over zedfuncs, regular numbers are automatically converted as zedfuncs by simply broadcasting their value over $\mathbb{Z}$; i.e. $f_a : k \mapsto a$ for a $a$ a number. This feature facilitates blending numbers and zedfuncs in the same expressions.

```
a = 42 // scalar number
U = V + a
U = V - a
U = V * a
U = V / a
U = max(V, a)
```

## Transforming zedfuncs

A *transformation* is a function that takes a zedfunc as input and returns a new “transformed” version of the zedfunc. In particular, Envision supports the two following transformations that are handy when modeling economic rewards:

`int(z: zedfunc)`

: the integral $F$ of the function $f$ passed as argument, with $F(0) = 0$.`diff(z:zedfunc)`

: the derivative $f$ of the function $F$ passed as argument.`shift(z: zedfunc, a: number)`

: shift a zedfunc to the right, $f \gg a : k \mapsto f(k - a)$, where $a$ is an integer (a real number is approximated by Envision to its nearest integer). Naturally, if`a`

is negative, then the shift operators keep working, but the left shift becomes a right shift, and*vice versa*.

Indeed, the *integral* can be interpreted as the *cumulative* reward up to a certain target, while the *derivative* can be interpreted as the *marginal* reward at a certain target.

## Evaluating zedfuncs

As a rule of thumb, the goal is to maintain the zedfuncs *as zedfuncs* as long as possible. However, there are situations where the only practical option consists of converting the zedfunc back to numbers. Envision supports two functions to achieve this:

`valueAt(z: zedfunc, a: number)`

which evaluates a given zedfunc at a target value. If`a`

is fractional, a linear interpolated value is returned to extend the zedfunc from $\mathbb{Z}$ to $\mathbb{R}$.`sum(z: zedfunc: a: number, b: number)`

which returns the*sum*over the segment $[a,b]$ where $a$ and $b$ are expected to be integers.

Assuming that the zedfunc has an affinity with a ranvar, the zedfunc can be visualized in a table, through `extend.ranvar`

as illustrated by:

```
p = poisson(5)
table G = extend.ranvar(p)
r = stockrwd.m(p, 0.1)
G.R = int(r, G.Min, G.Max)
show table "My Grid" with Id, G.Min, G.Max, G.R
```

## Aggregating zedfuncs

The zedfuncs can be summed their regular number counterparts. The `+`

operator can be iteratively applied over all the zedfuncs of a group via the aggregator `sum()`

.

```
inputf1 = same(T.ExampleInput) if (T.Example == 1)
inputf2 = same(T.ExampleInput) if (T.Example == 2)
inputf3 = same(T.ExampleInput) if (T.Example == 3)
where T.Example == 1 or T.Example == 2 or T.Example == 3
exampleSum = sum(T.ExampleInput) /// Is equal to
exampleSumAlt = inputf1 + inputf2 + inputf3
```