# Transforming functions

A transforming function operates across a dimension of an array and returns a result that has the same dimensions as its input array.

The function Cumulate(x, i) illustrates some properties of transforming functions.

Example:

Cumulate(Car_prices, Years) →
Years ▶
Car_type ▼ 2005 2006 2007 2008 2009
VW 16K 33K 51K 70K 90K
Honda 18K 37K 57K 79K 103K
BMW 25K 51K 79K 109K 141K

The second parameter, «i», specifying the dimension over which to cumulate, is optional. But if the array, «x», has more than one dimension, Analytica might not cumulate over the dimension you expect. For this reason, it is safer always to specify the dimension index explicitly in any transforming function.

## Cumulate(x, i, passNull, reset)

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».

Cumulate(1, i) is equivalent to @i, where each numbers the elements of an index.

The optional «passNull» parameter controls now Null values in «x» are passed through to the result. If «passNull» is false or omitted, then null values in «x» are ignored and do not effect the cumulation. Leading Null values will be passed through, but after a numeric value is encountered, Null values in «x» will cumulate the same as zero.

The optional «reset» parameter, an array of boolean values along «i», can be used to indicate points along i where you want to restart the cumulation. For example, if you want to restart the cumulation following a state change, «reset» can be set to true each time a new state is entered.

Library: Array

Example:

Cumulate(Cost_of_ownership, Time) →
Years ▶
Car_type ▼ 0 1 2 3 4
VW 2810 5761 8859 12.11K 15.53K
Honda 3535 7382 11.28K 15.45K 19.81K
BMW 3185 6479 9888 13.42K 17.07K
Cumulate(Cost_of_ownership, Car_type, reset: Time = 2) →
Years ▶
Car_type ▼ 0 1 2 3 4
VW 2810 5761 3098 6351K 9767K
Honda 3535 7382 3897K 8063K 12.43K
BMW 3185 6479 3409 6938K 10.59K

See Array Function Example Variables for example array variables used here and below.

## Uncumulate(x, i, firstElement)

Uncumulate(x, i) returns an array whose first element (along «i») is the first element of «x», and each other element is the difference between the corresponding element of «x» and the previous element of «x». Uncumulate(x, i, firstElement) returns an array with the first element along «i» equal to «firstElement», and each other element equal to the difference between the corresponding element of «x» and the previous element of «x».

Uncumulate(x, i) is the inverse of Cumulate(x, i). Uncumulate(x, i, 0) is similar to a discrete differential operator.

Library: Array

Example:

Uncumulate(Cost_of_ownership, Time) →
Years ▶
Car_type ▼ 0 1 2 3 4
VW 2810 141 147 155 163
Honda 3535 312 50 269 199
BMW 3185 109 115 120 127
Uncumulate(Cost_of_ownership, Time,0) →
Years ▶
Car_type ▼ 0 1 2 3 4
VW 0 141 147 155 163
Honda 0 312 50 269 199
BMW 0 109 115 120 127

See Array Function Example Variables for example array variables used here and below.

## CumProduct(x, i, passNull, reset)

Returns an array with each element being the product of all of the elements of «x» along dimension «i» up to, and including, the corresponding element of «x».

For a description of the optional parameters, «passNull» and «reset», see function Cumulate(). See also CumProduct().

Library: Array

Example:

Cumproduct(Rate_of_inflation, Years) →
Years ▶
2005 2006 2007 2008 2009
1 1.01 1.03 1.061 1.104

## Reverse(x, i, posFirst, posLast)

(New to Analytica 5.0)

Reverses the items in the array «x» along index «i». You can optionally specify «posFirst» and «posLast» to reverse only a subsequence within the array, where the first element is position 1. The index «i» can be omitted only when «x» has an implicit dimension. See Reverse().

## Rank(x, i, type, keyIndex, descending, caseInsensitive, passNaNs, passNulls)

Rank(x,i) returns an array of the rank values of «x» across index «i». The lowest value in «x» has a rank value of 1, the next-lowest has a rank value of 2, and so on. «i» is optional if «x» is one-dimensional.

