Lsd Equations Macro Language
See the Introduction to Lsd macro language
for
equations. Lsd accepts also pure C++ with the actual Lsd functions
expressed
in pure C++ (most models are expressed in this language. Refer to the manual
for the original Lsd language.).
Search the function of interest below, considering that most of them
are part of a family with post-fix -L, -S, -LS. For example, the
function
V(...) is part of a family of function together with VL(...), VS(...)
and
VLS(...).
Return values | Return Objects | Modify Values | Edit Model Structure | Other elements |
V | ADDOBJ | WRITE | ADDOBJ | v[n] |
STAT | RNDDRAW | INCR | DELETE | CURRENT |
SUM | RNDDRAWFAIR | MULT | SORT | p-> |
WHTAVE | SEARCH_CND | CYCLE | c-> | |
MAX | SEARCH | init_lattice(...) | cur, cur1, cur2... | |
INCR | update_lattice(...) | up->, next->, etc. | ||
MULT | model specific objects | |||
Random and math functions | Advanced coding (debug, memory
management, "object->hook", ) |
|||
V_CHEAT | Basic C++ | |||
INTERACT |
Lsd Equations
A simulation run consists in a sequence of time steps, during each
of which every Variable of the model is "updated". That is, a piece of
code is executed, normally returning a numerical value that is
associated
to the Variable for that time step. The Lsd equations are these pieces
of codes.
The code for the equations are separated in blocks (see below). They
are located all in a file, called the equations' file, which is then
compiled
together with the rest of the Lsd source code. Normally, this is doen
using
LMM, and therefore the user should find the equation file automatically
prepared.
The only required lines in the equation file are the following:
#include "../src/fun_head.h"
MODELBEGIN
MODELEND
void close_sim(void)
{
}
The user should place the equations only after the keyword MODELBEGIN and before MODELEND . Placing the keyword DEBUG before the first equation's code (but after MODELBEGIN begin) the simulation run will write a file called "log.log" where all the Variables' equations computed are listed with some relevant information. Of course, this slows down sensibly the simulation, but it may be useful to find errors, since the last Variable computed before a crash will be the likely faulty one.
Every type of Variable has its own equation, although a model normally contains many copies of a Variable. In this cases the same piece of code is executed, as many times as many copies of the Variables, but, of course, the values used in each execution may change. In fact, Variables are located in Objects, so many copies of the Objects contains the copies of the Variables. The equations' code always refer to an Object. For example, suppose an Object Firm contains Variable Q and Variable K. If there are many copies of Objects Firm's, each equation of Q, that uses K for its computation, will refer to its own copy of K, that is, the copy of K in the same Object containing the copy of Q currently under computation.
The equations' code for all the Variables are located in the same file. The order in which the equations appear in the file is irrelevant, since the system automatically decides which Variable needs to be executed. Therefore, each equation must be thought of as a difference equation, written independenlty from one another, and computed at the generic time t:
The code for a (type of) Variable can be expressed in two forms:
EQUATION("VarLabel")
/*
Normally here should be place a comment,
specifying what the equation does
*/
RESULT(3) //This equation assigns always the value 3 to any copy of Variable VarLabel
The first line indicates that the code refer to the Variable
labelled
VarLabel. After the initial line normally it is placed a comment
(highlighted
in green). The following lines can contain any Lsd (or C++) code. The
last
line must be indicated with the keyword "RESULT(...)" where, in between
the parenthesis, is contained the value that the Variable is assigned.
The EQUATION("VarLabel") line indicates that the Variable
must be computed once and only once at every time step. Therefore, for
example, if a Variable uses its values in many other equations, than it
returns always the same value. That is, the number VarLabel at time t
is
always identical.
Lsd offers numerous functions to express the equations. The most frequently used is V("Var_or_ParLabel") that simply compute the value of another Variable or Parameter in the model. When the computations required for an equation (or a function) are slightly less than trivial, it is common to use local variables where to store intermediate results. For example, consider the following equation:
EQUATION("PROF")
/***************************
The equation computes the profit rate:
PROF(t) = P(t) * A(t-1) -C -RIM - RIN*Inn
profits per unit of capital are equal
current
price times lagged productivity
minus the cost for research (innovative firms
spend for both type
of research) and fixed costs.
***************************/
RESULT(V("Price")*VL("A",1) - V("C") - V("RIM") - V("RIN")*V("Inn"))
It may be preferred to store the intermediate values used in the final computation in local variables, called v[0], v[1], v[2], etc.:
EQUATION("PROF")
/***************************
The equation computes the profit rate:
PROF(t) = P(t) * A(t-1) -C -RIM - RIN*Inn
profits per unit of capital are equal
current
price times lagged productivity
minus the cost for research (innovative firms
spend for both type
of research) and fixed costs.
***************************/
v[0]=V("Price");
v[1]=VL("A",1);
v[2]=V("C");
v[3]=V("RIM");
v[4]=V("RIN");
v[5]=V("Inn");
RESULT(v[0]*v[1]-v[2]-v[3]-v[4]*v[5])
This system has several advantages. Firstly, the code generally is more readable using shorter symbols for values. Secondly, the intermediate values can be observed using the Lsd debugger, so to trace errors. Thirdly, if a value is used many times in the same equation, instead of re-calling the function providing it it is faster to store the value in a v[...] local variable and just re-use it.
Besides local variables for intermediate numerical values, it is also available a group of local "pointers": cur, cur1, cur2, etc. These are used to store objects managed in the equation. Typically, when creating new Objects one may want to initialize the Parameters of the newly created Object. This is made storing the new Object in a temporary pointer, and applying to it the Lsd functions required. For example, the following lines in an equation create a new Object of type Firm and set to 0 its K Variable (see details in the description of the Lsd functions listed above).
...
cur=ADDOBJ("Firm");
WRITELS(cur, "K",0,t);
...
Most of the Lsd functions, like WRITE or V used above, come as a family where the name of the function can be expressed with no post-fix, "L", "S", and "LS" as post-fix. The post-fix "L" stands for Lag, indicating that the operation must refer to past values. The post-fix "S" indicates a Specific object. Consider that any Lsd operation is performed at a given time step in a given equation. Therefore, the time "now" and the Object containing the Variable whose equation is executed are used as default, and no post-fix needs to be used. Otherwise, for operations that must refer to past time steps, or to Objects different from the one containing the Variable whose equation is executed, the modeller must use the post-fix version of the Lsd functions and provide the necessary details:
Variables associated to an EQUATION are computed once and only once
at each time step. That is, the value of a variable can be used by
another variable in the model, by many other variables, or by no
variable at all. In any case, the system ensures that the code of the
equation is computed at each time step. If, in the same time step, the
value is requested more than once, then the system does not recompute
the equation but returns directly the same value computed before during
the same time step.
In some, rare, cases, a Variable should be recomputed
every time it is requested, even in the same time step, but should not
be computed if no variable request it.
This is, for example, the case of a Variable
computing an identification value that must differ for any object. For
example, suppose that in the model a firm can generate, with some
probability, a spin-off, that is, a new firm. Moreover, each firm must
have a unique IdFirm value. It is possible that during the same time
step many new firms are created, or none. To generate an identification
number unique for each firm it is possible to use the following code
FUNCTION("IdGenerator")
/*
Generate new values any time this variable is
requested
*/
RESULT(CURRENT + 1)
Objects in the equations' code
Most Lsd functions are operated by an Object, in the case above (and
almost always) by p->. The
reason
why (most of ) Lsd functions are operated by Objects is that the same
equation
code is, in general, used by many copies of the Variable it refers to.
For example, consider a model with an Object Firm containing Variables
Profit, Price and Quantity, and the equation for Profit is (neglecting
the temporal index):
Caller Object: c
In most of cases equations computing some Variable's values are
executed
because other equations needed those values. This object in an equation
contains the pointer to the Object that caused that equation to be
computed,
if any ("c" reads for "caller"). If an equation is computed only
because
the system requested so, and no other equation triggered the
computation,
then c is NULL, a conventional value.
Typically the object "c" is used in FUNCTION's,
since these are not computed unless another equation requested their
computation. As an example example, the following function generates a
random value from a poisson random function, with the mean value taken
from the parameter "mean" stored in the
Temporary Object's pointers:
cur, cur1, cur2, ...
These elements are pointers to Objects, used to store temporary
required
Object (like v[n] is used to stored temporay
numerical
values). Typically, the user applies to p->, or c-> a Lsd
function returning
Objects, assigning the result to cur.
Then uses cur to apply a function
returning values, or modifying values. See any example of the Lsd
function returning Objects.
object elements: up->,
next->,
son->
The information in this paragraph is not necessarily relevant for
writing
Lsd models. But it explains the technical implementation of a Lsd model
that can be used to optimize a model's code.
Every Object (for example, p, c etc.) is related to its neighbours
in the model hierarchy. Every Object can therefore bring to its
neighbours
using the links to them. The links are determined with the following
components
of each Object:
up
/\
||
--------
|object | => next
--------
||
\/
son
The fields above are proper Objects, and therefore can be used to
run
Lsd functions. For example, consider a model where you have 100,000
Objects
Firm descending from a single Object Market. If a Variable in Firm uses
a Parameter in Market, say Price, you can write the line
v[0]=V("Price");
but it will take a lot of time to work out, because the system will
have to visit and discard all the Objects Firm before moving "up" to
check
in market. In fact, the function V(...)
will search in Firm for
a Variable or Parameter Price. If it does not find it, it will look if
it can be found after the set of Firm, descending from the same Object.
Which means to skip through 100,000 objects, for the first firm, 99,000
for the second and so on. Instead, using the line:
v[0]=VS(p->up,"Price");
returns directly the desired value, since the first Object searched is p->up, which is Market. Note that the modeller must be sure that objects fields use exists. If, in the example above, the equation is placed in Root, no up-> Object exists, and the simulation will issue an error.
Model specific objects
The Object pointers saw above (p->, c->, cur-> etc.) are all
"local"
Objects, in the sense that they represent a different content depending
on the Variable in whose equation they are used. That is, they refer to
Objects that, depending on the Variable whose equation is computed,
change
their content when the Variable computed changes: p-> refers to the
Object
copy whose Variable is computed; c-> to the Object that caused the
Variable
to be computed; cur-> and the others are assigned within the
equations
code.
However, the modeller can create and use "global" Object pointers,
that is Object that never change the content throughout a simulation
run.
This is mainly done for optimization purposes, when a very large model
(many Objects) contain Variables that refer frequently to one specific
Object copy. The use of global Object should be avoided by
unexperienced
modellers, because it risks to create error difficult to be captured.
To use a global Object, declare the Object outside the scope of the
equation function, on the top of the equation file before the line:
MODELBEGIN
the declaration line must be something like:
object *market;
where the name of the Object ("market" in the example) must not be one of the existing Objects (p, c, cur etc). The Object must be assigned with one of the Lsd equation functions returning Objects within an equations code. For example, there may be a Variable called init making such assignements. For example, it may be:
EQUATION("Init")
/*
Technical initialization function. It is
computed only once and then it is
transformed in a parameter and never computed
again.
Sets the global pointer 'market' pointing
to the Object Market, so
to speed up the access to this object
*/
market=SEARCH("Market"); //assign the C++
object pointer "market" to point to the Lsd Object Market
param=1; //optional; transform "Init" in
a parameter so to not compute again this equation.
RESULT(1)
The Variable Init must be computed for sure before market
is used in any other equation. This can be ensured placing Init in
the Object Root, since the simulation step starts always the
computation
from the Variables contained in the top of the model structure.
With the setting described above, the modeller can use "market" as
any other Object, knowing that it refers always to the Lsd Object
Market.
For example, the equation for a Variable placed anywhere in the model
may
use the line:
v[0] = VS(market,"Price");
and be sure that the value of Variable Price is returned quickly. Note that also the conventional line
v[0] = V("Price");
would work. But it would cost a lot of time in case the Variable
whose
equation containing the line for Price is placed very "far" from
Market.
Modellers using global Objects should be careful when assigning
configurations
with many copies. If, for example, the model configuration uses many
copies
of Objects Market, any use of the global object market
would
refer only to the very first copy.
V("Lab"), VL("Lab",
lag),
VS(obj,"Lab"), VLS(obj,"Lab",lag)
This is the most used Lsd function. It returns the value of the
Variable
or Parameter with label Lab. The forms
VL(...)
and VLS(...) permit to specify a lag, so that the values returned
concern
the value of Lab with lag
lags. The forms VS(...) and VLS(...) specify in which Object the
Parameter
or Variable must be searched for. In V(...) and VL(...), where no
Object
is specified, the search starts from p (see
available Objects).
In case the model contains many instances of Variables with the same label Var (that is, many instances of Object containing this Variable), the function returns the value of the instance "closer" to the Object where the search start from. By closer, it is meant the first instance found by searching the model using the following strategy:
1) Search in the Object object (the
one specified in the function call);
2) Search in the Object(s) descending from object;
3) Search in the parent Object of object;
In each Object explored, the same strategy is applied recursively, so that every Object in the model is visited, if necessary. So, for example, if there is only one instance of Variable Varin the model, this can be found whatever Object is used to start the search.
Example
Consider the equation Qt = Kt-1 * At
The code will be as follows:
EQUATION("Q")
/*
Compute
the quantity Q as the product of lagged capital K and current
productivity
A
*/
RESULT( VL("K",1) * V(A) )
or, equivalently:
EQUATION("Q")
/*
Compute
the quantity Q as the product of lagged capital K and current
productivity
A
*/
v[0]=VL("K",1);
v[1]=V(A);
RESULT( v[0]* V(A) )
In the second case the two temporary variables v[0] and v[1] are used to store the intermediate results, which can be observed during a debugging session, so that modeller can trace possible unexpected results.
This function is used for sophisticated coding. When the standard V(...)
requests the value of a Variable, when this Variable equation is
executed
it can access the Object containing the caller Variable (Object c).
However, in some cases, mostly for reasons of efficiency, it may be
useful
to "cheat" the requested Variable in believing that the Object is
something
else. With V_CHEAT the modeller must specify another Object (fake_caller)
that will appear in the called Variable as if it were the "caller".
This function searches, with the same strategy described in V(...) (see also the different forms), an instance of the Variable Var. Then, it keeps on summing up all the values of Variables Var (with the lag lag if specified), found in the set of Objects contiguous to the one found. Normally, it should be used to sum up the values of descending Objects. For example, if Q_TOT is contained in an Object Market, from which descend a set of Objects Firm containing Variables Q, its equation can be:
EQUATION("Q_TOT")
/*
Compute
the sum of all Q's in the market*/
RESULT( SUM("Q") )
Note that, if your model contains many Objects Market, this equation
will sum up only the Q's contained in the set of descendants of Market,
and not all the Q's existing in the model.
MAX("Lab"),
MAXL("Lab",
lag), MAXS(obj,"Lab"), MAXLS(obj,"Lab",lag)
Same as object->sum(),
but returns the maximum value instead of the sum.
WHTAVE("Lab1","Lab2"), WHTAVEL("Lab1", "Lab2", lag), WHTAVES(obj,"Lab1","Lab2"),WHTAVELS(obj,"Lab1","Lab2",lag)
Same as object->sum(), but returns the weighted average of a Variable or Parameter, that is the sum of the products between the values of Lab1 times Lab2. Of course, both Variables need to be contained in the same type of Objects.
STAT("Var"),
STATS(obj,"VAR)
This function does not return a value as the ones above, but stores
a set of values in the vector v. It
works
as the function SUM, and the like, but computes a
set
of descriptive statistics. Namely, it places in v
the following values:
v[0]=number of elements;
v[1]=average of Var
v[2]=variance of Var
v[3]=maximum values
v[4]=mininimu values
SEARCH_CND("Lab", val), SEARCH_CNDL("Lab", val, lag), SEARCH_CNDS(obj, "Lab", val), SEARCH_CNDLS(obj, "Lab", val, lag")
This method is used to find an Object in the model that contains the Variable Lab with value val (considered the lag lag). Basically, it uses the same strategy to explore the model as described in function V(...) above. Only, it does not stop to the first instance encountered, but continues until the searched Variable is not found with the desired value. When an Object that satisfies the condition is found, it is returned to the calling equation, and can be used to activate other Lsd functions, like V(...) .
The function is used to identify a particular Object, which is neither p nor c. For example, suppose you want to extract randomly a Firm from a group of 100 instances, and that these contain a Parameter IdFirm set from 1 to 100, you can use the following code:
v[0]=rnd_integer(1,100)
cur=SEARCH_CND("IdFirm", v[0]);
SORT("LabObj", "Lab",
"Direction"), SORTS(obj, "LabObj", "Lab", "Direction"), SORT2("LabObj",
"Lab1", "Lab2", "Direction"), SORTS2(obj, "LabObj", "Lab1", "Lab2",
"Direction"),
This function sorts (with the quick sort method) a set of Objects
labeled
LabObj
according to the values of Variable
Lab.
The field Direction must be either
"UP"
or "DOWN". It returns an error in case the Variable
Var,
though defined in the model, is not contained in the Object Obj_Label.
In case there are many sets of Objects with label Obj_Label,
the function sorts only the first set encountered by exploring the
model
with the usual strategy (see V(...) ). If specified,
the
search for the group of Objects to sort start from
obj.
Example:
SORT("Firm","Q", "DOWN");
this line, used in an equation contained in an Object from which
descend
many Object labelled Firm, sorts these descendants according to
decreasing
values of their Variable Q.
The SORT2 function is also available
for ranking on two dimensions:
SORT2("AnObject","X", "Y", "UP");
In this second case the Objects are sorted according to their
increasing
values of X. If two or more Objects have identical values on X, then
the
Variable or Parameter Y is used to sort them.
For example, you can have an equation for a Variable in the Object Market that contains the following lines:
cur=ADDOBJ("Firm");
WRITE("DateBirth",(double)t);
The lines above create a new Object Firm, which has the same initial data as the first Object in the model file. Then it modifies the Parameter DateBirth, storing there the current time step. Note that the C++ variable t, expressing the time step of the simulation, is an integer Variable, and therefore needs to be explicitly declared as double (that is, double precision floating point variable in C++), because all the numerical values in Lsd are real numbers.
As a second example, suppose that in the Market Object is contained a Variable A_MAX containing the maximum productivity. The following lines identify the Object Firm with the maximum productivity and produce a new Firm with the same initialization of this Obejcts:
v[0]=V("A_MAX");
cur=SEARCH_CND("A", v[0]);
cur=ADDOBJ_EX("Firm", cur);
The first line obtains the value of the highest productivity among the existing Firms. Then, the function SEARCH_CND(...) returns the Object that has the same productivity as the maximum one. This Object is used as example for the creation of the new Firm. Note that the same temporary variable cur is used, firstly, to store the most productive Firm and then, both as example Object and as the new Object. This may seem strange to whom is not accustomed to C++, but it is perfectly safe. In fact, the content of the temporary variable cur has already been used when the function returns the newly created Object.
If the added Object is set to save its values, these are available
for
post-simulation Analysis of Result. The data concerning the periods
before
its introduction are filled with missing values.
Warning:
The newly created Object must be added to a parent Object (that is,
object->)
which is already defined as having Obj_Label
type of descendants.
DELETE(obj)
This function deletes the Object obj
from the model, removing it from the model and freeing the memory it
was
allocated for it. While its use is very simple, it should be used with
care to avoid the elimination of data structure used in other parts of
the model. The data produced by the Objects and saved are available for
the Analysis of Result
The data stored in the deleted Objects are always available for
analysis
at the end of the simulation, filling with missing values the periods
after
the deletion.
WRITE("Lab",
new_value),
WRITEL("Lab", new_value, time), WRITES(obj, "Lab", new_value),
WRITELS(obj,
"Lab", new_value, time)
This function writes the value new_value
in the Variable or Parameter Lab.
In case of Variable, it possible to make appear as if the
time
of latest computation for the overwriten Variable is time.
That is, after to function is executed, the Variable Var
will result as if its last computation had been executed at time time,
and the result of the equation were new_value.
If the label Var corresponds to a
Parameter,
the field time is ignored. The Variable must be contained in the Object
obj,
(or in p if obj not
specified), otherwise the functions returns an error and stops
the
simulation.
This function can be very useful to implement complex situations, but
it should be used with extreme care because it disrupts the automatic
system
of controls for the execution of the equations. If the function
concerns
a Parameter, the field time is
ignored. The most frequent use of write
concerns the initialization of newly added Objects.
SEARCH("Obj_Label"),
SEARCHS(obj, "Obj_Label")
This function explores one single branch of the model searching for
the first instance of the Object Obj_Label.
That is, it searches only within the descendants of obj,
if specified, or in p if obj
not
specified, and their descendants. Therefore, the search is not
exhaustive
over all the model, unless it is started from the Root
of the model. It returns the address of the found Object or NULL if no
Object is found.
v[n]
The standard way to express an equation is to collect a set of data
from the model and then to elaborate them to provide the desired value.
Since the Lsd function to collect data may be quite long, it is good
practice
to store values to be used in a numerical vector. See the Introduction.
The values of v[n] are reset
for each equation, and therefore cannot be used to transfer information
from one equation to another.
CURRENT
This keyword contains the current value of the Variable under
computation, irrespective of the time of last computation of the
variable.It is the same value that can be obtained with the function VL("VarLabel",1),
used in the equation for VarLabel. The result of the equation will be
reported
in CURRENT at the subsequent time step.
Example:
EQUATION("VarX")
/*
This
function
returns a progressive value each time it is requested
*/
v[0]=CURRENT;
v[1]=VL("VarX",1);
/* v[0] and v[1] are identical */
RESULT(v[0])
This can be used even when a variable is not defined to store past
values, since it accesses directly the C++ memory location storing the
variables' values.
INCR("Lab",
value),
INCRS(obj, "Lab", value)
This function works only if VarLabel
is contained in obj, or in p
if obj not specified,
otherwise
produces an error. It adds to the current value of Lab
the value of value. The
function
returns the new value after the increment. This function should be used
only with Parameters, for the same reasons explained in the functions WRITE.
MULT("Lab",
value),
MULTS(obj, "Lab", value)
This function works only if VarLabel
is contained in obj, , or in p
if obj not specified,
otherwise
produces an error. It multiplies the current value of VarLabel
times the value of value. The
function
returns the new value after the product.
Math and other
functions
Besides the Lsd specific function modellers can use one of the
following
random and mathematical functions. Of course, it is always possible to
declare new functions or link to the Lsd model any C++ library.
RNDDRAW("ObjLabel",
"VarLabel"), RNDDRAWL("ObjLabel", "VarLabel", lag), RNDDRAWS(obj,
"ObjLabel",
"VarLabel"), RNDDRAWLS(obj, "ObjLabel", "VarLabel", lag)
This function searches for a group of Objects ObjLabel,
and returns the pointer to one of them chosen randomly with probability
proportional to the values of VarLabel.
obj
can
specify where the search must start from. lag
can
specify the lag to use for the values of VarLabel.
EXAMPLE
Consider the equation for DrawAFirm which has to return the value of
Parameter IdFirm in one of the Objects Firm descending from the Object
where DrawAFirm is contained in. The equation will be:
is specified the starting then computes the values of VarLabel
for each of them. It returns the address of one of the Objects of the
group
chosen randomly with probability linearly dependent on the value of VarLabel.
The version of the function with total assumes that the latter value is
equal to the sum of all VarLabel in the group, and is faster.
The following example c an equation for a Variable stored in an Object
that contains a group of descending Objects Firm. The code assigns to
the
Parameter Prob in each Firm the square of their market shares and then
draws randomly one of them, returning its identification number.
EQUATION("DrawAFirm"))
/***************************
Return the Id of a Firm chosen randomly with
probability
equal to the square of the market shares.
***************************/
CYCLE(cur, "Firm")
{
v[0]=V("ms");
WRITES(cur,"Prob",v[0]*v[0]);
}
cur=RNDDRAW("Firm","Prob");
RESULT(VS(cur, "IdFirm")
RNDDRAWFAIR("ObjLabel"),
RNDDRAWFAIRS(obj, "ObjLabel")
This function is identical to RNDDRAW but uses
the same probability for any object. For example, the
following equation returns a the parameter IdFirm from a randomly
chosen
object Firm.
EQUATION("DrawAFirm"))
/***************************
Return the Id of a Firm chosen randomly with
identical
probabilities for each object
***************************/
cur=RNDDRAWFAIR("Firm");
RESULT(VS(cur, "IdFirm")
Can be used embedded CYCLE's , provided that the pointers differ for the different cycles. For example, consider a model including Objects Market containing Objects Firm. An equation in an object containing a set of Market, for example representing a country, can use the following code:
v[0]=0; //set to v[0] to be initially 0
CYCLE(cur, "Market")
{//for each market
CYCLES(cur,cur1, "Firm")
{//for each firm, contained
in cur
v[1]=VS(cur1,"Profit");
v[0]=v[0]+v[1];
}
}
//from here v[0]contains the cumulated profits
The cur pointer cycles through all Market's. For each Market
the pointer cur1 cycles through each Firm. For each Firm,
v[1]
contains the value of Profit which is cumulated in v[0].
WARNING: Never use DELETE(cur) in a CYCLE.
In fact, deleting the objects pointed to by cur prevents the CYCLE
from identifying the next one. Instead, use the command CYCLE_SAFE(cur,
"ObjLabel"). In this case, it is possible to delete the cycling
pointer
cur.
but it is not possible to nest different cycles.
The example below is a mistake because cur1 is deleted within a CYCLE
command
ERROR - ERROR -ERROR
CYCLE(cur, "Market")
{//for each market
CYCLES(cur,cur1, "Firm")
{//for each firm, contained
in cur
v[1]=VS(cur1,"Profit");
if(v[1]<0)
DELETE(cur1);
}
}
//from here there are no Firm with negative
profits
ERROR - ERROR -ERROR
Instead, it should be:
CYCLE(cur, "Market")
{//for each market
CYCLE_SAFES(cur,cur1, "Firm")
{//for each firm, contained
in cur
v[1]=VS(cur1,"Profit");
if(v[1]<0)
DELETE(cur1);
}
}
//from here there are no Firm with negative
profits
This function must be used only once in each simulation run and never again. Updates to the lattice colors can be applied using the update_lattice(...) function.
This function inserted in an equation allows the run to be modified according to the choice of an interacting user. For example, an equation may contain the following code:
v[1]=V("MinMarketShare");
//minimum
m.s. below which a firm should be removed
CYCLE_SAFE(cur, "Firm")
{//Cycle through each firm, allowing
for the removal of the pointer.
v[0]=VS(cur,"MarketShare");
//read
the market share
if(v[0]<v[1] )
v[5]=INTERACTS(cur, "Remove
this firm? (1=yes; 2=no)", v[4]);
if(v[5]==1)
{//remove if the answer
was 1
DELETE(cur);
v[3]++;
}
}
This cycle removed all firms having market shares smaller than a given value and that the user permitted to kill.
Beware that such a function used in a model requires the user to interact with it.
The commands listed here provide special operation rarely used. They
should concern only advanced programmers.
close_sim()
At the end of each simulation run modellers can execute some specific
code. Typically, this is used to free some memory allocated during the
simualation run. At the end of the file for the equation is located the
function close_sim() where such code can be placed. By default this
function
does nothing.
PARAMETER
This command within an equation transform the Variable in a Parameter,
so that the equation is never computed again during the simulation run.
Normally, this is used in equations meant to initialize a model at the
very first time step, and does not need to be computed during a
simulation
run.
global variable 't'
This variable indicates the current time step of the simulation. Note
that this is an integer variable, so that to assign its value to one of
the Lsd function, requiring real numbers, it is necessary to use a
cast.
For example:
v[9]=(double)t;
DEBUG_AT(XXX)
This function placed in the equation files is used to spot the
equations
that causes a crash of the program. It serves to tell the modeller
which
equation caused the crash.
This function must placed just aftet the command line MODELBEGIN and
causes the system to enter in a special running mode at time XXX
(and to remain so onward). Any time a variable needs to be computed
after
the specified time step the system opens a file called log.log and
writes the name of the variable and the time step. So, for example, if
an equation file begins with the code:
#include "fun_head.h"
MODELBEGIN
DEBUG_AT(2)
...
then we will find in the log.log file all the variables
computed.
obejct->hook
Lsd modellers need not to write programs, but just the code to
compute the values of variables. The Lsd functions available allow to
read the values of the model and/or to modify it. The elaboration of
the variables' equation can use any C++ legal command. Here we present
the most basic (and frequently used) commands. Remember that the code
to compute a variable's value is executed sequentially when the system
requires that variable to be updated. At the end of the equation's
computation the system assign the value to the variable and then moves
to compute another variable.
The code is composed by lines of
commands that the computer generally executes sequentially, moving to
the next line when the previous one has been completed.
Any line of code must respect the C++ rule of terminating with a
semi-colon ``;'', unless the line is a multi-column Lsd command like EQUATION, or C++ command, like if(condition).