Function parameter qualifiers

Revision as of 16:12, 17 March 2008 by Lchrisman (talk | contribs) (→‎Prob)

What's new in Analytica 4.0? >

Analytica 4.0 introduces several new parameter qualifiers. For simplicity, we decided to recommend a single preferred term for each qualifier, and discourage use of its synonyms. See the now deprecated synonyms at the end of this page.

Parameter qualifiers

Formal parameters are the names of function parameters used in the Parameters attribute in the declaration of a user-defined function. Qualifiers may be listed after formal parameters to specify what kind of parameter is expected. Qualifiers control whether and how a parameter should be evaluated, what type -- such as number or text, whether it should be an array, and if so, what index(es) it should have, whether it is optional or can be repeated, and various other properties. We also use parameter qualifiers when defining the syntax of built-in functions in the Syntax segment, to specify what the function expects and what it may do with its parameters.

Evaluation Mode Qualifiers

Index

Requires the identifier of an Index, local or global. It also works with the identifier of a variable that is not of Class Index, but which has a Domain Attribute that is an Index, Discrete, or defined as a List. The function does not evaluate the Index when it is called, and can use the parameter as an index in internal expressions, for example:

Function NormalizeWeights(x; i: Index)
Definition: x / Sum(x, i)
Notable Combinations:
I : Index
I : optional Index
I : ... Index
I : ... optional Index
I : Index = J
I : Index = Run

When used with the ellipsis notation, a list of indexes may be specified.

A function may use a parameter declared as an index in the array declaration of other parameters, to specify what dimensions it should have -- see "Array" qualifier below.

Arbitrary expressions cannot appear in the argument to an index parameter -- the argument must be an index identifier such as Fu1(J). In this case, J must identify a valid index; however, J does not need to be an index object, since other variable node types can also serve as valid indexes, as long as they either have a domain, self-index, or evaluate to a list. The A.I syntax may also be used to indicate the index of a particular array, such as Fu1(A.I), in which case I might be a local index (i.e., not found in the global namespace). Finally, a local variable identifier may be passed when that local variable is an alias for a valid index. For a local variable to be a valid alias for an index, it must either be declared as an Index or Variable parameter, be defined using an Index..Do declaration, or have a varTerm assigned to it. The latter case is unusual, but is demonstrated by the following:

var v := GetVariableByName("In1") do Fu1(v)

which is equivalent to

Fu1(In1)

You cannot specify a general expression where an Index is required, so you could not compose the above to: Fu1(GetVariableByName("In1"))

Within the definition of the user-defined function, the local variable, I, can appear in both value and index contexts. For example, in the expression Sum(I,I), the first argument to Sum is a value context, and the second is an index context. When I appears in a value context, I evaluates to a 1-D array of index values, which is indexed by the original index. This distinction is noteworthy when a self-indexed array is passed as the index parameter. This can be contrasted to the VariableType qualifier (described below). A VariableType parameter can also serve as an index in an index context, but in a value context, a variableType parameter evaluates to its context value, rather than its index value. Note: Prior to Analytica 4.0, index parameters in a value context acted like VariableType parameters.

Mid

Forces the parameter to be evaluated in Mid (deterministic) mode, irrespective of the context evaluation mode.

Prob

Forces the parameter to be evaluated in Prob (probabilistic) mode, independent of the context evaluation mode.

If your user-defined function applies statistical functions to a parameter, that parameter usually should be declared as Prob or Sample, otherwise your function may yield non-intuitive results. To illustrate, consider the following UDF that uses the statistical function Mean, shown two ways, with and without the Prob qualifier.

Function MeanMax1(X : Prob ; J : Index ) := Mean(Max(X,J))
Function MeanMax2( X : Array ; J : Index ) := Mean(Max(X,J))

Consider the results of applying these function in the following example:

