SetEvaluationFlag
new to Analytica 4.6
SetEvaluationFlag( flag, enable, expr )
Sets or resets a flag that has some effect on how Analytica evaluates expressions, and then evaluates «expr» with the indicated flag value. The change takes effect only within the scope of «expr» -- after the function completes, the flag has its original value. This is used primarily for turning on or off certain speed optimizations in cases where those speed optimizations might interact in an undesirable manner with «expr».
The «flag» parameter may be one of the following values:
- "evaluationContext"
- "fastCOMcalls"
- "fastCOMproperties"
These are described in detail in the sections below.
To set a flag, pass True
for the «enable» parameter. To clear a flag, pass False
for «enable».
EvaluationContext
Suppose only one slice of an intermediate result will be retained in the final result. Analytica can reduce computation time by only computing the one slice.
The system variable EnableEvalContextUse controls whether this speed optimization is applied globally to the whole model. It is set to 1 by default. SetEvaluationFlag is used to override this global setting just while «expr» is evaluated.
There are a few potential reasons for disabling this speed optimization. Usually it will be because you have a legacy model that was created prior to Analytica 4.6 (when this speed optimization was introduced), and you find that this optimization changes or breaks something in your model. Hence, you can turn the feature off to retain backward compatibility. You might turn it off globally initially, but then later turn it back on globally and use SetEvaluationFlag to turn it off only in specific places.
If a bug is discovered in the future (i.e., the optimization screws up something), SetEvaluationFlag will provide a way to work around it. Hopefully this won't happen.
Consider the expression, where A
and B
are both indexed by I
, an index with 10 elements.
Var count := 0; Var x[ ] := A; Var y[ ] := B+x; MsgBox( x & ',' & y ); count := count + 1; Uniform( x,y )
The declaration for x
specifies that it has no indexes, it is atomic, within the lexical context of x. Since A is indexed by I
, this requires the expression that follows to be evaluated 10 times, once for each atomic value of A. The same holds for y
. However, the evaluation context optimization allows Analytica to recognize that a second iteration over I
is unnecessary. Hence, the body needs to be evaluated only 10 times. When this completes, count will be 10.
Without the evaluation context optimization, two nested iterations occur. You'll see a MsgBox 100 times, count
will be 100 at the end, and Uniform will have been called 100 times. This illustrates three differences that the optimization can cause in legacy models: Side-effects in the form of interactions with the user may occur fewer times, side-effects in the form of variable assignments (count) may occur fewer times, and the number of calls to random number generation may occur fewer times, this altering the RandomSeed, which in turn will alter the random values sampled during Monte Carlo analysis.
Here is another example. Suppose x
in indexed by I
and J
.
Function F( A : Array[I] ; I : Index ; y : atom) F( x,I,J )[J="profit"]
Evaluating F(x)
by itself requires multiple calls to F, one for each value of J
. But because only one slice of the result is used, the evaluation context optimization will cause F to be called only once. If your function F has side-effects -- writing data to a file or external database, showing the user message boxes, assigning to variables, etc. -- the optimization may be undesirable. You would remedy this using
SetEvaluationFlag("evaluationContext",false, F(x,I,J)[J="profit"] )
And one other example. Suppose A is indexed by I
.
Function F1(x : atom) Function F2(x : atom) := F1( x + I ) F2(A)
Even when x is atomic, x+I
is an array indexed by I, so F1(x+I)
would normally require iteration. But when F2 in being evaluated on the A[I=n]
slice of A, only the I=n slice of the result of F2 will be retained, so within F2, F1 can be called a single time, essentially F2(x+n)
. Again, the smaller number of calls might be an issue if F1 has side-effects.
This case can be addressed either from the calling expression, or from within F2's definition. From the calling expression, we would use
SetEvaluationFlag("evaluationContext",false,F2(A))
This illustrates that the flag applies to User-Defined Functions called directly from «expr», or nested within UDFs called from «expr».
FastCOMcalls
(applicable to Analytica Enterprise or higher)
Suppose you call a method of a COM object that takes 5 minutes to complete.
obj->DoLongComputation(x,y)
During this time, by default Analytica will remain responsive to windows events, such as requests to redraw, moving or minimizing windows, and processing of Ctrl+break. Hence, it is possible to abort this if you get tired of waiting, or decide it is never going to return.
The problem is that there is a lot of overhead involved in processing events concurrently while waiting for the call to complete. If you were to call a method thousands of times, where each call should take microseconds, the overhead may require far more time than the calls themselves. In these cases, it is preferable to turn off concurrent event handling.
{ X is an array with 10K items } obj->veryFastComputation(X)
In this example, 10K calls occur, but each call includes the overhead to set up concurrent event handling, so the 10K calls take a long time. To speed these up, wrap the expression using
[[SetEvaluationFlag("fastCOMcalls",false, obj->veryFastComputation(X) )
In this case, Analytica won't become unresponsive because it has an opportunity between when one call completes and the next starts to handle window events.
If you turn on "fastCOMcalls" and a method takes a long time to complete, Analytica will be non-responsive while waiting for the method to return. This may lead you to (incorrectly) conclude that Analytica is hung.
You can change the global default by setting the system variable FastCOMCalls to 1. If you do this, all method calls outside of SetEvaluationFlag use this default. The system variable and "fastCOMcalls" flag impacts calls to the COMCallMethod function (except in the case where the «concurrent» is true), and to the syntax obj->method(...)
, when this is not followed by an assignment (:=
) operator. It does not impact calls to COMGetProperty, COMPutProperty, or calls using the syntax obj->property
-- with no parenthesis after the property name -- or
obj->property(...) := expr
-- which is equivalent to COMPutProperty.
FastCOMproperties
The "fastCOMproperties" flag controls whether event handling occurs while reading or writing the value of a property of a COM object. In the absence of SetEvaluationFlag, fast is the default. It is assumed that setting or getting a COM properties is a fast operation, so by default the overhead of concurrent evaluation is skipped.
If a COM object takes a long time to return or set a property value, Analytica will appear to be unresponsive while it is waiting. You won't be able to move or minimize the window, it won't repaint, or respond to user input in any way, and there is no way to abort the evaluation before it completes. To prevent Analytica from appearing non-responsive, you can disable this flag:
SetEvaluationFlag("fastCOMproperties",false,
obj->slowProperty
)
This adds overhead that may slow down evaluation, so you don't want to do this for properties that are going to be read many times. This setting applies to these cases:
- Calls to COMGetProperty, except in the case where the «concurrent» parameter is set to true.
- Calls to COMPutProperty, except in the case where the «concurrent» parameter is set to true.
- Evaluations of
obj->property
, where the property name is not followed by a parenthesis.
- Evaluations of
obj->property := expr
- Evaluations of
obj->property(item) := expr
See Also
Enable comment auto-refresher