# Cumulate

## Cumulate(X, I)

Returns an array with each element being the sum of all of the elements of «X» along dimension «I» up to, and including, the corresponding element of «X». It is the inverse of Uncumulate.

Cumulate(X: Array[I]; I: Index, passNull: optional Boolean, reset: optional Array)

Array Functions

## Examples

`I := [1, 2, 3, 4, 5, 6]`
`X := Array(I, [8, 2, 0, 5, -3, 7])`
`Cumulate(X, I) → Array( I, [8, 10, 10, 15, 12, 19])`

### Flattened ragged array example

One use for Cumulate arises when using a flattened representation of highly non-rectangular (i.e., ragged) 2-D data. The first dimension is `J`, but the number of items along the second dimensions varies with `J`. So the flattened representation concatenates all the array elements into to 1-D array indexed by `K`, and then performs its computations using the 1-D array. You start with a vector on `J` that tells you how many elements there are for each `J`, e.g.,

` Index J := [1,2,3,4,5]`
` Variable sizes := Array( J, [12, 2356, 3, 19342, 234 ] )`
` Index K := 1..Sum(sizes, J)`

To use this flattened representation, you need to know where along `K` the elements for a given `J` start and where they end. Cumulate gives you the last position along `K` directly:

`Variable LastPos := Cumulate( sizes, J ) → Array(J, [ 12, 2368, 2371, 21713, 21947 ] )`

The starting position along `K` is obtained as

`Variable FirstPos := Cumulate( sizes[@J=@J-1,defval:1], J ) → Array(J, [ 1, 13, 2369, 2372, 21714 ] )`

## Optional Parameters

### PassNull

«PassNull» is an optional boolean parameter that defaults to `False`. When it is omitted or explicitly set to `False`, Cumulate ignores Null values. In that case they have essentially the same effect as a zero, unless they happen to be the first value in «X», in which case they are passed since no numeric values are yet obtained.

When «passNull» is set to `True`, then Null values are passed through as Null in the result.

For example:

`X := [«null», «null», 4, 1, «null», «null», 1, 9, 3, 2, «null»]`
`Cumulate(X, I) →`
`Cumulate(X, I, passNull: false) → `
` [«null», «null», 4, 5, 5, 5, 6, 15, 18, 20, 20]`
`Cumulate(X, I, passNull: true) → `
`[«null», «null», 4, 5, «null», «null», 6, 15, 18, 20, «null»]`

### Reset

The optional «reset» parameter accepts an array of boolean values indexed by «I». At the positions where «reset» is true, Cumulate starts over: It sets the sum of previous values to zero, so that the result at that position is the same as the value in «X».

For example:

`I := [1, 2, 3, 4, 5, 6, 7]`
`X := [8, 2, 0, 5, -3, 7, 5]`
`R := [0, 0, 1, 0, 0, 1, 0]`
`Cumulate(X, I, reset: R) →`
` [8, 10, 0, 5, 2, 7, 12]`

Suppose `State` contains a number or text value designating the state of a system over `I`. You can calculate how long the system has been in each state using Cumulate with «Reset» set to `True` whenever the state changes compare to its previous value:

`Cumulate(1, I, Reset: State[@I = @I - 1] <> State)`

## Cumulate in Dynamic Functions

If objects `X` and `Y` are in the same dynamic loop, the definition of `Y` may not operate over the Time index on the value of `X`. When you write such an expression, you presumably intend to operate over the entire Time-indexed array for `X`, which would implicitly refer to future points in time that have not yet been computed. In a dynamic loop, it assumes `X` in `Y`'s definition refers to the value of `X` at the current time point, as it iterates over Time, so that an expression such as `Cumulate(X, Time)` would actually cumulate a constant value over time. While not disallowed, that is probably not what you intended, and it gives a warning. You can usually express operations over Time directly using Dynamic, for example, instead of `Cumulate(X, Time)` you would use:

`Dynamic(X, Self[Time - 1] + X)`