Index Case := 1..3
Chance Damage := Table(Case)( LogNormal(10,2), LogNormal(7,3), LogNormal(12,1.2) )
Variable E_worst1 := Meanmax1(Damage,Case)
Variable E_worst2 := MeanMax2( Damage,Case)

The variables E_worst and E_worst2 may be evaluated in either Mid or Sample mode. Let's compare:

Expression Evaluation Context
Mid Sample
Mean(Max(Damage,Case)) 20.53 20.53
MeanMax1(Damage,Case) 20.53 20.53
MeanMax2(Damage,Case) 12 20.53

From this table you can see that without the Prob qualifier, the result of MeanMax2 in mid mode is not the same as Mean(Max(Damage,Case). The potentially counter-intuitive result for Mid(MeanMax2(Damage,Case)) occurs because the first parameter value is obtained by evaluating Damage in mid mode, yielding the one-dimensional array [10,7,12] indexed by Case, rather than an array with the full distribution samples.

Sample

Like Prob, it forces the parameter to be evaluated in Prob mode, irrespective of the context mode. The only difference is that it gives an error message if the resulting value is not uncertain -- i.e. it does not contain the Run index.

Context

Evaluates the parameter in Mid or Prob mode, according to the evaluation mode used to evaluate the function being called. Context is the default evaluation mode, if no qualifier (Mid, Prob, or Sample) is specified, so there is strictly no reason to use it.

Unevaluated

Accepts any expression and does not evaluate it. It leaves it up to the function to evaluate it if needed. It is rarely used within user-defined functions, but is used in various built-in functions, for example:

 Whatif(e: Unevaluated; v: Variable; x)

ContextSample

Causes the qualified parameter to be evaluated in Prob mode if any of the other parameters to the function are Run. If not, it evaluates in Context mode -- i.e. Prob or Mid following the context in which the function is called.

This qualifier is used for the main parameter of most built-in statistical functions. For example, Mean has these parameters:

  Mean(x: ContextSample[i]; i: Index = Run)

Thus, Mean(X, Run) evaluates X in Prob mode. So does Mean(X), because the index i defaults to Run. But, Mean(X, J) evaluates X in Mid mode, because J is not Run.

When the parameter declaration contains more than one dimension, Prob mode is used if any of the indexes is Run.

Variable

Typical usage:
Fu1( Z : Variable )

[MH: Should we call this ObjectType, since it can refer to any class of Analytica object, not just a Variable? Or would it be better to offer a several such qualifiers, to specify what Class of Object is acceptable? E.g. ModuleType (any module type, including Model, Module, Library), VariableType (any Variable type, including Index, Constant, Chance, Decision, and Variable), or ObjectType, that allows an Object of any class. Alternatively, we could add ObjectType <Class>, where <class> can be any Analytica class. Should or could you be able to pass an Attribute, or User-defined Function, or System Function to an ObjectType parameter?]

[MH: Please review changes below]

The argument to a variableType parameter must be one of the following:

  • An identifier of an object in the global namespace.
  • A local variable identifier that is an alias for an object.
  • An X.I expression, where X holds an array and I is the identifier of an index of that array.

A local variable is an alias of an object when:

  • It was declared as a Variable or Index parameter.
  • It was declared with a Using..Do statement.
  • A varTerm was assigned to it, such as: var X := GetVariableByName("Va1");

You cannot specify a literal string, or a general expression, to a Variable parameter, even if that expression returns a varTerm (such as a call to GetVariableByName). This is because the parameter is not actually evaluated, as an expression would normally be. For example, in Fu2(X), X is the identifier of an object, it is not an expression that evaluates to an object. If the expression were evaluated, then X would have to hold a varTerm. If you need to use an expression that evaluates to a varTerm, then you would define a local variable to contain the result of that expression and specify the local variable identifier when you call the function.

Within the Definition of the function, the parameter name X serves as an alias for the original object, and can be passed to other functions that expect objects (i.e., VariableType parameters), such as WhatIf(y, X, x0), or <attrib> Of X, or X Of o if X is the name of an Attribute. A Function called from a Script (not called from a Variable) can assign to the parameter, X := <expr>, hence assigning a new definition to the variable X refers to. In other contexts, if X is in an expression or a parameter to another function that evaluates its parameters, Analytica evaluates X to return its value.

If the object passed in as the parameter is a valid index, then X can be used within the function in an index context, e.g., Sum(expr,X). The IndexType and VariableType qualifiers differ in their behavior when the local variable is used in a value-context and a self-indexed table is passed in. In a value context, a VariableType parameter will evaluate to the value, while an IndexType parameter evaluates to its index value.

The VariableType qualifier is similar to pass-by-reference in other computer languages. When called from a script (with no caching variables involved), the underlying variable's Value, ProbValue, or other attributes, can be assigned to. (However, because of a prohibition on side-effects with dependency maintenance, you can't assign to the object when a function is called from a variable evaluation).