If «i» is omitted when «x» is more than one-dimensional, the innermost dimension is ranked. If two (or N) values are equal, they receive the same rank and the next higher value receives a rank 2 (or N) higher. You can use an optional parameter, «type», to control which rank is assigned to equal values. By default, the lowest rank is used, equivalent to Rank(x, i, type: -1). Alternatively, Rank(x , i, type: 0) uses the mid-rank and Rank(x, i, type: 1) uses the upper-rank. Rank(x, i, type: Null) assigns a unique rank to every element (the numbers 1 thru N) in which tied elements may have different ranks.

A multi-key rank can be processed by indexing each key with a new index, and specifying this index for the optional «keyIndex» parameter. In a multi-key rank, x[@keyIndex = 1] determines the rank order, except that ties are then resolved using x[@keyIndex = 2], any ties there are resolved using x[@KeyIndex = 3], and so on.

Rank(x, i, descending: true) assigns the largest value a rank 1, the second largest a rank 2, and so on. When «x» contains textual values, the optional boolean parameter «caseInsensitive: true» ignores upper-lower case differences during the comparisons. The parameters «descending» and «caseInsensitive» may also be indexed by they «keyIndex» when they vary by key.

By default, Rank assigns an arbitrary ranking to NaN or Null values. Alternatively, you can pass these through to the result as NaN or Null using Rank(x, i, passNaNs: true, passNulls: true).

Library: Array

Examples: Basic example:

Rank(Years) →
Years ▶
2005 2006 2007 2008 2009
1 2 3 4 5
Rank(Car_prices, Car_type) →
Years ▶
Car_type ▼ 2005 2006 2007 2008 2009
VW 1 1 1 1 1
Honda 2 2 2 2 2
BMW 3 3 3 3 3

Optional «type» parameter example:

Index RankType := [-1, 0, 1, Null]
Rank(NumRepairs, CarNum, type: RankType) →
CarNum ▶
Rank_type ▼ 1 2 3 4 5 6 7
-1 7 2 6 2 2 1 2 Lowest rank for duplicates, 2 (default)
0 7 3.5 6 3.5 3.5 1 3.5 Mid rank for duplicates, 3.5
1 7 5 6 5 5 1 5 Upper rank for duplicates, 5
Null 7 2 6 3 4 1 5 Unique rank for duplicates

Multi-key example:

Rank(NumMaintEvents, CarNum, keyIndex: MaintType) →
CarNum ▶
1 2 3 4 5 6 7
7 4 6 2 3 1 5

See Array Function Example Variables for example array variables used here and below.

## Sort(x, i, keyIndex, descending, caseInsensitive)

Sort(x,i) returns the elements of «x», reordered along index «i» in sorted order. The equivalent can be accomplished using the SortIndex function as:

x[i =SortIndex(x ,i)]

To perform a multi-key sort, in which the first key determines the sort order unless there are ties, in which the second key breaks the ties, the third key breaks any remaining ties, etc., collect the key criteria along an index «K» and specify the optional «keyIndex» parameter, e.g.:

Sort(Array(K, [key1, key2, key3]), i, keyIndex: K)

The data is sorted in ascending order (from smallest to largest), unless you specify the optional parameter descending: true, which then reorders from largest to smallest. The optional parameter caseInsensitive: true ignores lower/upper case in textual comparisons. Either of these may also be indexed by the «keyIndex» when the order or case-insensitivity varies by key.

Multi-key example:

Sort(NumMaintEvents, CarNum, KeyIndex: MaintType, descending: true) →
CarNum ▶
MaintType ▼ 1 2 3 4 5 6 7
Repair 10 9 4 4 4 4 1
Scheduled 0 0 5 2 2 1 0
Tires 0 0 0 2 1 0 0

## Integrate(y, x, i)

Returns the integral of the piecewise-linear curve denoted by the points («xi», «yi»), computed by applying the trapezoidal rule of integration to the arrays of points «x», «y» over index «i». Integrate() computes the cumulative integral across «i», returning a value with the same number of dimensions as «y». Compare Integrate() to Area() and Cumulate(). When «x» is itself an index, then «i» can be omitted and «y» is an array indexed by «x». Likewise, if «y» is an index, «i» can be omitted and «x» is indexed by «y».

Library: Array

Example:

