Difference between revisions of "Var..Do"

Line 2: Line 2:
 
[[Category:Doc Status D]] <!-- For Lumina use, do not change -->
 
[[Category:Doc Status D]] <!-- For Lumina use, do not change -->
 
   
 
   
== Var «x» := «expr» Do «body» ==
+
== Var ''x'' := ''expr'' Do ''body'' ==
 
 
 
Declares a local variable with identifier «x», and assigns it an initial value obtained by evaluating «expr».  The identifier «x» can then be referred to within the «body» expression.  The expression «body» is said to be the ''lexical context'' of «x», since outside of the lexical context, the identifier «x» is not recognized.
 
Declares a local variable with identifier «x», and assigns it an initial value obtained by evaluating «expr».  The identifier «x» can then be referred to within the «body» expression.  The expression «body» is said to be the ''lexical context'' of «x», since outside of the lexical context, the identifier «x» is not recognized.
  
Line 17: Line 16:
  
 
== Dimensionality Declaration ==
 
== Dimensionality Declaration ==
 
 
The ''allowed'' dimensions of a local variable can be declared using the syntax:
 
The ''allowed'' dimensions of a local variable can be declared using the syntax:
 
 
:<code>Var «x»[«indexList»] := «expr» Do «body»</code>
 
:<code>Var «x»[«indexList»] := «expr» Do «body»</code>
  
 
an equivalent anachronism (considered deprecated) is
 
an equivalent anachronism (considered deprecated) is
 
 
:<code>Var «x» := «expr» in each «indexList» Do «body»</code>
 
:<code>Var «x» := «expr» in each «indexList» Do «body»</code>
  
Line 33: Line 29:
  
 
==== Example ====
 
==== Example ====
 
 
The following computes the standard deviation across only the time periods that are profitable:
 
The following computes the standard deviation across only the time periods that are profitable:
  
Line 40: Line 35:
 
:<code>SDeviation(earnings[Time = profitTimes], profitTimes)</code>
 
:<code>SDeviation(earnings[Time = profitTimes], profitTimes)</code>
  
Without the dimensional declaration restricting <code>earnings</code> to the <code>Time</code> index, [[Subset]] would complain that earnings has more than dimension in the event that <code>revenue-expenses</code> has an index in addition to <code>Time</code>.  The dimensional declaration here allows the expression to fully array abstract if new dimensions are added to the model.
+
Without the dimensional declaration restricting <code>earnings</code> to the [[Time]] index, [[Subset]] would complain that earnings has more than dimension in the event that <code>revenue-expenses</code> has an index in addition to [[Time]].  The dimensional declaration here allows the expression to fully array abstract if new dimensions are added to the model.
  
 
The above expression is meant to be illustrative, but for completeness we also note an alternative expression for the same computation that does not require iteration:
 
The above expression is meant to be illustrative, but for completeness we also note an alternative expression for the same computation that does not require iteration:
Line 46: Line 41:
  
 
=== Atomic Declarations ===
 
=== Atomic Declarations ===
 
 
A special case of the dimensional declaration is the declaration that a local variable must be ''atomic'' -- i.e., a single non-array value.  In this case, the we simply specify a zero-length list of allowed indexes:
 
A special case of the dimensional declaration is the declaration that a local variable must be ''atomic'' -- i.e., a single non-array value.  In this case, the we simply specify a zero-length list of allowed indexes:
 
 
:<code>Var «x»[] := «expr» Do «body»</code>
 
:<code>Var «x»[] := «expr» Do «body»</code>
  
Line 54: Line 47:
  
 
==== Example ====
 
==== Example ====
 