If the VariableType qualifier is followed by a Datatype qualifier, such as:

 Fu3( X: VariableType Number)

Analytica will evaluate X when calling Fu3 to check that its value has the specified Datatype. But, in the Definition of Fu3, it will treat X as an unevaluated VariableType, as just above. The Coerce qualifier has no effect on a VariableType parameter.

LVarType

This qualifier is for internal use by built-in functions. It is a variation on the VariableType qualifier.

Object

Typical declaration:

Fu1( obj : Object )

Typical function usage:

Fu1( MyIdentifier )

The Object qualifier indicates that an object identifier will be provided. As with the Variable qualifier, the object identified is not evaluated, and unlike the Variable qualifier, does not need to be an object that can be evaluated. For example, a module name can be provided as a parameter declared as Object, while a module identifier would not be accepted by a parameter declared as Variable.

A very closely related qualifier is Handle. The distinction is that Handle is a data type qualifier, while Object is an evaluation mode qualifier. If you have an expression that returns a handle when evaluated, and you want to pass the resulting handle to a function, then you would use the Handle qualifier. You would use the Object qualifier only if you want your function to accept an identifier directly without having to surround it within a call to the Handle function. Compare:

Fu1( obj : Object )           ---   call using:  Fu1( X )
Fu2( obj : Handle )           ---   call using:  Fu2( Handle(X) )

VarList

Related: List of Index

Specifies that a function expects a list of variables -- i.e., a list of pointers to Analytica objects. An example of such a function is the built-in WhatIfAll function.

If you are really interested in passing variable number of variable objects into a function, the preferable declaration is to use the ellipsis qualifier:

( Vs : ... VariableType )

In this case, each argument is not evaluated, and the reference to that object is passed. Inside the function, Vs contains a list of VarTerms.

When the VarList parameter is used, as with the declarations:

(vs: VarList )
(vs: VarList[ ] )
(vs: VarList[I] )
(vs: List[I] of Variable )

or with the related declaration:

(vs: List[] of IndexType )
etc.

Then the argument IS evaluated. The elements of the evaluated result must then be VarTerms. If not, an error results. In normal Analytica usage, it is pretty unusual for a result to evaluate to VarTerms. If you use an identifier within an expression, it will evaluate to the underlying value, so it doesn't work to pass a list of identifiers. For example:

Function Fu1( Vs : VarList )
Function Fu2( Vs : ... VariableType )
Fu1( [ Va1, Va2, Va3 ])    -- no good
Fu1( GetVariableByName(["Va1","Va2"]) ) -- Good
Fu2( [ Va1, Va2, Va3 ])    -- good
Fu2( Va1, Va2, Va3 )       -- good, equiv to previous
Fu2( GetVariableByName(["Va1","Va2"]) ) -- no good

Dimensionality Qualifiers

Dimensionality qualifiers declare the dimensions of each parameter that are expected by the function within the function definition. These allow Analytica to apply Horizontal Array Abstraction, iterating over extra indexes until only the allowed dimensionality is reached, evaluating the function repeatedly for each slice, and reassembling the results. When multiple parameters have dimensionality qualifiers that require each to be iterated, Analytica's function invocation coordinates the iteration so that indexes impacting multiple parameters are iterated together.

