4.3 Static and Dynamic References

Requirement for Static Set and Table Names in Basic Operations

The Aspen SCM Expert System interpreter resolves references to the names of sets and tables and to elements of sets when the rule is semi-compiled (i.e. as the interpreter is about to execute the rule for the first time after linking). It accepts variables as the values of row or column elements but not as the name of a set or table. Thus

IF     ?VALUE = ?TABLE(?ROW,?COL)

is not acceptable (?TABLE is unacceptable as a variable name for the table) but

IF     ?VALUE = MYTABLE(?ROW,?COL)

is OK.

Preference for Dynamic References to  Set Elements

Note, however, that

IF     ?VALUE = MYTABLE(ROW1,COL3)

may also be unacceptable if, at the time when the rule is semi-compiled (i.e. when the interpreter starts running the rule), either ROW1 or COL3 does not lie in the row- or column-sets respectively of MYTABLE.

Where the row or column sets are built dynamically (or their members differ between sites where a program is run) this often makes it necessary to use variables to reference the row or column of a table. Thus code such as:

IF      ( ?SITE EQ "UK"
              AND ?TAX = MYTABLE(?ROW,VAT)
           OR ?SITE EQ "FRANCE"
             
AND ?TAX = MYTABLE(?ROW,TVA)
         )

is unacceptable (because the column VAT exists only in the British case while the column TVA exists only in the French one). Even though the code would work when run (because the reference to VAT would only be executed in the case which contained the column set entry VAT; and likewise for TVA), the semi-compiler rejects this because it cannot resolve the reference to VAT in the French case or to TVA in the British case.

Instead this code has to be written as:

IF      ( ?SITE EQ "UK"
              AND ?TAXCOL = "VAT"
           OR ?SITE EQ "FRANCE"
              AND ?TAXCOL = "TVA"
         )
AND     ?TAX = MYTABLE(?ROW,?TAXCOL)

Even where static references appear to work, it is safer to use a dynamic reference if SORT operations are performed on the set to which the static reference belongs (this includes SORTs on tables indexed by the set). Under some circumstances (the precise conditions have not been established but appear to include many SORTs) the interpreter appears to lose track of the current location of the static reference in the set and uses an apparently random one (possibly the position which it had when the rule was linked). It thus accesses a different location from that which it should, causing unexpected behaviour.

Another place where static references are unacceptable is when testing for membership of a set. Even if VAT is a member of the set TABLE.H it is unacceptable to write

AND     "VAT" IN TABLE.H

Instead you must write:

AND     ?TAXCOL = "VAT"
AND     ?TAXCOL IN TABLE.H

Language Constructs Accepting Dynamic References to Sets and Tables

Much of the Aspen SCM Expert System language accepts dynamic references to sets and tables. The following constructs do:

  • ?MYVAR IN ?MYSET   - either as a loop (if ?MYVAR is FREE) or as a test (if ?MYVAR is bound)
  • ?CODE = CODEOF ?MYSET(?INDEX)

  • ?INDEX = INDEXOF ?MYSET(?CODE)
  • ?VALUE = MAXVAL ?MYTABLE(?ROW,?COLUMN)

  • ?VALUE = MINVAL ?MYTABLE(?ROW,?COLUMN)
  • ?SIZE = SETCOU ?MYSET

  • ?SIZE = SETMAX ?MYSET
  • ?SIZE = SIZEOF ?MYSET

Note in particular that the loop constructs work. Thus you can write

AND     FREE ?MYCODE
AND     ?MYCODE IN ?MYSET
AND         ?MYINDEX = INDEXOF ?MYSET(@)

to loop over an arbitrary set and get the value of the index. With this you can then use CODEOF to get the Code and DESCOF to get the Description.

More generally you can find the Description of an arbitrary Code for a dynamic set using

AND     ?MYINDEX = INDEXOF ?MYSET(?MYCODE)
AND     ?MYDESC = DESCOF ?MYSET(?MYINDEX)

Substitutes for Dynamic References which Do not Work

However, other language constructs, often the most basic, do not accept dynamic references to sets or tables, at least not as the location where the result is to be placed. Thus

IF      ?MYSET = "FRED"
AND     ?MYSET = 0

does not null the set FRED. Instead it sets the local variable ?MYSET first to FRED and then to 0.

For some of these language constructs (but not nulling a set) there are equivalent Aspen SCM commands which can be used instead. If you are using versions of Mimi before 6.0, you must ensure that such commands are included in $NOPRED and that $NOPRED has been hashed (which happens automatically if you edit $NOPRED).

