Difference between revisions of "Expressions that don't array-abstract"

 
(16 intermediate revisions by 3 users not shown)
Line 1: Line 1:
[[Category:Concepts]]
+
[[Category:Expressions]]
= Principle of Array Abstraction =
 
  
The general principle of array-abstraction can be expressed as follows.  Suppose ''f('''x''')'' denotes any function, expression, or sub-model that computes a result from input(s) '''''x''''', and which does not operate over the index ''I''.  Then for any input ''x'' (which may be array-valued, and may contain the index ''I''), and any element ''n'' of ''I'', the following holds:
+
== Principle of Array Abstraction ==
  
  f(x[I=n]) = f(x)[I=n]
+
A key source of the convenience and power of Analytica is array abstraction, embodied in the feature called [[Intelligent Arrays]].
 +
The general principle of array abstraction can be expressed as follows. Suppose ''f(x)'' denotes any function, expression, or sub-model that computes a result from input(s) «x», and which does not operate over the index ''I''.  Then for any input «x» (which may be array-valued, and may contain the index ''I''), and any element ''n'' of ''I'', the following holds:
 +
 
 +
:<code>f(x[I = n]) = f(x)[I = n]</code>
  
 
In English this says that if you compute your model on the ''n''<sup>th</sup> slice of the input, you'll get the same thing you'd get if you compute your model on the entire array input and then keep just the ''n''<sup>th</sup> slice of the result.   
 
In English this says that if you compute your model on the ''n''<sup>th</sup> slice of the input, you'll get the same thing you'd get if you compute your model on the entire array input and then keep just the ''n''<sup>th</sup> slice of the result.   
  
This simple concept turns out to be extremely powerful.  Notice that the concept applies at every level -- at the level of individual function calls or individual operations (like +, *, etc), all the way up to the level of your entire model.  The uniformity of array abstraction allows you to add and remove dimensions from our models easily, even after the logic is fully encoded, at which point you are better able to understand your problem and decide which subdivisions lead to the greatest insight.  It also allows us to think abstractly about our problem, rather than worrying about the mechanics of computation, greatly simplifying cognitive load while building models.
+
This simple concept turns out to be extremely powerful.  Notice that the concept applies at every level -- at the level of individual function calls or individual operations (like <code>+, *</code>, etc), all the way up to the level of your entire model.  The uniformity of array abstraction allows you to add and remove dimensions from our models easily, even after the logic is fully encoded, at which point you are better able to understand your problem and decide which subdivisions lead to the greatest insight.  It also allows us to think abstractly about our problem, rather than worrying about the mechanics of computation, greatly simplifying cognitive load while building models.
  
Expert modelers learn the importance of ensuring that models fully array-abstract, so that you can add new dimensions at any time and feel confident that the correct results continue to be computed.
+
Expert modelers learn the importance of ensuring that models fully array-abstract, so that you can add new dimensions at any time and feel confident that the correct results continue to be computed.
  
= Limitations =
+
Note that if ''f(x)'' operates over the index ''I'', then the above relationship does not necessarily hold.  For example, expressions [[Max]](A, I) or [[Cumulate]](A, I) operate over the index «I». The principle only holds for indexes that the function or expression does not operate over.
  
In an ideal world, all expressions and models would obey the above principle of array-abstraction. In Analytica this is nearly the case; however, there are several cases which do not fully array abstract. These fall into a couple categories:
+
== Limitations ==
 +
The vast majority of Analytica functions and operators obey the above principle of array-abstraction. It is helpful to be aware of those few that don't, so that you can treat them accordingly. In most cases, you can rewrite expressions so that they will array abstract. Functions and operators that don't array abstract fall into these categories:
  
* List-generation functions: These cannot accept array-valued parameters.
+
* Functions that create lists, such as [[Sequence]], [[Subset]] and [[Copyindex]]: These cannot accept parameters that are arrays (or have more than one index) because they must generate lists which can have only one dimension.
 +
* [[While]] loops, because the condition ''c'' in WHILE ''c'' DO ''e'' must be a scalar Boolean -- <code>True</code> (1) or <code>False</code> (0).
 +
* Assignments in conditional statements like [[If|If-Then-Else]].
 +
* Functions that simply violate the array-abstraction principle.  E.g. [[Size]](A), which returns the number of elements in Array «A».
 