Array

Typical Usage:
( X : Array[Time,I,J] ; I : IndexType ; J : optional IndexType )

The Array qualifier is also referred to as a dimensionality declaration, since it is used to declare the expected dimensionality of a parameter. The keyword "Array" is optional -- a list of indexes inside square brackets implies the Array qualifier (unless the vector or list qualifiers are used, both of which are slight variations on the Array qualifier semantics).

The Array qualifier specifies that the parameter is a multi-dimensional array (of zero or more dimensions), and is most importantly used to declare what those dimensions are. Inside the body of the function, parameter variable is guaranteed to contain no dimensions other than those declared. Analytica iterates over the function, calling it repeatedly on successive slices when an argument contains extra dimensions, so that this guarantee is satisifed within the function body -- this is the basis for Array Abstraction.

Suppose A is indexed by Time, In1, In2, and In3 and that a function having the above Typical Usage declaration is called as F(A,In1). Analytica will iterate over all combinations of In2 and In3, slicing A at each combination and calling F, such that inside the function body, parameter X is indexed only by Time and In1 (and parameter I is an alias for In1 inside the function body).

The Array keyword is optional, the brackets alone have the effect of declaring the dimensionality. Thus, the following are the same:

(X : Numeric Array[Time] )
(X : Numeric[Time] )

An array declaration does not add in dimensions, so for example, if in the earlier example, if the function were called using: F(5,In1), inside the function body X will be the scalar 5 -- the dimensions Time and In1 are not automatically added to the parameter. However, since for all array-abstractable function, 5 is equivalent to an array containing 5 for every element, computations will usually remain equivalent (and sometimes more efficient) even if the argument does not contain the dimension. The All keyword (described elsewhere on this page), used in conjunction with a dimensionality declaration.

When creating user-defined functions using procedural programming constructs, it is highly recommended that you explicitly declare dimensionality of each parameter using the array qualifier. Constructs such as While loops or local index sequences are then more likely to continue working if dimensions are added to your model later.

Atom

Typical Usage:
( X : Atom )

Specifies that the parameter is atomic -- a single element. If an array is passed to this parameter, Analytica will iterate over its dimensions so that at each call the parameter value is guaranteed to consist of a single element, typically a number, text string, a reference, or the value Null.

In esoteric cases, some internal data types can also be passed, which could theoretically include an parsed expression structure, a varset, a data blob (such as an image), a LP, QP or NLP problem-specification object.

Because an atom is considered to be a zero-dimensional array, the atomic qualifier is functionally equivalent to the Array qualifier with zero indexes, i.e.:

( X : Array[ ] )

Scalar

Typical usage:
( X : Scalar )

The scalar qualifier is an alias for "Number Atom".

Vector

Typical Usage:
( X : Vector[I] ; I : Optional IndexType )

The vector qualifier specifies that the argument passed must contain at least one dimension, even if that dimension is not explicitly specified. When there is an explicit index provided, the behavior is the same as the Array qualifier. The distinguishing behavior occurs when no index is specified, such as when an optional index is omitted in the typical preceding typical usage. In such a case, array abstraction is applied to a vector parameter until a single dimension remains, while in the case of Array it would be applied until the parameter is scalar. When the parameter contains multiple dimensions, the default single remaining dimension will be the canonically first dimension. If no index can be identified, an error results.

Examples:

Fu1 ( X : Vector[I,J] ; I,J : optional IndexType ) 
Fu2 ( X : Array [I,J] ; I,J : optional IndexType )
Fu3 ( X : Vector )
Variable A := (indexed by In1 and In2)
Dimensionality of X within function body:
   Fu1(A)  ==> X is dimensioned by In1.  Iterates over In2.
   Fu2(A)  ==> X is atomic. Iterates over In1 and In2.
   Fu1(A,In2) => X is dimensioned by In2.  Iterates over In1.
   Fu1(A,In1,In2) => X is dimensioned by In1 and In2.
   Fu3(A)  ==> X is dimensioned by In1.  Iterates over In2.
   Fu1([A,A^2])  ==> X is a null-indexed list of atoms.  Iterates over In1 and In2.
   Fu2([A,A^2])  ==> X is atomic.  Iterates over null-list, In1 and In2.

Download example model

Note that the example illustrate the difference between Vector and Array qualifiers.

Many built-in Analytica functions that operate on 1-D parameters act as if they are declared in this fashion (internally not all built-in functions use the newer parameter scheme documented here). These include Sum, Min, Max, Product, Cumulate, Uncumulate, CumProduct, etc.

List

Typical Usages:
( L : List[ ] )
( L : List All [ ] )
( L : List[ I ] ; I : IndexType )

The List parameter qualifier is a variation of the Array qualifier that is used when a null-indexed dimension is expected, and the function does not want array abstraction it iterate over and remove that dimension before evaluating the function.

The array qualifier has no syntactic variation that allows you to the Null-dimension within the list of dimensions. The so-called Null-dimension does not really correspond to an actual Analytica object, but rather is a term that refers to a list. But, essentially, a declaration "List[I,J]" would be the conceptual equivalent of "Array[NullDim,I,J]". It declares that the parameter may be indexed by the null-dimension, I, and J. Without the All qualifier, none of these dimensions are required, but they are the only ones allowed.

As is the case with the Array qualifier, a List declaration with no brackets is allowed but not particularly useful, since it doesn't restrict the dimensionality of the parameter.

The declaration ( L : List[ ] ) specifies that only the null-dimension is allowed. If the argument is not a list, then L will be atomic at each function invocation. If the argument has a null-dimension, then all other dimensions are iterated, with only the null-dimension passed to the function.

When the All qualifier is included, as in ( L : List All[I] ) or (L : List All[ ] ), then both the specified index(es) and the null-index are required. When a null-index is added, Analytica has no reference index object to determine its length, so a null-list of length one is added.

When the list qualifier is used in conjunction with the VariableType or IndexType qualifiers, a somewhat different treatment results. For these cases, see the VarList qualifier. "Variable List" or "List of Variable" is synonymous with "VarList".

All

Typical Usage:
( A : Array All[I,J] )

The All qualifier is used with Array, Vector, or List to specify that the function requires all listed indexes to be present. Without All, it allows, but does not require that the parameter has these dimensions. With All , the function body is guaranteed that the parameter has all and exactly the listed dimensions.

If an argument to an array parameter has extra indexes not listed, they are iterated, whether or not the All qualifier is present. If any named index(es) is (are) not an index of the actual parameter, it adds the index(es) as a dimension, repeating the value of the parameter across the added dimension(s). Internally, it represents them as sparse dimensions, so that there is little memory or time penalty involved in passing the extra dimensions; however, if the function operates over that dimension, intermediate or final results may require more memory, because for example, intermediate values may no longer be constant over those dimensions.

Reduced

Typical Usage:
( A,B : Array[I] ; C:Array[J] ; D : Reduced )

When a parameter is declared with the Reduced keyword, it is sliced along any dimensions that are iterated as a result of dimensionality declarations on other parameters. For example, with the preceding declaration, suppose that the function is called with A[I,J], B[I,K], C[J,K] and D[I,J,K]. Then Analytica will iterate over J (for parameter A) and over K (for parameters B and C). D will thus be reduced by dimensions J and K, so that within the function body, D will be remain dimensioned only by I.

When a parameter is declared as Reduced, no index dimensions can be declared. In other words, D : Reduced[I] would result in an error.

An example situation where the Reduced qualifier is useful is the following. Suppose a function can compute multiple related results. A parameter, computation, indicates which result is desired, e.g.:

