Ps-i 2.4 - routines

General description

A routine are used to explain ps-i how to compute quantities specific to a particular model. Writing a routine is very much like using a calculator. In fact the name "routine" was chosen specifically to remind a person used to C or C++ that these are not functions in the sense of these programming languages.

Using routines

Routines take no arguments. Rather, there is a global notion of "current agent". Before any routine is execute the "current agent" is set to point to a particular agent on a field. Thus if you routine is told to look for the value of attribute influence the particular value it obtains depends on particular current agent. There are several types of routines:

builtin
these routines are implemented in C and are part of ps-i. They are always available no matter what model is running.
Example:
prototype
This is a generalization of builtin type. This routine cannot be called, rather it is used to produce a customized routine by specifying parameters specific to the current model.
customized
This is a routine derived from prototype routine by specifying certain parameters.
inline
This is a composite routine which was not given a specific name by the user. They are generated automatically by the program.
composite
A routine defined completely by the user. It can consists of arithmetic operations, if statement, attribute values and calls to other routines.
Note:a composite routine can call only routines defined before it or builtin routines. There are no provisions for cycles, goto statements and recursion. This was done on purpose - all routines are guaranteed to return. If you want cycles you should instead write a new builtin routine in C - this would be much faster and just as easy.
parameter
These behave exactly as composite routines. The Tcl/Tk shell treats them differently by only showing parameter routines in the parameter dialog.
INTERNAL
These routines have composite or parameter type, but their name starts with the word INTERNAL. They are never displayed in the parameters dialog and, furthemore, could be dynamically modified by Ps-i without notifying the user. None of user-specified routine should have a name that starts with the word INTERNAL.

You can see the list of all functions currently known to Ps-i (this can depend upon the model loaded) by opening "Main menu->Help->Routine Browser" window.

Section format

Example:

routine 'test1' composite
	comment 'An example'
	code "[inactive]*([influence]+6)"
end

Each routine has a distinct name, a type and a comment. Other directives vary depending on the type of the routine.

Builtin routines and prototype routines

These require no declaration in the model

Customized routines

Example:

routine 'identity_poll' from 'sum_over'
	comment 'Computes identity count around the current agent'
	parameters "agent_range" "activated([cache])==$1"  "agent_influence"
end

This type of routine specifies from which routine it was derived. You should also specify a parameters directive. The number of parameters vary depending on which prototype routine was used. In the above example a customized routine "cache_activated" is derived from prototype routine "activated" by specifying which attribute to use. The routine "cache_activated" will thus return the activated identity in attribute "cache" (assumed to be of type repertoire). Note: due to time constraints no type checking was implemented (however the necessary hooks are in place). Though you can use attribute of any type in the above example only attributes of repertoire type will produce meaningful numbers.

Composite routines

Example:

routine 'test1' composite
	comment 'An example'
	code "[inactive]*([influence]+6)"
end

You can use three directives, beside comment, during routine declaration.

code "expression"
is used to specify an expression, which is computed to obtain routine value.
default "expression"
is synonymous to code and is provided for extra code readability.
when "condition" "expression"
must always be followed by code or default, or another when directive. It evaluates condition and when true computes expression, othewise it computes the value of directives following it.

Example:

routine 'agent_range' composite
	comment 'Returns range of an agent'
	when "agentclass==[[#basic]]"  "b_range"
	when "agentclass==[[#entrepreneur]]"  "e_range"
	when "agentclass==[[#innovator]]"  "e_range"
	when "agentclass==[[#apathetic]]"  "b_range"
	when "agentclass==[[#fanatic]]"	"-1"
	code "0"
end

Known operations (here A,B and C are some valid expressions):
(A)value of A
$2value of parameter 2. Produces recoverable error when number specified is greater than number of existing parameters. Parameters start with 1 and cannot be 0 or negative.
A + Badd values of A and B
A - Bsubtract B from A
A * Bmultiply values of A and B
A / Bdivide A by B (division by 0 produces recoverable error)
A mod Bremainder of division A by B (division by 0 produces recoverable error)
A ? B : Cif value of A is non zero return value of B, otherwise return value of C
A and Breturn 1 if both A and B are non zero, return 0 otherwise
A or Breturn 1 if at least one of A and B is non zero, return 0 otherwise
A intersect Bintersect two sets (bitwise and)
A union Bunion of two sets (bitwise or)
A <= Breturn 1 if A is less or equal to B, return 0 otherwise
A < Breturn 1 if A is strictly less than B, return 0 otherwise
A >= Breturn 1 if A is greater or equal to B, return 0 otherwise
A > Breturn 1 if A is strictly greater than B, return 0 otherwise
A = Breturn 1 if A and B have equal values
[[aname]] return index of attribute aname
[[#aname]] return index of agentclass aname
[aname] return value of attribute aname of the current agent
{aname}, also aname return value of function with name aname
aname(a,b,c) return value of function with name aname and parameters a, b, c
falsesame as 1
true same as 0

Example:

routine 'test4' composite
	comment 'Returns square of its argument'
	code "$1*$1"
end

Making a call "test4(rand)" will only call rand one time as it is evaluated before calling test4

Parameter routines

Example:

routine 'my_parameter' parameter
	comment 'An example'
	code "4"
end

As you can see the specification is exactly like for composite routine but with type specified as parameter. The name of the routine gets displayed as the name of the paratemer and the comment is displayed in the description field.

Note: in particular, this implies that in Ps-i you can input expressions as parameters. So, setting my_parameter to time*2 will make it dependent on time.

Inline routines

These routines have no user assigned name and are not visible in routine browser. They are created whenever the user specified an expression.

Example:

statistics
	sum		'active_agents' "1" "[inactive]==false"  
end

In this case two inline functions would be created one for "1" and another for "[inactive]==false".

Recoverable errors

During evaluation of expression it may happen that Ps-i will encounter an error, like, for example, division by 0. When this happens an expression is assigned a special "error" value. This value always resolves as false in boolean tests. When saving in statistics file it will be printed as "NaN". When displayed it will produce gray color. All further manipulations with an error value will produce another error value.

You can force an expression to return a recoverable error by calling builtin function error.

Related

See also About Ps-i 2.4.