* Expressions that assume scalar or 1-D parameters.  These usually arise from omitting indexes unnecessarily -- by specifying the index you are operating over, your expressions can usually be made to array abstract.
 
* Expressions that assume scalar or 1-D parameters.  These usually arise from omitting indexes unnecessarily -- by specifying the index you are operating over, your expressions can usually be made to array abstract.
* [[While]] loops, where the condition is ambiguous when array-valued.
 
* Assignments in [[If|If-Then-Else]].
 
* Functions that simply violate the array-abstraction principle.  E.g. [[Size]].
 
  
There may be cases where it is appropriate to use expressions that do not array-abstract, and even in these cases, with surrounding declaration qualifiers you may still be able to ensure that your net expressions abstracts.  Nevertheless, a key skill for moving from a competent Analytica model builder to an expert model builder is learning to recognize these cases, and understanding how to formulate expressions so that they will array abstract.  In most cases that do not array abstract, there are equivalent formulations possible that do abstract.
+
There are rare cases where it is appropriate to use expressions that do not array-abstract. Even in these cases, you can often ensure that the overall definition array abstracts by,  surrounding declaration qualifiers.  Nevertheless, a key skill for becoming an expert Analytica modeler is learning to recognize these cases, and understanding how to reformulate expressions so that they do array abstract.
  
= List-Generation Functions =
+
== List-Generation Functions ==
  
Consider the function: [[Sequence]](a,b), or equivalently ''a..b'' -- a sequence from a starting value «a» to an ending value «b» by ones.  For example:
+
Consider the function: [[Sequence]](a, b), or equivalently ''a..b''.  For example:
:[[Sequence]](1,5) &rarr; [1,2,3,4,5]
+
:<code>Sequence(1, 5) &rarr; [1, 2, 3, 4, 5]</code>
:[[Sequence]](3,8) &rarr; [3,4,5,6,7,8]
+
:<code>Sequence(3, 8) &rarr; [3, 4, 5, 6, 7, 8]</code>
 +
:<code>1 .. 5  &rarr; [1, 2, 3, 4, 5]</code>
  
Now, suppose that ''b := [5,6,7]'' and you evaluate [[Sequence]](1,b).  You end up with the three sequences:
+
Suppose that <code>b := [5, 6, 7];</code> then <code>Sequence(1, b)</code> might generate three sequences:
:[1,2,3,4,5]
+
:<code>[1, 2, 3, 4, 5]</code>
:[1,2,3,4,5,6]
+
:<code>[1, 2, 3, 4, 5, 6]</code>
:[1,2,3,4,5,6,7]
+
:<code>[1, 2, 3, 4, 5, 6, 7]</code>
  
If you try to collect these along the index ''b'', the result would be a non-rectangular array.  Since Analytica does not allow non-rectangular arrays, this construct is allowed.  Hence, [[Sequence]] is an example of a function that does not array-abstract. When you use it, you must guarantee that each parameter is scalar.  If you add a dimension to your model that propagates to a parameter of [[Sequence]], an error will occur when [[Sequence]] is evaluated.
+
If you try to combine these along the index «b», the result would be a non-rectangular array.  Analytica disallows this, since it does not support non-rectangular arrays.  Hence, [[Sequence]] does not array-abstract. Its parameters must all be scalar i.e. single numbers, not arrays of numbers.  If you add a dimension that propagates to a parameter of [[Sequence]], it will cause an error message when [[Sequence]] is evaluated.
  
This general limitation applies to all functions that evaluate to a list.  These include:
+
This limitation applies to all functions that evaluate to a list, including:
 
* [[Sequence]]
 
* [[Sequence]]
 
* [[SplitText]]
 
* [[SplitText]]
 
* [[Subset]]
 
* [[Subset]]
 
* [[SortIndex]]  (without the «I» parameter)
 
* [[SortIndex]]  (without the «I» parameter)
* [[Concat]]      (with 2 parameters)
+
* [[Concat]]      (with only 2 parameters)
 +
* [[Unique]]
 
* [[DbQuery]]
 
* [[DbQuery]]
  