Examples of static /E constructs and their equivalent dynamic commands are:

Static /E construct

Dynamic Aspen SCM Command

MYSET(?ELEMENT,D) = ?VALUE

FILL ?MYSET(?ELEMENT,D) = ?VALUE

MYTABLE(?ROW,?COL) = ?VALUE

FILL ?MYTABLE(?ROW,?COL) = ?VALUE

MYTABLE = NULL

FILL ?MYTABLE(*,*) = 0 (or "" for string tables)

MYSET2 = MYSET1

COPY ?MYSET1 INTO ?MYSET2 (true replacement)

MYSET3 = MYSET1 + MYSET2

APPEND ?MYSET2 ONTO ?MYSET1 (doesn’t remove duplicates)

MYTABLE2 = MYTABLE1

COPY ?MYTABLE1 INTO ?MYTABLE2 (but remember to copy the row- and column-sets first)

MYSET(INDEX) = ?MYNUM

SETIND ?MYSET = ?MYNUM

If you have a set with zero elements, NULLSET, you can null other sets by using the statement

COPY NULLSET INTO ?MYSET

but this causes ?MYSET to acquire the characteristics of NULLSET, i.e. its lengths of Code and Description, Type and maximum number of elements. A better way to null a set is to use the MODIFY command:

MODIFY ?MYSET COUNT = 0

A problem with dynamic Aspen SCM commands is that they are processed in a buffer which is about 80 characters long. This means that a command may fail because its syntax is invalid when it is truncated to the buffer length, e.g. a character string which is enclosed in quotes may lose its trailing quote and become meaningless.

Retrieving Values from Dynamic Tables

Values can be retrieved from dynamic sets using INDEXOF, CODEOF and DESCOF and by looping (see above). Retrieving values from dynamic tables is more difficult. The AMPSET command provides a mechanism:

IF      ?DATAREF = '?MYTABLE(?ROW,?COL)'
AND     AMPSET $1 = ?DATAREF
AND     ?VALUE = $1

Care needs to be taken here, because all amper variables are character so ?VALUE will be character even if ?MYTABLE contains numeric data. In such cases the statement

AND     ?VALUE = ?VALUE + 0

should be added to convert ?VALUE to numeric data type so that comparisons (especially with 0) will work as expected.

Note, however, that the use of dynamic Aspen SCM commands such as FILL and AMPSET is inefficient. If there are more than a few such assignments it may well be better to operate on a scratch set or table in the rule and move the data into it at the beginning and copy the data back out at the end.

Using TCHOSEN as a Scratch Table

A very useful scratch table is TCHOSEN which is automatically reformatted, along with its row and column sets TCHOSENR and TCHOSENC by a SELECT statement. However, its very usefulness carries with it dangers. It is liable to be used in many rules so if it is referenced in a loop which calls another rule, it may well have been changed before the loop terminates.

One problem which arises out of TCHOSEN’s ubiquity is that while the syntax for referencing it is usually TCHOSEN(?ROW,?COL) it can have a third argument, i.e. TCHOSEN(?ROW,?COL,?CHARS) if it is a string or panel table. Which is correct is determined at run-time as the interpreter enters the rule with the reference (i.e. the interpreter uses late binding for this rather than LINK-time binding when testing for static references to elements of sets).

It is therefore inadequate simply to execute a SELECT statement on a string or panel table and then reference TCHOSEN(?ROW,?COL,?CHARS). Instead the SELECT statement must either be executed in a jacket routine before entering the rule which accesses TCHOSEN with three arguments or a dummy SELECT statement must be executed on a string or panel table before entering the rule. The same applies in reverse if TCHOSEN is to be referenced with two arguments after a SELECT statement on a string or panel table.

Tokens which End with a Variable

A curious feature of the interpreter is that if a token which appears on the right hand side of an assignment ends with (but does not consist wholly of) the name of a local or global variable, the interpreter will substitute the variable’s value and then pass the result to the command interpreter. Thus statements such as

IF      ?N1 = 1
AND     ?N2 = 2
AND     MYSET = MYSET?N1 + MYSET?N2

work while

IF      ?SET1 = "MYSET1"
AND     ?SET2 = "MYSET2"
AND     MYSET = ?SET1 + ?SET2

and

IF      ?N1 = 1
AND     ?N2 = 2
AND     MYSET = MYSET?N1.S + MYSET?N2.S

do not.

Back                                Next

Comments