Function Process( A : Numeric[I] ; I : IndexType ; computation: Reduced )

Within the function, Process can examine the computation parameter to determine exactly which computations need to be done. If the same computation is requested several times (for the same iteration along A), work does not need to be repeated, and if two computations share 90% of a computation, the function can leverage this fact, which it would not be able to do if these were done on separate iterations.

Data Type Qualifiers

Each parameter may have zero or one data type qualifier, specifying the required data type for all atomic elements passed to the parameter. It may be used in conjunction with any of the evaluation modes, including for example IndexType (in which case the index elements are tested), as well as with any dimensionality declarations. The presence of absence of the coerce keyword determines whether Analytica attempts to coerce atomic values into the indicated data type or flags values as errors. The data type is optional, and if omitted, no data type checks are performed when a function is called. A small performance penalty is incurred at the time of a function call when the data type is specified.

Number

(x: Number)

Requires that x is a number (which includes INF, -INF, or NaN), or an array containing only these types of value.

Text

(s: Text)

S must be a text value, or an array containing only text elements.

Reference

( R : Reference )

R must be a reference, or an array of references. It may refer any type of value or object. The qualifiers can place no restrictions on the type or dimensions of the value referred to, other than it is a reference.

Positive

( X : Positive )

A positive number, which could include INF, but not NAN.

NonNegative

Zero or a positive number, which could include INF, but not NAN.

Handle

( V : Handle )

A handle to an Analytica object. The handle may be obtained from Handle, HandleFromIdentifier, IndexesOf, or via the Contains or IsIn attributes of an object, for example. Handles are used in Meta-Inference. The Handle qualifier is a bit different from the Variable, Index or Object qualifiers in that its parameter is typically evaluated. The handle qualifier controls the data type of the elements, not the evaluation mode.

Coerce <type>

If possible, it converts the value of the parameter into the desired type, Text or Number, as specified.

Typical Usages:
(t : Coerce Text; x : Coerce Number)

When coercing a number to Text, it renders the number into text using the Number format of the variable or function that calls the function with the coerced parameter -- not the number format of the coercing function. For example, suppose:

Function Result_text(x: Coerce Text) := 'The result is ' & x
Y -> 'The result is 12,343.68'

Suppose the Number format of Y is Fixed point with 2 decimal digits and commas, then

 Variable Y := Result_text(12345.678)

