Controlling When Result Values Are Cached
Caching of Computed Results
When Analytica computes the result of a variable, it stores the computed value in memory. If that result is requested later, it simply returns the previously computed value without having to recompute it. This process is referred to as caching. The stored result is the cached result.
After Analytica has cached a computed result, it maintains information about what factors went into that computation. If any upstream value is changed, Analytica automatically detects that its cached value may no longer be valid. When this happens, Analytica invalidates the cached result. Only the variables that are or may be influenced by a changed parameter are invalidated. After a cached value is invalidated, that value is no longer stored in memory, and thus next time it is needed, Analytica must recompute it. This system of remembering what each result depends on is referred to as dependency maintenance. As a user of Analytica, you seldom need to worry about making sure values get recomputed when things change -- the dependency maintenance subsystem takes care of it for you automatically.
Analytica actually caches up to three separate results for each variable: The mid value, sample value and index value. Some of these may not apply to particular variables. In practice, it is the mid value and sample value that have the potential to consume subtantial amounts of memory.
Many benefits emerge from the automatic caching of results. Some computations are automatically made dramatically more efficient, since intermediate variables don't need to be recomputed by every child variable that uses the result. In some dramatic cases this can actually convert an exponential algorithm into a polynomial one, with no effort from the modeler (in effect, it automatically converts to a dynamic programming algorithm). When you are examining or debugging the results of a model, the ability to see the values of intermediate variables can be extremely helpful. Not only are these readily accessible without additional recomputation, but you see exactly the values (including the precise Monte Carlo samples) that were used during the computation of downstream results.
Analytica caches results at the resolution of variables. Intermediate results used during the evaluation of a definition live only as long as their values are used, and then their memory is reclaimed. It is only when a variable object's mid or sample value completes is that value cached. These are stored in the midValue and probValue attributes of the object. Only variable objects, and objects subclassed from Variable (Decision, Chance, Objective, Index, Constant) are cached. In particular, the values of User-Defined Functions are never cached, even if they have zero input parameters.
Controlling which results get cached
One aspect of automatic caching of results is that it essentially trades memory for speed. The downside arises when available memory is limited. Caching all intermediate results in your model consumes memory, which may limit the scale of computation you can complete without the available memory resources of your computer. By eliminating some cached results, it may be possible to free up memory for use elsewhere in your model. This is the motivation for controlling what gets cached.
You can impact how much data is cached through various restructurings of your model. You seldom want to do this if you can avoid it, since it may impact transparency of your model. But when in desperation, such restructurings are sometimes warranted.
Restructurings intended to reduce the amount of cached data are based on principles. The first is that only final results of variables are cached -- not intermediate results. The second is that User-Defined Functions never cache their results. Thus, when you want to eliminate the memory caching overhead of an intermediate variable, you can fold it into the expression of its successor and eliminate the variable, or you can just convert it to a User-Defined Function.
Converting to a User-Defined function is easy in theory, since a UDF does not have to have any parameters. With a blank parameter list, it simply evaluates its definition, which can depend on other global input variables. To ensure equivalence with a variable node, your result should not have an implicit dimension (since a UDF cannot promote this to a self-index, given that it doesn't cache its results).
The mechanics of converting a variable to be a UDF are a bit more problematic. There is no user-interface method for converting the class of an object from Variable to Function. In general, you need to do this by adding a function node, copying your definition to it, changing each child of your variable to use the function instead (which involves a syntactic change as well -- adding parenthesis after the function name), and then deleting your original object.
Before going to the effort of enacting these restructurings, it is always wise to run the Performance Profiler to measure the amount of memory consumed by your intermediate variables' caches. There is no reason to eliminate variables that do not consume substantial amounts of memory.
Configuring the CachingMethod Attribute
This section describes an experimental feature that is new to Analytica 4.2.
This feature requires Analytica Enterprise.
Analytica 4.2 introduces a new attribute, CachingMethod, which you can use to specify how results are to be cached for individual variables. CachingMethod is an attribute of variable objects, which can be set to the following numeric values:
- 0 = Analytica's default (this is Always cache)
- 1 = Always cache result
- 2 = Never cache result
- 3 = Release cached result after all children are fully computed
These values apply to both cached mid-value and sample-value results. You can also separately control how mid and sample values are cached, if you have reason to do so, using the following values:
- 18 = Always cache sample, Never cache mid
- 19 = Always cache sample, release mid
- 33 = Never cache sample, always cache mid
- 35 = Never cache sample, release mid
- 49 = Release sample, always cache mid
- 50 = Release sample, never cache mid
Never Cache Setting
When a variable is set to Never Cache its result, then its result must be recomputed every time it is requested. If its parents are cached, those cached value when be utilized, and only the varible's own definition will need to be re-evaluated.
Suppose a variable X is set to never cache its result, and X has two children, Y1 and Y2, both of which use X in their definition. When these are computed, X's definition will need to be re-evaluated at least twice -- once when Y1 is computed, and again when Y2 is computed. It may end up re-evaluating X many more than just two times. Suppose Y1 is defined as X+X. In this case, X will be re-evaluated twice during the evaluation of Y1. You can avoid that extra work using:
- Var x:=x do x+x
which temporarily stores the value of x in a local variable with the same name.
If you later attempt to view the result window or result graph for X, the user interface will have to re-evaluate X's definition again. While the result window is open, small changes may cause the UI to re-read the result, in which case it may be again re-evaluated. Every time you switch to a different view (e.g., from PDF to CDF), the sample value will be re-evaluated. In exchange for recovering the memory from X's cached value, quite a bit of convenience may be sacrificed. On the other hand, if the intermediate variable is not of primary interest, this may be an insignificant price to pay.
Enable comment auto-refresher