+
The following computes the log-factorial of a number in an [[Array Abstraction|array-abstractable]] fashion (i.e., works even if ''n'' is originally an array:
The following computes the log-factorial of a number in an array-abstractable fashion (i.e., works even if ''n'' is originally an array:
 
 
 
 
:<code>Var n[] := n do Sum(Ln(1..n))</code>
 
:<code>Var n[] := n do Sum(Ln(1..n))</code>
  
Line 62: Line 53:
  
 
=== Atomic..Do syntax ===
 
=== Atomic..Do syntax ===
 
+
Analytica also recognizes the following syntax for declaring a local variable as atomic:
''New to Analytica 4.2''
 
 
 
Analytica 4.2 also recognizes the following syntax for declaring a local variable as atomic:
 
 
:<code>Atomic «x» := «expr» Do «body»</code>
 
:<code>Atomic «x» := «expr» Do «body»</code>
  
Line 72: Line 60:
  
 
== Explicit Iteration ==
 
== Explicit Iteration ==
 
 
The following syntax:
 
The following syntax:
 
 
:<code>Var «x» := «expr» In «I» Do «body»</code>
 
:<code>Var «x» := «expr» In «I» Do «body»</code>
  
Line 80: Line 66:
  
 
== Assignment ==
 
== Assignment ==
 
 
Although side-effects are generally prohibited from within Analytica expressions (due to dependency-maintenance and Analytica's adherence to the principle of [http://en.wikipedia.org/wiki/index.php/Referential_transparency_(computer_science) referential transparency]), you can change the value of a local variable using the [[Assignment Operator::_::=|assignment operator, :=]].  For example:
 
Although side-effects are generally prohibited from within Analytica expressions (due to dependency-maintenance and Analytica's adherence to the principle of [http://en.wikipedia.org/wiki/index.php/Referential_transparency_(computer_science) referential transparency]), you can change the value of a local variable using the [[Assignment Operator::_::=|assignment operator, :=]].  For example:
  
Line 94: Line 79:
  
 
=== Slice assignment ===
 
=== Slice assignment ===
 
 
You can also assign to individual slices of a local variable.  This is described in detail at [[Slice assignment]].
 
You can also assign to individual slices of a local variable.  This is described in detail at [[Slice assignment]].
  
 
== Evaluation Mode ==
 
== Evaluation Mode ==
 
 
A local variable contains only a single value.  It is not an Analytica object in the way a global variable is (this type of variable that appears on an influence diagram).  A local variable has no attributes, does not appear in the global namespace, and does not maintain a separate [[Mid]]- and [[Sample]]-value.   
 
A local variable contains only a single value.  It is not an Analytica object in the way a global variable is (this type of variable that appears on an influence diagram).  A local variable has no attributes, does not appear in the global namespace, and does not maintain a separate [[Mid]]- and [[Sample]]-value.   
  
Line 106: Line 89:
 
:<code>SDeviation(u)</code>
 
:<code>SDeviation(u)</code>
  
When this expression is evaluated in Mid mode it is not equivalent to ''[[SDeviation]]([[Uniform]](0,1))''.  The later evaluates to 0.29, while the former results in 0.  This is because ''u'' is assigned [[Mid]]([[Uniform]](0, 1)), which is 0.5, and then the result is [[SDeviation]](0.5), which is zero.
+
When this expression is evaluated in [[Mid]] mode it is not equivalent to <code>SDeviation(Uniform(0, 1))</code>.  The later evaluates to 0.29, while the former results in 0.  This is because <code>u</code> is assigned <code>Mid(Uniform(0,1))</code>, which is 0.5, and then the result is <code>SDeviation(0.5)</code>, which is zero.
  
You can, of course, call [[Sample]]( ) or [[Mid]]( ) explicitly from «expr» when desired, e.g.:
+
You can, of course, call [[Sample]]() or [[Mid]]() explicitly from «expr» when desired, e.g.:
 
:<code>Var u := Sample(Uniform(0, 1));</code>
 
:<code>Var u := Sample(Uniform(0, 1));</code>
 
:<code> SDeviation(u)</code>
 
:<code> SDeviation(u)</code>
  
 +
== Meta-Inference and the use of handles ==
 +
Most models built in Analytica make no use of [[handle]]s, and so the considerations described here impact only the most advanced modelers.  Inference involving [[handle]]s provides a mechanism for [[meta-Inference]] -- that is, reasoning about or altering your model from within Analytica itself.  Advanced uses of [[meta-Inference]] can be used to extend Analytica's capabilities in many ways, creating functionality in your model beyond what is offered directly by the Analytica interface.
  
== [[Meta-Inference]] and the use of [[Handle]]s ==
+
A [[handle]] is essentially a pointer to an Analytica object, such as a Variable, Index, or Module object. [[Meta-inference]] implementations usually need to store [[handle]]s inside local variables, assign handles to local variables, read information about the objects pointed to by these handles, and manipulate the objects pointed to by these handles.   
 
 
Most models built in Analytica make no use of [[Handle]]s, and so the considerations described here impact only the most advanced modelers.  Inference involving [[Handle]]s provides a mechanism for [[Meta-Inference]] -- that is, reasoning about or altering your model from within Analytica itself.  Advance uses of [[Meta-Inference]] can be used to extend Analytica's capabilities in many ways, creating functionality in your model beyond what is offered directly by the Analytica interface.
 
 
 
A [[Handle]] is essentially a pointer to an Analytica object, such as a Variable, Index, or Module object. [[Meta-inference]] implementations usually need to store [[handle]]s inside local variables, assign handles to local variables, read information about the objects pointed to by these handles, and manipulate the objects pointed to by these handles.   
 
  
When implementing [[Meta-inference]] algorithms in Analytica 4.2 or later, two variations of [[Var..Do]] are preferred when [[Handles]] are involved, since these two variations have a cleaner semantics.  They are:
+
When implementing [[meta-inference]] algorithms, two variations of [[Var..Do]] are preferred when [[Handles]] are involved, since these two variations have a cleaner semantics.  They are:
  
* [[LocalAlias]] «x» := «expr» Do «body»
+
* LocalAlias «x» := «expr» Do «body»
*: or equivalently, [[LocalAlias|Alias]] «x» := «expr» Do «body»
+
*: or equivalently, Alias «x» := «expr» Do «body»
 
* MetaVar «x»''[«indexList»]'' := «expr» Do «body»
 
* MetaVar «x»''[«indexList»]'' := «expr» Do «body»
  
When [[LocalAlias..Do]] is used to assign a [[Handle]] to «x», then «x» is treated everywhere as an alias of the object pointed to.  If you were to copy the expression and substitute the object's identifier everywhere «x» appears (assuming the object is in the global namespace), you would get the identical result.  Once the local variable is assigned a handle, you can no longer change the handle (i.e., change which object is pointed to), since an assignment, «x» := z, would be interpreted as an assignment to the object pointed to, rather than an assignment to the local variable.  You cannot declare dimensions in a [[LocalAlias..Do]] or [[LocalAlias..Do|Alias..Do]] declaration.
+
When [[LocalAlias..Do]] is used to assign a [[handle]] to «x», then «x» is treated everywhere as an alias of the object pointed to.  If you were to copy the expression and substitute the object's identifier everywhere «x» appears (assuming the object is in the global namespace), you would get the identical result.  Once the local variable is assigned a handle, you can no longer change the handle (i.e., change which object is pointed to), since an assignment, «x» := z, would be interpreted as an assignment to the object pointed to, rather than an assignment to the local variable.  You cannot declare dimensions in a [[LocalAlias..Do]] or [[LocalAlias..Do|Alias..Do]] declaration.
  
When a [[Handle]] is assigned to a local variable declared as [[MetaVar..Do]], then the variable refers to an atomic handle object.  Operations such as ''«x»+1'' do not make sense, since this would be attempting to add 1 to a handle object, rather than adding 1 to value of the variable pointed to by the object.  As the declaration name [[MetaVar]] implies, this is usually the preferred method for declaring local variables that are used to manipulate handles to objects.  Your local variable may contain a handle, or an array of handles, as well as other data types. Like [[Var..Do]], you can declare dimensions inside a [[MetaVar..Do]] declaration (for example, the dimensions allowed to exist in the array of handles).
+
When a [[handle]] is assigned to a local variable declared as [[MetaVar..Do]], then the variable refers to an atomic handle object.  Operations such as ''«x»+1'' do not make sense, since this would be attempting to add 1 to a handle object, rather than adding 1 to value of the variable pointed to by the object.  As the declaration name [[MetaVar]] implies, this is usually the preferred method for declaring local variables that are used to manipulate handles to objects.  Your local variable may contain a handle, or an array of handles, as well as other data types. Like [[Var..Do]], you can declare dimensions inside a [[MetaVar..Do]] declaration (for example, the dimensions allowed to exist in the array of handles).
  
 
When a handle is assigned to a local variable «x» declared using [[Var..Do]], it acts as a hybrid between a localalias an a metavar.  In a value context, «x» acts as an alias to the object.  However, in an assignment context (an L-value context), the local variable is changed «x», not the object pointed to by «x».  Consider:
 
When a handle is assigned to a local variable «x» declared using [[Var..Do]], it acts as a hybrid between a localalias an a metavar.  In a value context, «x» acts as an alias to the object.  However, in an assignment context (an L-value context), the local variable is changed «x», not the object pointed to by «x».  Consider:
Line 134: Line 115:
 
:<code>x := x + 1</code>
 
:<code>x := x + 1</code>
  
Here ''x'' is first assigned a handle to ''A''.  In the assignment operation, when the right-hand side of the assignment is evaluated, ''x+1'' refers to the value of ''A'' plus 1.  Hence ''x'' acts as an alias to ''A''.  The assignment changes the value of the local variable, but does not alter ''A''.  After the assignment, the local ''x'' contains numeric value (or perhaps array of numeric values) and no longer points to the variable ''A''.
+
Here <code>x</code> is first assigned a handle to <code>A</code>.  In the assignment operation, when the right-hand side of the assignment is evaluated, <code>x + 1</code> refers to the value of <code>A</code> plus 1.  Hence <code>x</code> acts as an alias to <code>A</code>.  The assignment changes the value of the local variable, but does not alter <code>A</code>.  After the assignment, the local <code>x</code> contains numeric value (or perhaps array of numeric values) and no longer points to the variable <code>A</code>.
  
Suppose in the above example that A evaluated to a [[Self-Indexed Arrays|self-indexed array]].  The right-hand side of the assignment is a value context, so in this case, ''x'' refers to the array-value of ''A''.  If we wanted ''x'' to alias the index value of ''A'', rather than the array value, we could use the following instead:
+
Suppose in the above example that <code>A</code> evaluated to a [[Self-Indexed Arrays|self-indexed array]].  The right-hand side of the assignment is a value context, so in this case, <code>x</code> refers to the array-value of <code>A</code>.  If we wanted <code>x</code> to alias the index value of <code>A</code>, rather than the array value, we could use the following instead:
  
 
:<code>Var x := Handle(A, asIndex: true);</code>
 
:<code>Var x := Handle(A, asIndex: true);</code>
Line 142: Line 123:
  
 
== See Also ==
 
== See Also ==
 
 
* [[For..Do]]
 
* [[For..Do]]
* [[Index..Do]], [[MetaIndex..Do]]
+
* [[Index..Do]]
 +
* [[MetaIndex..Do]]
 
* [[Function Parameter Qualifiers]]
 
* [[Function Parameter Qualifiers]]
 
* [[Assignment Operator :=]]
 
* [[Assignment Operator :=]]

Revision as of 04:35, 20 January 2016


Var x := expr Do body

Declares a local variable with identifier «x», and assigns it an initial value obtained by evaluating «expr». The identifier «x» can then be referred to within the «body» expression. The expression «body» is said to be the lexical context of «x», since outside of the lexical context, the identifier «x» is not recognized.

Var..Do is often used in a procedural syntax, where the declaration is followed by a semi-colon and the Do keyword is omitted, such as:

Var x := Sum(A, I);
Var y := Sum(B, I);
(x + y) * (x - y)

With this syntax, the lexical context for «x» extends from the expression immediately following the semi-colon to the end of the sub-expression that the Var..Do declaration is embedded in. For example, in the following expression the lexical scope of a is shown in green.

1 + (Var a := b^2; Var c := a/b; c^2 - a - c - 2) + 5

Dimensionality Declaration

The allowed dimensions of a local variable can be declared using the syntax:

Var «x»[«indexList»] := «expr» Do «body»

an equivalent anachronism (considered deprecated) is

Var «x» := «expr» in each «indexList» Do «body»

There are some situations where the extra information about which indexes are allowed is required in order to ensure that the «body» expression will array abstract correctly when new dimensions are added to a model later.

When the allowed indexes are declared, Analytica will ensure that when «body» is evaluated, the value of «x» will not have any indexes not listed in «indexList». If the original value assigned to «x» has indexes beyond those found in «indexList», Analytica will automatically iterate, evaluating «body» multiple times one slice at a time.

If the result of «expr» does not already have all the indexes declared in «indexList», the missing indexes are NOT added to «x».

Example

The following computes the standard deviation across only the time periods that are profitable:

Var earnings[Time] := revenue-expenses;
Index profitTimes := Subset(earnings > 0);
SDeviation(earnings[Time = profitTimes], profitTimes)

Without the dimensional declaration restricting earnings to the Time index, Subset would complain that earnings has more than dimension in the event that revenue-expenses has an index in addition to Time. The dimensional declaration here allows the expression to fully array abstract if new dimensions are added to the model.

The above expression is meant to be illustrative, but for completeness we also note an alternative expression for the same computation that does not require iteration:

Var earnings := revenue - expenses Do SDeviation(earnings, Time, w: earnings > 0)

Atomic Declarations

A special case of the dimensional declaration is the declaration that a local variable must be atomic -- i.e., a single non-array value. In this case, the we simply specify a zero-length list of allowed indexes:

Var «x»[] := «expr» Do «body»

Then inside «body», «x» is guaranteed to be atomic.

Example

The following computes the log-factorial of a number in an array-abstractable fashion (i.e., works even if n is originally an array:

Var n[] := n do Sum(Ln(1..n))

Note: The local variable can have the same identifier as a global variable, and the value of the global can appear within «expr» since that is outside the local identifier's lexical scope. Inside «body», the identifier always refers to the local variable. Having two local variables with the same identifier is not allowed.

Atomic..Do syntax

Analytica also recognizes the following syntax for declaring a local variable as atomic:

Atomic «x» := «expr» Do «body»

This syntax is equivalent to Var «x»[] := «expr» Do «body» as long as the result of «expr» does not contain any Handles. It is actually equivalent to the following variation of Var..Do (also introduced in release 4.2):

MetaVar «x»[] := «expr» Do «body»

Explicit Iteration

The following syntax:

Var «x» := «expr» In «I» Do «body»

evaluates «expr», then iterates over each element of index «I», setting «x» to the «expr»[«I» = i] slice while «body» is evaluated. In a sense, this is a dual to the dimension declaration -- here we are specifying the dimensions that are not allowed in «x», while the Var «x»[«I»] := ... syntax specifies the dimensions that are allowed. However, in this syntax, only a single index can be specified.

Assignment

Although side-effects are generally prohibited from within Analytica expressions (due to dependency-maintenance and Analytica's adherence to the principle of referential transparency), you can change the value of a local variable using the assignment operator, :=. For example:

Var n := 27;
Var steps := 0;
While (n > 2) Do (
steps := steps + 1;
n := if Mod(n, 2) Then n/2 else 3*n + 1
);
steps

Assignment always resets the value of «x», even if «x» contains a handle. In other words, when you assign to a local variable, you are resetting what the local variable points to, as opposed to changing the value of the object pointed to by the local variable. See more in the section below on Meta-Inference.

Slice assignment

You can also assign to individual slices of a local variable. This is described in detail at Slice assignment.

Evaluation Mode

A local variable contains only a single value. It is not an Analytica object in the way a global variable is (this type of variable that appears on an influence diagram). A local variable has no attributes, does not appear in the global namespace, and does not maintain a separate Mid- and Sample-value.

When the local variable is declared, «expr» is evaluated in the current Evaluation mode. From that point on, «x» becomes an alias for the value that resulted from that evaluation, whether or not the identifier «x» appears in Mid- or Sample- context. This can be a source of confusion. Consider the following example:

Var u := Uniform(0, 1);
SDeviation(u)

When this expression is evaluated in Mid mode it is not equivalent to SDeviation(Uniform(0, 1)). The later evaluates to 0.29, while the former results in 0. This is because u is assigned Mid(Uniform(0,1)), which is 0.5, and then the result is SDeviation(0.5), which is zero.

You can, of course, call Sample() or Mid() explicitly from «expr» when desired, e.g.:

Var u := Sample(Uniform(0, 1));
SDeviation(u)

Meta-Inference and the use of handles

Most models built in Analytica make no use of handles, and so the considerations described here impact only the most advanced modelers. Inference involving handles provides a mechanism for meta-Inference -- that is, reasoning about or altering your model from within Analytica itself. Advanced uses of meta-Inference can be used to extend Analytica's capabilities in many ways, creating functionality in your model beyond what is offered directly by the Analytica interface.

A handle is essentially a pointer to an Analytica object, such as a Variable, Index, or Module object. Meta-inference implementations usually need to store handles inside local variables, assign handles to local variables, read information about the objects pointed to by these handles, and manipulate the objects pointed to by these handles.

When implementing meta-inference algorithms, two variations of Var..Do are preferred when Handles are involved, since these two variations have a cleaner semantics. They are:

  • LocalAlias «x» := «expr» Do «body»
    or equivalently, Alias «x» := «expr» Do «body»
  • MetaVar «x»[«indexList»] := «expr» Do «body»

When LocalAlias..Do is used to assign a handle to «x», then «x» is treated everywhere as an alias of the object pointed to. If you were to copy the expression and substitute the object's identifier everywhere «x» appears (assuming the object is in the global namespace), you would get the identical result. Once the local variable is assigned a handle, you can no longer change the handle (i.e., change which object is pointed to), since an assignment, «x» := z, would be interpreted as an assignment to the object pointed to, rather than an assignment to the local variable. You cannot declare dimensions in a LocalAlias..Do or Alias..Do declaration.

When a handle is assigned to a local variable declared as MetaVar..Do, then the variable refers to an atomic handle object. Operations such as «x»+1 do not make sense, since this would be attempting to add 1 to a handle object, rather than adding 1 to value of the variable pointed to by the object. As the declaration name MetaVar implies, this is usually the preferred method for declaring local variables that are used to manipulate handles to objects. Your local variable may contain a handle, or an array of handles, as well as other data types. Like Var..Do, you can declare dimensions inside a MetaVar..Do declaration (for example, the dimensions allowed to exist in the array of handles).

When a handle is assigned to a local variable «x» declared using Var..Do, it acts as a hybrid between a localalias an a metavar. In a value context, «x» acts as an alias to the object. However, in an assignment context (an L-value context), the local variable is changed «x», not the object pointed to by «x». Consider:

Var x := Handle(A);
x := x + 1

Here x is first assigned a handle to A. In the assignment operation, when the right-hand side of the assignment is evaluated, x + 1 refers to the value of A plus 1. Hence x acts as an alias to A. The assignment changes the value of the local variable, but does not alter A. After the assignment, the local x contains numeric value (or perhaps array of numeric values) and no longer points to the variable A.

Suppose in the above example that A evaluated to a self-indexed array. The right-hand side of the assignment is a value context, so in this case, x refers to the array-value of A. If we wanted x to alias the index value of A, rather than the array value, we could use the following instead:

Var x := Handle(A, asIndex: true);
x := x + 1

See Also

Comments


You are not allowed to post comments.