If the Number of When coercing parameters are coerced to Text, a string representation of each atomic value is rendered (atomic values that are already Text remain unchanged). The number format for the object calling the function is used for the coercion -- not the number format for the function. (If a coercion occurs within the body of the function, such as with the expression ("" & s ), then the number format of the function is used.

Examples:

Fu1 ( S : coerce Text) := S      # format = short date
Fu2 ( S ) := Fu1( S )                # format = fixed pt currency w/commas
Fu3 ( S ) := "" & S                  # format = #.##% trailing zeroes
Va1 := Fu1( 39K )                    # format = suffix
Va2 := Fu2( 39K )                    # format = exponential
Va3 := Fu3( 39K )                    # format = long date

A number to text coercion occurs in the evaluation of Va1, Va2 and Va3. In the case of Va1, Va1's number format determines the coercion. In the case of Va2, Fu2's number format is used. In the case of Va3, Fu3's number format is used. Thus the results would be:

 Va1 = '39K'
 Va2 = '$39,000'
 Va3 = '3900000.00%'

When coercing to numeric, strings containing numeric values are parsed. Thus, the string "45" would be parsed to the numeric value 45. The number format of the caller determines whether the value is parsed as a date, in the same manner as the coercion to string previously described.

Coercion to a reference will cause add a reference to an atomic value that is not already a reference, resulting in a reference to a number, reference to a string, etc.

In all cases, if a coercion is not possible (including the case where a string can't be parsed to a number), an error results.

Ordering Qualifiers

Ascending

Typical Usages:
( A : Ascending[I] )
( L : Ascending List[ ] )
( I : Ascending IndexType )

The ascending qualifier specifies that the values of a list, vector, array, or index must be in non-strictly ascending order. Use of this qualifier requires that the declaration specifies a one-dimensional parameter. Without one dimension, the index over which it must be ascending is ambiguous, and hence an error is issued.

The test triggers an error if any element is less than the value that precedes it. The test is non-strict, so that a constant array, or an element equal to its precedesor, does not trigger an error. There is no parameter qualifier variation that tests for strict ascending order.

Descending

The descending qualifier specifies that the values of a list, vector, array, or index must be in non-strictly descending order. It is the exact dual of the Ascending parameter qualifier -- see the description above for Ascending for details.

Optional and Repeated Parameters

Optional qualifier

Typical uses:
( X : optional )
( A : Array[I] ; I : optional IndexType )

The optional qualifier specifies that a parameter is optional. With the keyword, a default value is not necessary. Inside the function body, a user can test whether a parameter was providing using the function IsSpecified(...) or conversely, using IsUndef(...).

In the body of your function, you can pass a parameter declared as optional as a argument to another function having an optional parameter. If the parameter is not specified to the first function, it will appear to the second function as if it is not specified as well. Within the body, should the parameter variable itself be used, it contains the special system value Undefined.

Optional can be applied to values or indexes. Using the optional qualifier on index parameters causes array parameters using that index to be of variable dimensionality.

Note: Use of the ellipsis qualifier, or the inclusion of a default value, are alternative means to specify optional or variable-length parameter lists.

Default values

Syntax: ident : qualifiers = defaultValue

Typical Usages:
( X : Optional Number= 0 )
( X : Number = 0 )
( A : ContextSample[R] ; R : Index = Run )

An explicit default applies to an optional parameter and provides a value that is used when the parameter is omitted in a call. For value parameters, the optional value should usually be a constant, although an expression is also accepted. For Index and Variable parameters, the optional value must identify an index. For these Unevaluated parameters, it may refer to another parameter earlier in the declaration.

The optional qualifier keyword is implied when a default value is provided. Therefore, the optional keyword is itself optional, although stylistically it makes the declaration more readable.

This feature may not be extremely robust when general expressions are used for the default. Therefore, it is recommended that you try to limit your default values to simple constants.

An index parameter may be given the default of Common, in which case its default is inferred to be the index that all array parameters declared on this index have in common. For example:

( P,R : Array[I] ; I : Index=Common)

In this case, the parameters passed for P and R must share exactly one index if I is not specified.

Repeated parameters (...)

Typical Usages:
(X: ... Scalar)
(A: Array[I] ; I : ... IndexType )


Three dots "..." qualifies a parameter as repeated: The function accepts one or more actual parameters of the given type. If you combine "..." with Optional, it acceptszero or more parameters -- instead of requiring at least one parameter. Within the function, an repeated parameter is a list (with Null index) containing the actual parameters given. For example,

Function ValMax(x: ... Number) := Max(X)
ValMax(3,6,-2,4) --> 6

ValMax() returns the maximum value of its repeated parameter. Unlike the built-in Max function, it doesn't need square brackets around its parameters. During evaluation of ValMax, X is the null-indexed list [3, 6,- 2, 4]. ValMax could also be applied to array arguments, such as

ValMax( sqrt(X), X^2, 0 )

This function

Function Total(a: Array[I]; i: ... IndexType) 

sums its parameter, a, over one or more dimensions -- a generalization of Sum(A,I). For example:

Total(A, I, J, K)

is equivalent to, and simpler than:

Sum(Sum(Sum(A, I), J), K).

Inside the body of Total, A would be an array containing the null-index, along with all dimensions listed in the I parameter.

You can specify an array parameter with a variable number of explicit indexes, by using the ellipsis on an index parameter, e.g:

(A: Array[I]; I: ... Optional IndexType)

A parameter passed to an repeated parameter may NOT be indexed by null. (However, an explicit bracket syntax can be used to group a variable number of arguments in the call, see examples below).


Several syntaxes may be used when calling a function containing an repeated parameter. When the parameter is named in the call, then all arguments that follow are considered to be instances of that parameter up until another parameter name is indicated. For example, in the declaration You may use several methods to specify the actual parameters to a function with repeated parameters. For this function:

 Function Fxy(X: ... scalar; Y: ... Optional Scalar)

you may give the repeated parameter by name:

Fxy(X: 1, 2, 3, 4, Y: 5, 6, 7)

Use position and naming only the second parameter Y:

Fxy(1, 2, 3, 4, Y: 5, 6, 7)

In this case, the first four are treated as parameters to X. You needed to specify parameter Y by name, to make clear that the second four are elements of Y.

You may also use square brackets with pure positional syntax:

Fxy([1,2,3,4], [5,6,7])

The brackets prevent any ambiguity.

Repeated parameters for indexes are useful to enable a variable number of dimensions for an array parameter. However, you cannot (currently) use the individual indexes explicitly from within the user-defined function. You could implement the Total function above as:

 Sum(Sum(Sum(Sum(Sum(Sum(Sum(Sum(Sum(Sum(Sum(Sum(Sum(Sum(Sum(A)))))))))))))))

which would work up to 15 dimensions (the maximum # of dimensions allowed in Analytica anyway), but note that the indexes are not specified explicitly. It would be difficult currently to use the I parameter in the function itself.

Note that Repeated indexes can be mixed with non-Repeated indexes in array declarations, e.g.

(A: Array[I,J]; I: IndexType; J: ... IndexType)

This function requires two or more indexes: I and one or more instances of J.

Other Qualifiers

Hidden

When marked as hidden, a parameter will not be exposed to a user in the object finder dialog, or when pasting the definition via the definition menu. The parameter, however, is there and can be specified in a function call.

Internally Analytica makes use of hidden parameters in the following construct:

( A ; exprA : hidden unevaluated = A )

This allows the underlying implementation access to the expression for A, while still receiving the evaluated parameter A (suitably iterated and typechecked if other qualifiers are attached to A).

Of

The Of qualifier is ignored by the parameter qualifier parser, but can be included within qualifier list for stylistic preference, such as:

(X : Ascending Array[I,J] of Number)
(L : List of Number)

as equivalent alternatives to

(X : Ascending Number Array[I,J] )
(X : Number List )

and so on. Note that qualifiers can appear in any order, and contain various aliases (such as Numeric or Numbers) to make either stylistic variation sensible, depending on user preference.

Deprecated Synonyms for Parameter Qualifiers

We originally defined many parameter qualifiers with multiple synonyms, thinking it would let you specify parameter lists more flexibly. On reflection, it makes more terms to recognize and remember, so we have chosen one preferred term and deprecate the others. Please use the preferred one, since the deprecated ones may not be supported in future releases.

For the benefit of those looking at old Analytica code, here are the synonyms, after the recommended term for each qualifier:

Array: ArrayType, Arr

Index: IndexType

Prob: Probabilistic, ProbType, Uncertain

Sample: Samp, SampType, SampleType

Mid: Determ, DetermType, DetermMode, MidMode

Context: Expr, ContextType

Unevaluated: Expression

ContextSample: ContextSamp, MaybeSamp, MaybeSample

Variable: VariableType, Var, VarType

VariableList: VarList, Variable List, List of Variable

Atom: Atomic, AtomicType, AtomType

Scalar: ScalarType, Scalars

Vector: VectorType

List: ListType

Number: Numeric, Numbers, NumberType, NumericType, Num, Real, Boolean

Text: Textual, TexType, TextType

Reference: Ref, RefType, ReferenceType

NonNegative: PositiveOrZero, NotNegative

Coerce: Coerced

Optional: opt

Comments


You are not allowed to post comments.