When you need to use a function that returns a list result, and you need it to operate in an array-abstractable fashion, one method is to pad the shorter results with [[Null]] values.  The functions [[Subset]], [[SplitText]] and [[Concat]] provide an optional index parameter for the result, which does exactly this, thus saving you the work of re-indexing the intermediate results onto a known index.  For list-generating functions that do not do this, you can accomplish this with your own code, often involving explicit [[For..Do]] loops.
+
When you need to use a function that returns a list result, and you need it to operate in an [[Array Abstraction|array-abstractable]] fashion, one method is to pad the shorter results with [[Null]] values.  The functions [[Subset]], [[SplitText]] and [[Concat]] provide an optional index parameter for the result, which does exactly this, thus saving you the work of re-indexing the intermediate results onto a known index.  For list-generating functions that do not do this, you can accomplish this with your own code, often involving explicit [[For..Do]] loops.
 
 
= Expressions assuming 1-D parameters =
 
 
 
The array parameter for many array functions, including [[Sum]], [[Max]], [[Min]], and others is optional but highly recommended.  When you sum over an array, you should write [[Sum]](A,I), including the second index parameter «I» to tell Analytica which index you are operating over.
 
  
When you know that your array «A» has only one dimension, most functions will allow you to omit the index parameter and write, e.g., [[Sum]](A).  While this works fine when ''A'' is 1-D, if an additional dimension is added to ''A'' in the future, the operation becomes ambiguous -- which dimension is being operated over. For legacy reasons, Analytica in many cases will allow such ambiguous operations without reporting an error, but since you can't tell which dimension is operated over, it may do something differently than expectedThe best advice -- always specify the index being operated over (unless your intention is to operate over the implicit dimension, in which case the omission of the index parameter is fine).
+
== Expressions assuming 1-D parameters ==
 +
For some array functions, including [[Sum]](A, I), [[Max]](A, I), and [[Min]](A, I), the second Index parameter «I» is optional. If omitted, the function selects the outermost index of «A». If «A» has more than one index, it's not obvious which index this is, and it may change if the dimensions of «A» change, and so the result may be ambiguous and not what you intendFor this reason, you should always include the index explicitly as a parameter (except in those very rare cases where you intend to operate over an [[implicit index]]).
  
= [[While]] loop conditions =
+
== While loop conditions ==
 +
A [[While]] loop While ''cond'' Do ''expr''
  
A [[While]] loop, e.g.:
+
evaluates «expr» repeatedly until «cond» becomes true.  [[While]] requires «cond» to be scalar, so that the termination condition is non-ambiguous.  Adding a dimension that propagates to «cond» may result in an error being reported by [[While]] that «cond» is not scalar.
[[While]] ''cond'' Do ''expr''
 
 
 
evaluates ''expr'' repeatedly until ''cond'' becomes true.  [[While]] requires ''cond'' to be scalar, so that the termination condition is non-ambiguous.  Adding a dimension that propagates to ''cond'' may result in an error being reported by [[While]] that ''cond'' is not scalar.
 
 
 
= [[Assignment Operator:: ::=|Assignment]] inside [[If|If-Then-Else]] =
 
  
 +
== Assignment inside If-Then-Else ==
 
The conditional construct [[If|If ''A'' Then ''B'' Else ''C'']] in Analytica is evaluated in an array-fashion.  This can lead to some non-intuitive behaviors, and in particular to expressions that violate the law of array-abstraction if you do anything with side-effects (e.g., assignment) inside the Then or Else clauses.
 
