Constraints take the form
name :THE CONDITION: condition :IMPLIES: consequence
:THE CONDITION: and :IMPLIES: are special keywords in Vensim. condition and consequence are logical expressions described below. The name of a Constraint must use letters and numbers just as other variables in Vensim. Constraints do not need units of measure, though if you are using the Text Editor you must put in the tilde symbol ~ as a placeholder. You can attach comments to Constraints just as you do with other variables in Vensim.
Logical Expressions
Constraints use a condition and a consequence that are both defined as logical expressions. An example of this would be:
no capital no production :THE CONDITION: Capital = 0 :IMPLIES: |
production= 0 |
When testing Reality Check equations, Vensim will force a condition to be true whether the model generated values suggest it should be true or not, and test the consequence for truth. When the condition is true, but the consequence is not, Vensim reports the problem as a Reality Check failure. Vensim also does passive testing as described below.
Logical expressions can be more complicated then this. They are built up by using the comparisons =, >, <, and <> along with :OR:, :AND: and :NOT:. A valid logical expression could be:
Population > 8E9 :AND: (food ratio < .75 :OR: |
Pollution > critical pollution) |
Here a number of things are being compared and this expression will be true if Population > 8E9 and either food ratio < .75 or Pollution > critical pollution or both. Logical expressions can quickly become difficult to understand and you are encouraged not to combine too many things in a condition. In the consequence portion, it is often useful to have many items combined with :AND:s (to test several consequences of a single condition), but more complicated structures are rarely helpful.
The condition portion of a Constraint definition is restricted to the comparison of variables to other variables and variables to numbers. The only exception to this is that you can use var=expr, or a named Test Input as one of the condition's logical components. Thus:
pop lt cc :THE CONDITION : Population < Carrying Capacity * 1.1 |
:IMPLIES: deaths from crowding < 1000 |
is wrong because it takes the form var<expr, whereas
pop lt cc :THE CONDITION : Population = Carrying Capacity * 1.1 |
:IMPLIES: deaths from crowding < 1000 |
uses var=expr and is a legitimate expression. Expressions included directly in Constraint conditions in this manner can use TIME TRANSITION and must conform to the rules for forming Test Inputs.
Test Inputs may be used for the condition of a Constraint, as in:
pop lt cc :THE CONDITION : pop at cc plus 10 |
:IMPLIES: deaths from crowding < 1000 |
where pop at cc plus 10 is a Test Input. Note that Test Inputs are treated as logical variables taking on a value of true if they are active and false if they are not.
All components of a Constraint are restricted to using simple functions (MIN, MAX, SUM etc.). Other than this, there is no restriction on logical expressions in the consequence portion of a Constraint definition.
It is not generally useful to test equality in a consequence because equality tests are very likely to fail even when there is nothing wrong with the model. This is because even for concepts that are definitionally equivalent, but computed in different manners, there are likely to be slight numerical differences which will be flagged during an equality test.
Dynamic Tests in the Consequences
Reality Check equations that have Test Inputs using RC... functions typically use a corresponding RC...CHECK function in the consequence. The RC ... CHECK functions work in an analogous way to RC... functions in Test Inputs. While Test Inputs change the value of a variable, the consequence portion of a Constraint makes a comparison of the value of a variable. The RC...CHECK function takes one more argument than the corresponding RC... function. This argument is the grace period and it allows a delay after a Test Input occurs before the consequences are tested. For example:
TI Production to zero :TEST INPUT: |
production = RC STEP(production,0) |
RC No Production no Shipments :THE CONDITION: |
TI Production to zero :IMPLIES: |
sales <= RC RAMP CHECK(.5,sales,.0001) |
The Test Input causes production to step to zero at RC START TIME. After a grace period of .5 sales is checked to see if it is less than or equal to .0001 times the value it had at RC START TIME. The use of .0001 instead of 0 prevents nuisance violations that might occur with continuous formulations and is good practice.
The grace period is the first argument to all the RC...CHECK functions except for RC COMPARE CHECK which takes uses the literal name of a file first.
:CROSSING:
In the implication portion of a Reality Check you can use :CROSSING: and :AT LEAST ONCE: with > and < to look for above/below type relations, as in:
... :IMPLIES: |
Inventory > :CROSSING: RC STEP CHECK(0,Inventory,1) |
This will test to be sure that at RC START TIME Inventory is first bigger than its baseline value and then becomes smaller and stays smaller. If there were two :CROSSING: keywords in a row as in:
Inventory > :CROSSING: :CROSSING: RC STEP CHECK(0,Inventory,1) |
Inventory would need to start bigger, then become smaller, then become bigger and stay bigger.
If you use one or more :CROSSING: keywords, you can end the sequence with :IGNORE: to indicate that after the required number of crossings have been made, it does not matter if any more crossings occur. For example
Inventory > :CROSSING: :IGNORE: RC STEP CHECK(0,Inventory,1) |
This says that Inventory needs to start bigger, then become smaller, then it does not matter what it does.
:AT LEAST ONCE:
Analogous to the :CROSSING: keyword is a :AT LEAST ONCE: keyword that simply requires that the condition be true once after RC START TIME. For example
Inventory > :AT LEAST ONCE: RC STEP CHECK(0,Inventory,1) |
says that Inventory needs to exceed its value at RC START TIME at least once during the rest of the simulation. It might always be above, or cross from below to above. It the value is above once it can also cross below and the condition will remain true.
Empty Conditions
The condition part of a Constraint may be empty as in:
debt bounded :THE CONDITION: :IMPLIES: debt < 4E6
This equation states that no matter what happens there will never be more than four million in debt. Note that Vensim does not try to test all possible model conditions when it sees an empty condition. Constraints with empty conditions are checked passively anytime you are using the Reality Check function, and will detect a high debt.
For the simple example given here, using 4E6 as the maximum value that debt could take on in the equation for debt would also result in a message when debt exceeds 4E6 as long as warnings are not suppressed. The Empty condition can, however, be used to evaluate much more general expressions.
Wildcard Tests in the Consequence
In addition to testing a variable, you can test all variables to see if they satisfy a condition. To do this use a * instead of a variable name. For example you might write the Constraint
all peaceful :THE CONDITION: FINAL TIME=101 :IMPLIES: |
* < 1E9 :AND: * >= -1E3 |
which will test to be sure that all variables stay in the range -1,000 to 1 billion. The condition FINAL TIME = 101, which simply runs the simulation an extra year, is used instead of the empty condition because this is a time consuming check to make and Constraints with empty conditions are checked passively every time any Reality Check is being made.