Chapter 7: Expression and Functions
Expressions
FRED models include expressions that evaluate to either a single numerical value or a lists of values.
Expressions are always evaluated with respect to a single agent, called the evaluating agent. The evaluating agent may be an ordinary agent, a group agent, or the Meta agent.
Expressions may include any read-only variable described in Chapter 6. In addition, expressions can include:
single-valued expressions
Single-valued expressions are expressions that evaluate to a numerical value. FRED includes both shared and agent variables, each capable of storing the result of a single-valued expression. Agent variables may have distinct values for eaxch agent. Shared variables are shared by all agents–each agent “sees” the same value. A shared table variable may also store single valued expressions.
An example of a single-valued expression:
my_eligibility_to_vote = gte(age, 18)
In this example, an agent is setting the my_eligibility_to_vote
variable to 1
if the agent is at least 18 years old and 0
otherwise. In this expression,
the variable age
is evaluated with respect to the agent evaluating the
expression.
The mathematical operators +
, -
, *
, /
, and %
will produce
single-valued expressions if both arguments are single-valued:
<expression> + <expression>
: returns the sum of the expressions.<expression> - <expression>
: returns the difference of the expressions.<expression> * <expression>
: returns the product of the expressions.<expression> / <expression>
: returns the quotient of the expressions.<expression> % <expression>
: returns modulus of expressions.
The following examples may help clarify how the mathematical operators act on single-valued expressions:
x = 1 + 2 # 3
x = 2 - 1 # 1
x = 2 * 3 # 6
x = 6 / 3 # 2
x = 6 % 5 # 1
Finally, accessing an element of a table will result in a single-valued expression:
<table>[key]
: returns a value associated with a key from a table.
list-valued expressions
List-valued expressions are expressions that evaluate to lists of numerical values. FRED includes both shared and agent list-variables, each capable of storing the result of a list-valued expression. Agent list-variables are agent-specific lists of values, while shared list-variables are accessible by all agents.
An example of a list-expression:
my_housemates = members(Household)
In this example, an agent is setting a list-variable, my_housemates
, to a
list of all agents who are members of the evaluating agent’s household. The
members()
function returns a list of agent ID numbers.
A list-valued expression may consist of a simple list, e.g.
list(1, 2, 3, 4)
. A list may be composed of either numerical values or
other lists, for example:
old_list = list(1, 2, 3)
new_list = list(4, old_list, 5)
The list-variable, new_list
, contains the list-valued expression
list(4, 1, 2, 3, 5)
. list()
is an example of a function that returns a
list:
list(<expression>, <expression>, ..., <expression>)
– returns the list of values of the given expressions.Note
Each argument may be single-valued or list-valued. The result is always flattened into single list.
The mathematical operators +
, -
, *
and /
can produce
list-valued expressions if either argument is a list:
<list_expression> + <expression>
returns a list of values consisting of the sum of the single-valued expression and each of the values in the list.<expression> - <list_expression>
- returns a list of values consisting of the difference of the first expression and each of the values in the list.<list_expression> - <expression>
- returns a list of values consisting of the difference of each of the values in the list with the value of the second expression.<list_expression> - <list_expression>
- returns a list of values consisting of the difference of the items in the first list with the corresponding items in the second list. The lists must have equal lengths.<list_expression> * <expression>
- returns a list of values consisting of the product of the single-valued expression and each of the values in the list.<list_expression> * <list_expression>
- returns a list of values consisting of the product of the items in the first list with the corresponding items in the second list.<expression> / <list_expression>
- returns a list of values consisting of the quotient of the first expression and each of the values in the list.<list_expression> / <expression>)
- returns a list of values consisting of the quotient of each of the values in the list with the value of the second expression.<list_expression> / <list_expression>
- returns a list of values consisting of the quotient of the items in the first list with the corresponding items in the second list. The lists must have equal lengths.
Note
The add()
, sub()
, mult()
and div()
functional form of the
mathematical operators all take list-valued arguments. If either or both
arguments is a list, the result is a list of values.
Note
The addition and multiplication operators, +
and *
, are
commutative, i.e reversing the order will result in the same expression.
The following examples may help clarify how the mathematical operators act on lists:
x_list = list(1, 2, 3)
y_list = list(10, 20, 30)
# addition
x = 10 + x_list # list(11, 12, 13)
# subtraction
x = 10 - x_list # list(9, 8, 7)
x = x_list - 10 # list(-9, -8, -7)
z_list = y_list - x_list # list(9, 18, 27)
# multiplication
x = x_list * 10 # list(10, 20, 30)
x = 10 * x_list # list(10, 20, 30)
z_list = y_list * y_list # list(10, 40, 90)
# division
x = x_list / 2 # list(0.5, 1.0, 1.5)
x = 1.5 / x_list # list(1.5, 0.75, 0.5)
z_list = y_lixt / x_list # list(10, 10, 10)
The following returns a list of integers:
range(start,stop,step)
- returns a list of integers fromstart
in increments ofstep
up (or down ifstep < 0
) to but not includingstop
. If two arguments are given, thestep
is assumed to be1
. If only one argument is given, thenstart = 0
andstep = 1
. Sorange(5)
returns the list(0, 1, 2,\ 3, 4)
. It is an error ifstep = 0
. The list is empty ifstep > 0
andstop <= start
, or ifstep < 0
andstart <= stop
.
Accessing an element of a list-table will result in a list-valued expression:
<list-table>[key]
: returns a list associated with a key from a list-table.
Finally, accessing a list of elements in a table will result in a list-valued expression:
<table>[<list_expression>]
: returns a list of values associated with a list of keys.
table-valued expressions
Table-valued expressions are expressions that evaluate to a table or list-table consisting of key-value pairs. Table variables are capable of storing the result of a table-valued expression.
Tables and list-tables are data structures consisting of key-value pairs. For tables, the values are real numbers. For list-tables, the values are lists. All tables are shared variables accessible by all agents.
Numerical Operators
Expressions may contain the usual numerical operators +
, -
, *
,
/
, and %
for addition, subtraction, multiplication, division, and the
modulo operator. Each of these can be expressed either in infix or prefix
notation:
infix |
prefix |
---|---|
|
|
|
|
|
|
|
|
|
|
Note
The numerical operators +
, -
, *
, /
, and %
are expressed
in infix notation, where A + B
is a synonym for add(A, B)
, etc. FRED
parses expressions into prefix notation prior to execution, so you may see
the prefix form in error and warning messages.
Note
The numerical operators +
, -
, *
, and /
apply to list-valued
arguments as well as mixed single-valued and list-valued arguments.
Warning
Division by zero will cause FRED to abort a simulation with an appropriate error message.
Input Functions
FRED supports input function that read from files. The following function returns a list of values:
read(filename, column)
– returns a list of numeric values in the indicated from the named comma-separated value file. Column numbers begin with0
. Blank lines in the file are skipped, as are any lines with a non-numeric value in the first column.
Mathematical Functions
FRED supports a number of mathematical functions:
comparison
equal(x, y)
– returns1
if the arguments are equal,0
otherwise.eq(x, y)
– synonym forequal(x, y)
.neq(x, y)
- returns1
if the arguments are not equal,0
otherwise.lt(x, y)
- returns1
ifx
is less thany
,0
otherwise.lte(x, y)
- returns1
ifx
is less than or equal toy
,0
otherwise.gt(x, y)
- returns1
ifx
is greater thany
,0
otherwise.gte(x, y)
- returns1
ifx
is greater than or equal toy
,0
otherwise.
rounding and remainder
floor(x)
– returns the largest integral value less than or equal tox
.ceil(x)
– returns the largest integral value greater than or equal tox
.int(x)
– returns the integer part ofx
. the result is equal tofloor(x)
ifx
is non-negative andceil(x)
ifx
is negative.round(x)
– returns the integral value nearest tox
, rounding half-way cases away from zero.
exponential, logarithmic, and power
log(x)
- returns the base \(e\) logarithm ofx
, \(\log_e(x)\)pow(x, y)
- returns the base,x
, raised to the power exponent,y
, \(x^y\)exp(x)
- returns the base \(e\) exponential ofx
, which is \(e\) raised to the powerx
, \(e^x\).sqrt(x)
- returns the square root ofx
.
trigonometric
sin(x)
– returns the sine ofx
, wherex
is interpreted as radians.cos(x)
– returns the cosine ofx
, wherex
is interpreted as radians.tan(x)
– returns the tangent ofx
, wherex
is interpreted as radians.asin(x)
– returns the principal value of the inverse sine ofx
. The result is in the range \([-\pi/2, \pi/2]\).acos(x)
– returns the principle value of the inverse cosine ofx
. The result is in the range \([0, \pi]\).atan(x)
– returns the principal value of the inverse tangent ofx
. The result is in the range \([-\pi/2, \pi/2]\).atan2(y, x)
– returns the principal value of the inverse tangent ofy/x
using the signs of both arguments to determine the quadrant of the returned value.sinh(x)
– returns the hyperbolic sine ofx
.cosh(x)
– returns the hyperbolic cosine ofx
.tanh(x)
– returns the hyperbolic tangent ofx
.asinh(x)
– returns the inverse hyperbolic sine ofx
.acosh(x)
– returns the principle value of the inverse hyperbolic cosine ofx
. The result is in the range \([0, \infty]\).atanh(x)
– returns the inverse hyperbolic tangent ofx
.
miscellaneous
min(x, y)
– returns the smallest of the two values.max(x, y)
– returns the largest of the two values.abs(x)
– returns the absolute value ofx
.nprob(p, n)
– returns the probability, math:q, such that, when an agent makesn
repeated independent choices with probability of success :math`q`, the total probability of success isp
. This is equivalent to the expression1- pow(1 - p, 1 / n)
.distance(lat1, lon1, lat2, lon2)
– returns the distance in km between the points, (lat1
,lon1
) and (lat2
,lon2
), on the surface of the Earth.
Warning
Illegal operations using mathematical functions will cause FRED to abort a simulation with an appropriate error message. Examples of illegal operations include taking the logarithm of a negative number or taking the inverse sine of a number outside the range [-1,1].
Statistical Distribution Functions
FRED provides the following functions that return draws from statistical distributions:
bernoulli(p)
– returns1
with probabilityp
, otherwise0
.binomial(t, p)
– returns an integer according to a binomial discrete distribution. This distribution produces random integers in the range \([0, t]\), where each value represents the number of successes in a sequence oft
trials (each with a probability of success equal top
).cauchy(a, b)
– returns a floating point number according to a Cauchy distribution with a mediana
and shape parameter,b
. This is equivalent to a Student-t distribution with one degree of freedom.chi_squared(n)
– returns a floating point number according to a chi-squared distribution. This distribution produces random numbers as if the square ofn
independent standard normal random variables with \(\mu=0\) and \(\sigma=1\), were aggregated, wheren
is the distribution parameter, known as degrees of freedom.exponential(λ)
– returns a floating point number according to an exponential distribution. This distribution produces random numbers where each value represents the interval between two random events that are independent but statistically defined by a constant average rate of occurrence,λ
.extreme_value(a, b)
– returns a floating point number according to a Type I extreme value distribution. This distribution produces random numbers where each value can be interpreted as the extreme (maximum or minimum) of a number of samples of a random variable.fisher_f(m, n)
– returns a floating point number according to a Fisher-F distribution. This distribution produces random numbers as the result of dividing two independent Chi-squared distributions ofm
withn
degrees of freedom.gamma(α, β)
– returns a floating point number according to a Gamma distribution. This distribution can be interpreted as the aggregation ofα
exponential distributions, each withβ
as parameter. It is often used to model waiting times.gompertz(shape, scale)
– returns a floating point random number according to a Gompertz distribution.lognormal(median, dispersion)
– returns a floating point random number according to a lognormal distribution with the givenmedian
anddispersion
.Note
The default parameterization is the “multiplicative”, also known as the “geometric parameterization”, i.e., median = exp(μ) and dispersion = exp(σ).
negative_binomial(k, p)
– returns a random integer according to a negative binomial discrete distribution. This distribution produces random integers where each value represents the number of successful trials beforek
unsuccessful trials happen in a sequence of trials, each with a probability of success equal top
.normal(μ, σ)
– returns a floating point random number from a normal distribution with a givenμ
and standard deviation,σ
.poisson(λ)
– returns an integer value drawn from a Poisson distribution with a meanλ
.student_t(n)
– returns a floating point random number according to a Student-T distribution withn
degrees of freedom. This distribution produces random numbers as the result of normalizing the values of a relatively small sample (\(n+1\) values) of independent normally-distributed values. As the sample size increases, the distribution approaches a standard normal distribution.uniform(l, u)
– returns a uniform random number in range [l
,u
).weibull(a, b)
– returns a floating point random number according to a 2-parameter Weibull distribution with a probability density function of:\[p(x|a,b) = \frac{a}{b}\left( \frac{x}{b}\right)^{a-1}e^{-\left(\frac{x}{b}\right)^a}\]
Date and Time Functions
FRED operates in steps each representing one hour of simulated time. The functions in this section are often used in connection with wait rules to control the amount of time an agent spends in a given state.
The following function returns the simulation step corresponding to a given date and hour:
sim_step(year, month, day, hour)
– returns the simulation time step corresponding to the given date and hour. For example,sim_step(2020, 6, 16, 19)
returns the simulation time step corresponding to June 6, 2020 at 7pm.Note
sim_step(year, month, day)
is equivalent tosim_step(year, month, day, 0)
.
Often this function is used in combination with wait rules. For example,
the following wait
rule would cause an agent to wait until
the simulation time step corresponding to Aug 12 at 2 a.m. during the year
represented by the variable Yr
:
wait(sim_step(Yr, 8, 12, 2) - now)
The until()
function returns the number of hours until the specified
date and time:
until(year, month, day_of_month, hour)
For example, the following wait
rule would wait until 2020-Dec-31 at
11 p.m.
wait(until(2020, 12, 31, 23))
The until()
function understands symbolic terms for months and hours,
so the above could also be written as:
wait(until(2020, Dec, 31, 11pm))
If three arguments are given of the form until(month, day, hour)
, where
the first argument is the symbolic name of the month, the function
returns the number of hours until the next occurrence of the given date
and time.
For example, the following makes an agent wait until 11 p.m. on the next New Year’s Eve:
wait(until(Dec, 31, 11pm))
The until()
function also accepts two arguments, as long as the first
argument is a symbolic name for a month or a day of the week, for example:
wait(until(Sat, 11pm))
wait(until(Dec, 31))
In the latter case, the hour is assumed to be 12am
.
If a single argument is given consisting of a number following by am
or pm
, until()
returns the number of hours until the next occurrence
of the indicated time, for example:
wait(until(1pm))
Finally, if until()
is given a single argument not in the format
<number>am
or <number>pm
, the argument is interpreted as a
timestamp or a datestamp:
A timestamp is an expression that evaluates to a number of the form
YYYYMMDDHH
, whereYYYY
represents the year,MM
represents the month (with values01, ..., 12
), andHH
represents the hour on a 24-hour clock (with values00, ..., 23
.
You can construct a timestamp using the the formula:
my_timestamp = 1000000 * year + 10000 * month + 100 * day_of_month + hour
A datestamp is an expression that evaluates to a number of the form
YYYYMMDD
.
The formula for a datestamp is:
my_datestamp = 10000 * year + 100 * month + day_of_month
For example, we might have a variable next_change
whose current
value is 20201104
(a valid datestamp). Then the following makes an
agent wait until 2020-Nov-04 at 12 a.m.:
wait(until(next_change))
If the current value of next_change
is the timestamp
2020110413
, then the following makes an agent wait until 2020-Nov-04
at 1 p.m.:
wait(until(next_change))
If the expression does not evaluate to a valid timestamp or datestamp, a run-time error will occur and the simulation will be terminated.
The following function is useful for finding the time between two specified timestamps:
steps_between(<timestamp1>, <timestamp2>)
returns the number of time steps between the two timestamps.The result is positive if
<timestamp1>
occurs before<timestamp2>
.If the timestamps are equal,
steps_between()
returns 0.If either timestamp evaluates to a datestamp value of the form
YYYYMMDD
, it is interpreted asYYYYMMDDHH
whereHH = 00
.An error is thrown if either timestamp is not valid.
The following function extract the components of a timestamp:
get_year_from_timestamp(<timestamp>)
returns the value of theYYYY
portion of the timestamp.get_month_from_timestamp(<timestamp>)
returns the value of theMM
portion of the timestamp.get_day_from_timestamp(<timestamp>)
returns the value of theDD
portion of the timestamp.get_hour_from_timestamp(<timestamp>)
returns the value of theHH
portion of the timestamp.
Timestamps are correctly computed for 100 years before the
start_date
to 100 years after the end_date
. Outside this range,
the results are unpredictable.
Functions on Conditions
current_count(<condition_name>.<state_name>, <group_name>)
- returns the number of agents currently in the given state. The second argument is optional. If a group name is provided, the count is restricted to agents that share the given group with the agent.current_state(<condition_name>)
- returns the current state of the agent in the given condition.daily_count(<condition_name>.<state_name>, <group_name>)
- returns the number of agents that entered the given state on the previous day. The second argument is optional. If a group name is provided, the count is restricted to agents that share the given group with the agent.source(<condition_name>.<state_name>, <group_name>)
- returns the agent ID of the transmission source for the given condition.transmissions(<condition_name>.<state_name>, <group_name>)
- returns the number of other agents that have been exposed to the given condition by the current agent. The result is 0 if the agent has not transmitted the condition.total_count(<condition_name>.<state_name>, <group_name>)
- returns the total number of agents that have ever entered the given state. The second argument is optional. If a group name is provided, the count is restricted to agents that share the given group with the agent.prev_state(<condition_name>)
- returns the agent’s previous state before transitioning to the current state.Note
The previous transition may have been from the current state.
sus_list(<condition_name>)
- returns the list of agents that are susceptible to a condition, i.e. agents who have a susceptibility greater than0.0
.
Functions on Groups
get_group_id(<group_name>)
- returns the group ID of the named group, or0
if the calling agent is not a member of such a group.current_place()
- returns the place ID of the place that the agent is visiting at the current time, or0
if the agent is not at any place.
associated agents
size(Population)
- returns the number of ordinary agents in the population.size(<group>)
- returns the number ofmembers in the ordinary agent’s given group. Returns
0
if the agent has no such group.
size(<expression>)
- returns the number ofmembers in the group whose ID is the value of the expression. Error occurs if the expression does not evaluate to agroup ID.
get_size()
- returns the number of members in a group agent’s group. Error occurs if called by a non-group agent.members(<group>, <group>, ..., <group>)
- returns a list of all agents who share one or more of the groups with the agent.
For example,
new_list = members(Household, Classroom)
returns a list of all the agents who are in the agent’s household or
classroom, or both. Each agent appears at most once in the resulting list.
The result is sorted by agent ID numbers.
get_group_agents(<group_name>)
- returns a list of IDs for the group agents associated with the sites of the given group type. If the group type does not have group agents, the list will be empty.get_group_agent(<group_name>)
- returns the group agent ID if the evaluating agent is a member of the named group and the group agent exists. Otherwise, returns0
.get_group_agent(<group_ID>)
- returns the group agent ID of the group with the given ID, or0
if the group does not exist or the group has no group agent.
geographical
The following functions return information on the location or relative location of one or more places:
latitude(<place_name>)
– latitude of the agent’s place. If the argument is omitted, return the latitude of the agent itself.longitude(<place_name>)
– longitude of the agent’s place. If the argument is omitted, return the longitude of the agent itself.elevation(<place_name>)
- returns the height in meters above sea level of the agent’s place. If the argument is omitted, return the elevation of the agent itself.getx(<place_name>)
– x-coordinate of the agent’s place (meters from western edge in simulation area). If the argument is omitted, return the x-coordinate of the agent itself.gety(<place_name>)
– y-coordinate of the agent’s place (meters from southern edge of simulation area). If the argument is omitted, return the y-coordinate of the agent itself.dist(<place_name1>, <place_name2>)
– returns the distance in km between the places whose IDs are represented by the arguments.
place containers
get_container(<container_type>, <place_name>)
: returns the place ID of the container of the type in the first argument that contains the agent’s place of the type in the second argument.
on networks
links(Network)
returns a list of agents to which the agent is directly connected by edges in the given undirected network.outlinks(Network)
returns a list of agents to which the agent is directly connected by outward edges in the given directed network.inlinks(Network)
returns a list of agents that have edges to the agent in the given directed network.get_weight(Network, source, destination)
: returns the weight of the edge fromsource
todestination
in the named network. Returns 0 if no such edge exists.shortest_path(Network, source, destination)
: returns a list of nodes in theNetwork
fromsource
todestination
with the shortest total edge weights, using Dijkstra’s algorithm. Returns an empty list if either node is not in the network, or if there is no path fromsource
todestination
.weight_neighborhood(Network, source, weight_limit, weight_vec)
: returns a list of nodes in theNetwork
whose shortest paths from thesource
node have weights less than or equal toweight_limit
. The nodes are sorted by ascending weight of the their shortest paths. The 4th argument is optional; if present it must be the name of a shared or agent list-variable, which is set to the list of weights of the returned list of nodes.edge_neighborhood(Network, source, edge_limit, edge_vec)
:` returns a list of nodes whose shortest edge-paths have no more thanedge_limit
edges in the named network. The nodes are sorted by ascending edge-lengths of the their shortest edge-paths. The 4th arg is optional; if present it must be the name of a shared or agent list var, which is set to the list of edge-lengths of the returned list of nodes.
Functions on Other Agents
get_population()
– returns a list of IDs of all oridinary agents in the population.ask(<expression1>, <expression2>)
– If the first argument evaluates to the ID of another agent, the function returns the value of the second argument, evaluated with respect to the other agent. If the first argument evaluates to a list of agent IDs, the function returns a list of values of the second expression, evaluated with respect to each of the other agents. If the first argument is the name of a group (such asSchool
), then the other agent is the group agent for the primary agent’s group of that type. If there is no such group agent, the result of the function is 0.The following sets the value of
sibling_age
to the age of the agent whose ID is stored inmy_sibling
:sibling_age = ask(my_sibling, age)
The following sets
my_household_ages_list
to a list of the ages of the members of the agent’s household:my_household_ages_list = ask(members(Household), age)
Suppose the evaluating agent is a
member
of a group calledTheater
. Then the following setsavailable_tickets
to the value of thetickets
agent variable for the group agent for the agent’sTheater
:available_tickets = ask(Theater, tickets)
Functions on Lists
selecting an element
An element in a list variable may be accessed using square brackets,
<list_variable>[<expression>]
. The expressions is truncated to an integer,
and used as an index into the list. If the element does not exist, 0.0
is
returned. Equivalently, this can be accomplished with the select()
function.
Note
If X
is declared as a list variable then the parser translates X[string]
to select(X, string)
, so the
following are equivalent:
select(x_list, index_list)
andx_list[index_list]
select(x_list, _ > 0)
andx_list[_ > 0]
- returns all positive numbers inx_list
select(x_list, ask(_, age) > 18)
andx_list[ask(_, age) > 18]
- returns the list of agents inx_list
that haveage > 18
.
A single element can be selected from a list by the following functions:
select(<list-expression>, <expression>)
– returns the item in the value of the first argument indexed by the second argument. Note that th<list-expression>
need not be a list variable, For example,select(members(Household),0)
would retrun the first member of the agent’s household.last(<list_expression>)
– returns the last item in the list. Throws an exception if the list is empty.
The select
function can also be used to select a sub-list:
select(<list-expression>, <list_expression>)
- returns the sub-list of the first argument corresponding to the list of indices in the second argument.find_index(<value>, <list_expression>)
– returns the index of thevalue
in thelist_expression
, or -1 if the value does not occur in the list.
Elements in a list may also be selected based on a test:
select(<list-expression>, <test>)
- returns the sub-list of the first argument consisting of the items that pass the test. The special variable_
in the test refers to the list item being evaluated. For exampleselect(list(20, 5, 2, 40), (10 < _))
would return the list(20, 40)
.select_index(<list-expression>, <test>)
- returns the list of the indices for the list in the first argument corresponding to items that pass the test. The special variable_
in the test refers to the list item being evaluated. For exampleselect_index(list(20, 5, 2, 40), (10 < _))
would return the list(0, 3)
.
examples
You can access the first or last element in a list X
:
first_item = X[0]
last_item = X[length(X) - 1]
last_item = last(X)
or select a member of an agent’s household:
first_housemate = select(members(Household), 0)
unique(<list-expression>)
- Returns a sorted list of unique elements that occur in the list parameter.
miscellaneous
length(<list_expression>)
– returns the number of items in the value of the list-expression.max(<list_expression>)
– returns the maximum of values in the list. Returns0
if list is empty.min(<list_expression>)
– returns the minimum of values in the list. Returns0
if list is empty.percentile(<value>, <list_epression>)
- returns the percentile of a value within a list of sorted list of values.prod(<list_expression>)
– returns the product of values in the list. Returns0
if list is empty.sum(<list_expression>)
– returns the sum of values in the list. Returns0
if list is empty.partial_sums(<list_expression>)
- returns the list of partial sums of the values in the list. That is, each value in the resulting list consists of the sum of all items up to an including the current item.unique(<list_expression>)
- returns a list of unique elements from the list.
examples
The following example sets a variable, mean_X
, equal to the average of a
list X
:
if (length(X) > 0) then mean_X = sum(X) / length(X)
filtering
Filtering a list entails producing a sub-list from a list that matches some criteria. There are several functions that perform filtering. The following functions act on any list:
filter_values(<list_expr>, <op>, <expr>)
- returns a sub-list of the values that satisfy the test of the given operator against the expression, where<op>
is<
,<=
,=
,==
,>
,>=
, or!=
.index_values(<list_expr>, <op>, <expr>)
returns the sub-list of values that satisfy the given test.filter_by_index(<list_expr>, <list_of_desired_indexes>)
returns the selected items from a list given the list of desired index values.
Another set of functions specifically act on a list of agent IDs:
filter_agents(<list-expression>, <test1>, <test2>, ..., <testN>)
- returns a list of all agents in the list-expression that satisfy all the tests in the remaining arguments.index_agents(<list-expression>, <test1>, ..., <testN>)
- returns a list of indexes of agents on the list that satisfy all the tests.
Note
The <list-expression>
argument in the preceding two functions must
be a list of agent IDs.
examples
For example, a list can be filtered based on the value of it’s elements:
old_list = list(2, 10, 8, 4, 6)
new_list = filter_values(old_list, >, old_list[0] + 3)
The resulting list, new_list
, is equal to list(10, 8, 6)
.
Similarly, the indices that produce this filtering can be recovered:
old_list = list(2, 10, 8, 4, 6)
index_list = index_values(old_list, >, old_list[0] + 3)
new_list = filter_by_index(old_list, index_list)
The resulting list, index_list
, is equal to list(1, 2, 4)
. That list of
indices can be used to generate the filtered list, new_list
, again equal to
list(10, 8, 6)
.
For example, to generate a list of all the agents who are in an agent’s school, older than the agent, and are of the opposite sex:
my_older_opposite_sex_friends = filter_agents(members(School),\
age < ask(_,age), sex != ask(_,sex))
Note
The special variable _
is replaced by the current item in the
list of agent being processed. For example, in the first test in
the example above,
the read-only variable age
refers to the age of the agent evaluating the expression,
and the expression ask(_,age)
returns to the age of the agent being evaluated
by the filter, that is the current item in the list member(Schhol)
.
sampling
The following functions return a random sample from a list. Each call to the function returns a distinct randomized sample.
sample_without_replacement(<list-expr>, <expr>)
- returns a random sample of the list of sizek
wherek
is the value of second expression. Sampling is without replacement, meaning that no item is selected more than once.sample_without_replacement(<list-expr>, <expr>, <list-expr2>)
- returns a random sample of the list of sizek
wherek
is the value of second expression. Sampling uses the weights specified in the last argument, which must evaluate to a list of positive values with the same length as the first argument. Sampling is without replacement meaning that no item is selected more than once.sample_with_replacement(<list-expr>, <expr>)
- returns a random sample of the list of sizek
wherek
is the value of second expression. Sampling is performed with replacement, meaning that items may be selected more than once.sample_with_replacement(<list-expr>, <expr>, <list-expr2>)
- returns a random sample of the list of sizek
wherek
is the value of second expression. Sampling uses the weights specified in the last argument, which must evaluate to a list of positive values with the same length as the first argument. Sampling is performed with replacement meaning that items may be selected more than once.
set operations
The following functions implement set union, intersection, and difference operations:
union(<list_expr>, <list_expr>)
- returns a list of unique items that occur in either list, sorted in increasing order.intersection(<list_expr>, <list_expr>)
- returns a list of unique items that occur in both lists, sorted in increasing order.set_difference(<list-expr1>, <list-expr2>)
- returns the list of unique items that are in the first list but not in the second list.
sorting
The following functions can be used to reorder a list:
sort(<list_expr>)
- returns a sorted list.arg_sort(<list_expr>)
- returns a list of indices that sort the list.shuffle(<list_expr>)
- returns a randomly sorted copy of the list.
evaluating an expression on each item
apply(<list_expr>, <expression>)
- returns a list of the values of the expression in the second argument, evaluated with respect to each item in the first argument. Any occurrence of_
in the expression refers to the value of the current item in the list.
examples
For example, a new list can be generated by multiplying every element in a list
by 2.0
:
x_list = list(1, 2, 3, 4, 5)
y_list = apply(x_list, 2 * _)
# result: y_list = list(2, 4, 6, 8, 10)
Functions on Tables
Tables and list-tables are data structures consisting of key-value pairs.
For tables, the values are real numbers. For list-tables, the values are lists.
A value in a table or list-table may be selected using square brackets,
<table-name>[<key>]
. Equivalently, this can be accomplished using the
lookup()
function.
A specific position in a list-table can be accessed using two values
in square brackets. For example, if x
is a list-table and the list
associated with key key
has three values in the list x[key]
, then
x[key][2]
refers to the third value in the list. In the following
example, we set the third item in the list to the first item in the
list plus 1:
x[key][2] = x[key][0] + 1
Functions on tables and list-tables include:
lookup(<table_name>, <key-expression>)
- returns the value in the table/list-table associated with the given key.Note
If the key does not exist, a run-time error occurs unless the table has a defined
default_value
property, in which case the default value is returned. The default value is not inserted into the table as the value of the key.length(<table_name>)
– returns the number ofkey-value
pairs in the table/list-table.get_keys(<table_name>)
- returns the list of keys stored in the indicated table/list-table.get_values(<table_name>)
- returns the list of values stored in the indicated table.
True-or-False Predicates
The predicates discussed in Chapter 8 evaluate to true
or
false
. When used as part of an expression, they evaluate to
numeric values, with true
being treated as 1
and false
treated as 0
.