The conditional construct [[If|If ''A'' Then ''B'' Else ''C'']] in Analytica is evaluated in an array-fashion.  This can lead to some non-intuitive behaviors, and in particular to expressions that violate the law of array-abstraction if you do anything with side-effects (e.g., assignment) inside the Then or Else clauses.
  
 
The following example demonstrates (for more information, see the "Gotchas" section at [[Assignment Operator:: ::=|Assignment operator]]:
 
The following example demonstrates (for more information, see the "Gotchas" section at [[Assignment Operator:: ::=|Assignment operator]]:
  
{| border="0"
+
:<code>Var b := [true, false];</code>
|
+
:<code>Var r := 0;</code>
[[Var]] b := [true,false];
+
:<code>If b then r := r + 1 else r := r - 1;</code>
[[Var]] r := 0;
+
:<code>r</code>
[[If]] b then r:=r+1 else r:=r-1;
+
:<code>&rarr; 0</code>
r
 
| &rarr; 0
 
|}
 
  
When this is evaluated, since ''b'' contains both ''true'' and ''false'' values, both the then and else clauses are evaluated.  ''r'' is incremented then decremented, so the final result is 0.  But:
+
When this is evaluated, since <code>b</code> contains both ''true'' and ''false'' values, both the then and else clauses are evaluated.  <code>r</code> is incremented then decremented, so the final result is 0.  But:
  
{| border="0"
+
:<code>Var b := true;</code>
|
+
:<code>Var r := 0;</code>
[[Var]] b := true;
+
:<code>If b then r := r + 1 else r := r - 1;</code>
[[Var]] r := 0;
+
:<code>r</code>
[[If]] b then r:=r+1 else r:=r-1;
+
:<code>&rarr; 1</code>
r
 
| &rarr; 1
 
|}
 
  
{| border="0"
+
:<code>Var b := false;</code>
|
+
:<code>Var r := 0;</code>
[[Var]] b := false;
+
:<code>If b then r := r + 1 else r := r - 1;</code>
[[Var]] r := 0;
+
:<code>r</code>
[[If]] b then r:=r+1 else r:=r-1;
+
:<code>&rarr; -1</code>
r
 
| &rarr; -1
 
|}
 
  
If the expression obeyed the principle of array abstraction, the result for the b:=[true,false] case would be [1,-1], not 0.
+
The right way to do this is to assign to <code>r</code> the result of the conditional expression:
  
= Functions that violate the Array-Abstraction Principle =
+
:<code>Var b := [true, false];</code>
 +
:<code>Var r := 0;</code>
 +
:<code>r := If b then r + 1 else r - 1</code>
 +
:<code>&rarr; [1, -1]</code>
  
 +
== Functions that violate the Array-Abstraction Principle ==
 
Some functions simply violate the law of array-abstraction by the very nature of what they do.  Many meta-inferential algorithms fall into this category.  Perhaps the most common yet subtle is the [[Size]] function.  As an exercise, dhow that [[Size]](A) violates the law of array-abstraction expressed at the top of this page.
 
Some functions simply violate the law of array-abstraction by the very nature of what they do.  Many meta-inferential algorithms fall into this category.  Perhaps the most common yet subtle is the [[Size]] function.  As an exercise, dhow that [[Size]](A) violates the law of array-abstraction expressed at the top of this page.
  
= Obtaining Abstractable Expressions via Encapsulation =
+
== Obtaining Abstractable Expressions via Encapsulation ==
 
 
 
Suppose you have an expression that works in the simple case, but does not array-abstract for one of the above reasons.  Although you may be able to find a way to write it differently, you may also be able to encapsulate it appropriately so that the full expression does array abstract.
 
Suppose you have an expression that works in the simple case, but does not array-abstract for one of the above reasons.  Although you may be able to find a way to write it differently, you may also be able to encapsulate it appropriately so that the full expression does array abstract.
  
Consider the example above demonstrating the perils of using side-effects inside an [[If-Then-Else]].  In this case, we have a single variable, ''b'', serving as input to the algorithm.  By augmenting the declaration of ''b'' to indicate the dimensionality that ''b'' should have inside the expression, Analytica can iterate appropriate so that ''b'' will be atomic when the [[If]] condition is evaluated.  The following two declarations are equivalent syntaxes for declaring that ''b'' is atomic (i.e., zero-dimensional):
+
Consider the example above demonstrating the perils of using side-effects inside an [[If-Then-Else]].  In this case, we have a single variable, <code>b</code>, serving as input to the algorithm.  By augmenting the declaration of <code>b</code. to indicate the dimensionality that <code>b</code> should have inside the expression, Analytica can iterate appropriate so that <code>b</code> will be atomic when the [[If]] condition is evaluated.  The following two declarations are equivalent syntaxes for declaring that <code>b</code> is atomic (i.e., zero-dimensional):
  
[[Var]] b[ ] := ...
+
:<code>Var b[ ] := ...</code>
 
or
 
or
[[Atomic]] b := ...
+
:<code>Atomic b := ...</code>
  
The first syntax lists the allowed dimensions of ''b'' between brackets -- in this case, an empty list, indicating that no dimensions of ''b'' are allowed.   
+
The first syntax lists the allowed dimensions of <code>b</code> between brackets -- in this case, an empty list, indicating that no dimensions of ''b'' are allowed.   
  
{| border="0"
+
:<code>Var b[ ] := [true, false];</code>
|
+
:<code>Var r := 0;</code>
[[Var]] b[ ] := [true,false];
+
:<code>If b then r:=r + 1 else r:=r - 1;</code>
[[Var]] r := 0;
+
:<code> r</code>
[[If]] b then r:=r+1 else r:=r-1;
+
<code>&rarr; [1, -1]</code>
r
 
| &rarr; [1,-1]
 
|}
 
  
 
A second method for encapsulating, which is more efficient when there are two or more inputs, is to wrap the expression in a [[User-Defined Function]] and declare the dimensionality of each parameter:
 
A second method for encapsulating, which is more efficient when there are two or more inputs, is to wrap the expression in a [[User-Defined Function]] and declare the dimensionality of each parameter:
  
Function F(b : atom) :=
+
:<code>Function F(b : atom) :=</code>
  [[Var]] r := 0;
+
:<code>Var r := 0;</code>
  [[If]] b Then r:=r+1 Else r:=r-1;
+
:<code>If b Then r := r + 1 Else r := r - 1;</code>
  r
+
:<code>r</code>
 +
:<code>F([true, false]) &rarr; [1, -1]</code>
 +
 
 +
When called with <code>F([true, false])</code>, Analytica uses the dimensionality information to iterate so at to obtain a result consistent with the principle of array-abstraction.
  
When called with F([true,false]), Analytica uses the dimensionality information to iterate so at to obtain a result consistent with the principle of array-abstraction.
+
==See Also==
 +
* [[Array Abstraction]]
 +
* [https://www.youtube.com/watch?v=_8ZaXnEwhoE Intelligent Array Abstraction] (explanatory video on YouTube)
 +
* [[Intelligent Arrays]]

Latest revision as of 21:17, 4 August 2016


Principle of Array Abstraction

A key source of the convenience and power of Analytica is array abstraction, embodied in the feature called Intelligent Arrays. The general principle of array abstraction can be expressed as follows. Suppose f(x) denotes any function, expression, or sub-model that computes a result from input(s) «x», and which does not operate over the index I. Then for any input «x» (which may be array-valued, and may contain the index I), and any element n of I, the following holds:

f(x[I = n]) = f(x)[I = n]

In English this says that if you compute your model on the nth slice of the input, you'll get the same thing you'd get if you compute your model on the entire array input and then keep just the nth slice of the result.

This simple concept turns out to be extremely powerful. Notice that the concept applies at every level -- at the level of individual function calls or individual operations (like +, *, etc), all the way up to the level of your entire model. The uniformity of array abstraction allows you to add and remove dimensions from our models easily, even after the logic is fully encoded, at which point you are better able to understand your problem and decide which subdivisions lead to the greatest insight. It also allows us to think abstractly about our problem, rather than worrying about the mechanics of computation, greatly simplifying cognitive load while building models.

Expert modelers learn the importance of ensuring that models fully array-abstract, so that you can add new dimensions at any time and feel confident that the correct results continue to be computed.

Note that if f(x) operates over the index I, then the above relationship does not necessarily hold. For example, expressions Max(A, I) or Cumulate(A, I) operate over the index «I». The principle only holds for indexes that the function or expression does not operate over.

Limitations

The vast majority of Analytica functions and operators obey the above principle of array-abstraction. It is helpful to be aware of those few that don't, so that you can treat them accordingly. In most cases, you can rewrite expressions so that they will array abstract. Functions and operators that don't array abstract fall into these categories:

  • Functions that create lists, such as Sequence, Subset and Copyindex: These cannot accept parameters that are arrays (or have more than one index) because they must generate lists which can have only one dimension.
  • While loops, because the condition c in WHILE c DO e must be a scalar Boolean -- True (1) or False (0).
  • Assignments in conditional statements like If-Then-Else.
  • Functions that simply violate the array-abstraction principle. E.g. Size(A), which returns the number of elements in Array «A».
  • Expressions that assume scalar or 1-D parameters. These usually arise from omitting indexes unnecessarily -- by specifying the index you are operating over, your expressions can usually be made to array abstract.

There are rare cases where it is appropriate to use expressions that do not array-abstract. Even in these cases, you can often ensure that the overall definition array abstracts by, surrounding declaration qualifiers. Nevertheless, a key skill for becoming an expert Analytica modeler is learning to recognize these cases, and understanding how to reformulate expressions so that they do array abstract.

List-Generation Functions

Consider the function: Sequence(a, b), or equivalently a..b. For example:

Sequence(1, 5) → [1, 2, 3, 4, 5]
Sequence(3, 8) → [3, 4, 5, 6, 7, 8]
1 .. 5 → [1, 2, 3, 4, 5]

Suppose that b := [5, 6, 7]; then Sequence(1, b) might generate three sequences:

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

If you try to combine these along the index «b», the result would be a non-rectangular array. Analytica disallows this, since it does not support non-rectangular arrays. Hence, Sequence does not array-abstract. Its parameters must all be scalar i.e. single numbers, not arrays of numbers. If you add a dimension that propagates to a parameter of Sequence, it will cause an error message when Sequence is evaluated.

This limitation applies to all functions that evaluate to a list, including:

When you need to use a function that returns a list result, and you need it to operate in an array-abstractable fashion, one method is to pad the shorter results with Null values. The functions Subset, SplitText and Concat provide an optional index parameter for the result, which does exactly this, thus saving you the work of re-indexing the intermediate results onto a known index. For list-generating functions that do not do this, you can accomplish this with your own code, often involving explicit For..Do loops.

Expressions assuming 1-D parameters

For some array functions, including Sum(A, I), Max(A, I), and Min(A, I), the second Index parameter «I» is optional. If omitted, the function selects the outermost index of «A». If «A» has more than one index, it's not obvious which index this is, and it may change if the dimensions of «A» change, and so the result may be ambiguous and not what you intend. For this reason, you should always include the index explicitly as a parameter (except in those very rare cases where you intend to operate over an implicit index).

While loop conditions

A While loop While cond Do expr

evaluates «expr» repeatedly until «cond» becomes true. While requires «cond» to be scalar, so that the termination condition is non-ambiguous. Adding a dimension that propagates to «cond» may result in an error being reported by While that «cond» is not scalar.

Assignment inside If-Then-Else

The conditional construct If A Then B Else C in Analytica is evaluated in an array-fashion. This can lead to some non-intuitive behaviors, and in particular to expressions that violate the law of array-abstraction if you do anything with side-effects (e.g., assignment) inside the Then or Else clauses.

The following example demonstrates (for more information, see the "Gotchas" section at Assignment operator:

Var b := [true, false];
Var r := 0;
If b then r := r + 1 else r := r - 1;
r
→ 0

When this is evaluated, since b contains both true and false values, both the then and else clauses are evaluated. r is incremented then decremented, so the final result is 0. But:

Var b := true;
Var r := 0;
If b then r := r + 1 else r := r - 1;
r
→ 1
Var b := false;
Var r := 0;
If b then r := r + 1 else r := r - 1;
r
→ -1

The right way to do this is to assign to r the result of the conditional expression:

Var b := [true, false];
Var r := 0;
r := If b then r + 1 else r - 1
→ [1, -1]

Functions that violate the Array-Abstraction Principle

Some functions simply violate the law of array-abstraction by the very nature of what they do. Many meta-inferential algorithms fall into this category. Perhaps the most common yet subtle is the Size function. As an exercise, dhow that Size(A) violates the law of array-abstraction expressed at the top of this page.

Obtaining Abstractable Expressions via Encapsulation

Suppose you have an expression that works in the simple case, but does not array-abstract for one of the above reasons. Although you may be able to find a way to write it differently, you may also be able to encapsulate it appropriately so that the full expression does array abstract.

Consider the example above demonstrating the perils of using side-effects inside an If-Then-Else. In this case, we have a single variable, b, serving as input to the algorithm. By augmenting the declaration of b</code. to indicate the dimensionality that b should have inside the expression, Analytica can iterate appropriate so that b will be atomic when the If condition is evaluated. The following two declarations are equivalent syntaxes for declaring that b is atomic (i.e., zero-dimensional):

Var b[ ] := ...

or

Atomic b := ...

The first syntax lists the allowed dimensions of b between brackets -- in this case, an empty list, indicating that no dimensions of b are allowed.

Var b[ ] := [true, false];
Var r := 0;
If b then r:=r + 1 else r:=r - 1;
r

→ [1, -1]

A second method for encapsulating, which is more efficient when there are two or more inputs, is to wrap the expression in a User-Defined Function and declare the dimensionality of each parameter:

Function F(b : atom) :=
Var r := 0;
If b Then r := r + 1 Else r := r - 1;
r
F([true, false]) → [1, -1]

When called with F([true, false]), Analytica uses the dimensionality information to iterate so at to obtain a result consistent with the principle of array-abstraction.

See Also

Comments


You are not allowed to post comments.