Integrate(Cost_of_ownership, Time) →
Time ▶
Car_type ▼ 0 1 2 3 4
VW 0 2881 5905 9081 12.42K
Honda 0 3691 7563 11.59K 15.86K
BMW 0 3240 6591 10.06K 13.65K
Tip
There are subtle relationships among Area(), Integrate(), Sum() and Cumulate():

When Area() operates over the entire index it returns the last value of the Integrate() series. Both of these functions are based on trapezoidal integration, meaning that they integrate the averages of each adjacent pair over the boundaries of the index. Similarly, Sum() returns the last value of Cumulate(). But in this case the operation is a simple addition, not a trapezoidal integration.

## Normalize(y, x, i)

Returns a re-scaled version of array «y», such that the area under the piecewise-linear curve denoted by the points («xi», «yi») is re-scaled to be one. Normalize() is equivalent to

y/Area(y, x, , , i)

The arrays «x» and «y» must both contain numeric values, and should share «i» as a common index. When either «x» or «y» is itself the shared index, the parameter i can be omitted, but it is a good practice to include it anyway.

Tip
Normalize() does not force the values along index «i» to sum to 1, nor does it force the sum of squares to be 1. To do these operations divide «y» by Sum(y, i) or by Sqrt(Sum(y^2, i)). We recommend always including the third parameter, «i», when using Normalize(), even when the shared index is passed for «x», since this helps to avoid errors or confusion with these other senses of normalization.

Library: Array

Example:

Normalize(Cost_of_Ownership, Time, Time) →
Time ▶
Car_type ▼ 0 1 2 3 4
VW 0.2263 0.2377 0.2495 0.2627 0.2725
Honda 0.2229 0.2426 0.2457 0.2627 0.2752
BMW 0.2333 0.2413 0.2497 0.2585 0.2678

See Array Function Example Variables for example array variables used here and below.

## Dispatch(demand, capacity, resource, active, minimum, increment, method)

Allocates «capacity» from a set of resources to satisfy a «demand», consuming capacity from the first resource in the order they appear in the resource index. «capacity» is an array indexed by the resource index. The result is an array indexed by «resource» indicating how much of each resource’s «capacity» is dispatched to satisfy the total demand.

The optional «active» flag parameter, when specified, should be indexed by «resource» and set to true when the corresponding resource can be used to fill the demand, false if it cannot be applied to fill the demand.

Optional «minimum» and «increment» parameters, which may optionally be indexed by «resource», specify that the indicated resource must be dispatched in fixed increments, with at least «minimum» capacity dispatched, in integral increments of «increment». You can pass the same value to «capacity» and «increment» to indicate that each resource must be dispatched fully or not at all. A null or 0 value appearing in either minimum or increment indicates that no increment constraint applies to the corresponding resource. If either of these are specified, it might not be possible to match «demand» exactly, in which case the «method» parameter specifies how this should be handled, with the following possible values for «method»:

0: (default) Never exceed demand.
1: Meet or exceed demand, if possible.
2: Meet or exceed demand, if possible, maximizing the allocation of earlier resources.

Method 0 is appropriate when «demand» specifies a budget that cannot be exceeded. Methods 1 and 2 both give priority to resources in the order they appear in the «resource» index; however, Method 1 avoids excess allocation from earlier resources. For example, suppose resource 1 has a capacity of 8, resource 2 has a capacity of 20 with a minimum dispatch of 10, and demand is 12. Method 2 would return the allocation [8,10], allowing resource 1 to supply as much as possible, but requiring 10 from resource 2 to meet or exceed demand. Method 1 returns the allocation [2,10], which in this case exactly matches demand. Even though resource 1 has priority, allocating more than 2 from it doesn’t help.

Library: Array

Example: A set of projects have been pre-ordered from highest to lowest return on investment (ROI). Each project must receive at least half its funding or none at all. There is a budget of $600K to allocate. Full_Cost := Project ▶ 1 2 3 4 5 6 7 8$50K $25K$100K $75K$250K $330K$95K $300K Dispatch($600K, Full_cost, Project, Minimum: Full_cost/2, method: 0) →
Project ▶
1 2 3 4 5 6 7 8
$50K$25K $100K$75K $250K$0 \$95K 0