`1_Specifying_Games.Rmd`

This vignette illustrates how you can specify dynamic games with the `RelationalContracts`

package. We start with simple examples and move to more complex use cases.

In particular, sections 7-9 give advice on how to effectively specify state transitions for complex game with multidimensional state spaces.

Consider a simple two player repeated game. Each player \(i\) chooses an effort level \(e_i\) on a grid between 0 and 1 that directly benefits the other player. Effort involves for player \(i\) cost of \(\frac 1 2 e_i\) and grants the other player a benefit of \(e_i\):

library(RelationalContracts) effort.seq = seq(0,1,by=0.1) g = rel_game("Mutual Gift Game") %>% rel_state("x0", # Both players can pick effort # on a grid between 0 and 1 A1 = list(e1=effort.seq), A2 = list(e2=effort.seq), # Stage game payoffs pi1 = e2 - 0.5*e1^2, pi2 = e1 - 0.5*e2^2 ) # Solve SPE g %>% rel_spe(delta=0.3) %>% get_eq() %>% select(x, ae.lab)

```
## # A tibble: 1 x 2
## x ae.lab
## <chr> <chr>
## 1 x0 0.6 | 0.6
```

The function `rel_game`

specifies an empty game object and `rel_state`

specifies a state. A repeated game has just a single state, but one can also specify more general stochastic games with several states.

The parameters `A1`

and `A2`

specify the action spaces of each player. You have to provide a named list of actions for each player, here we have the actions `e1`

for player 1 and `e2`

for player 2. Note that you must choose different names for each player’s actions, i.e. you could not call both actions just `e`

.

The parameters `pi1`

and `pi2`

specify payoffs for both players. Payoffs will be lazily evaluated later on the corresponding action space. This means they can depend on the chosen action or parameters specified for the game or state.

Consider now the following game with two states:

library(RelationalContracts) effort.seq = seq(0,1,by=0.1) vul = 1 g = rel_game() %>% rel_state("not_vul", A1 = list(e1=effort.seq, make_vul = c(FALSE, TRUE)), A2 = list(e2=effort.seq), pi1 = e2 - 0.5*e1^2, pi2 = e1 - 0.5*e2^2 ) %>% rel_state("vul", A1 = list(e1=effort.seq), A2 = list(e2=c(-vul,effort.seq)), pi1 = e2 - 0.5*e1^2, pi2 = e1 - 0.5*pmax(e2,0)^2 ) %>% rel_transition("not_vul","vul", make_vul=TRUE,prob=1) %>% rel_transition("vul","not_vul", prob = 0.05) %>% rel_compile() # Solve SP # g %>% rel_spe(delta=0.3) %>% get_eq() %>% select(x, ae.lab)

```
## # A tibble: 2 x 2
## x ae.lab
## <chr> <chr>
## 1 not_vul 0.6 1 | 0.6
## 2 vul 0.9 | 0.9
```

We now have two states. The game starts in state “not_vul”. Here player 1 has a two dimensional actions space `A1`

. In addition to choosing effort levels, player 1 can choose via `make_vul`

whether to make herself vulnerable or not. In the state “vul”, player 2 can choose negative effort that harms player 1. We specify the state transitions via the function `rel_transition`

.

The command `rel_transition("not_vul","vul",make_vul=TRUE,prob=1)`

means that there is a transition from state “not_vul” to state “vul” with probability `prob=1`

if the action `make_vul=TRUE`

was chosen. The effort levels do not affect this transition probability.

The line `rel_transition("vul","not_vul", prob = 0.05)`

means that there is a transition from state “vul” to state “not_vul” with probability of 5%, irrespective of which actions have been chosen.

For cases in which no explicit transition probability is specified it is assumed that play remains in the current state. I.e. if player 1 chooses `make_vul = FALSE`

in stat “not_vul” the game remains in state “not_vul” even though we have not explicitly specified this.

Consider the following game specification that has 6 different states determined by increasing vulnerability of player 1:

effort.seq = seq(0,1,by=0.1) g = rel_game() %>% rel_states(x = 0:5, A1 = list(e1=effort.seq, inc_vul = c(FALSE, TRUE)), A2 = list(e2=c(-1,effort.seq)), pi1 = ifelse(e2 != -1,e2, -x/5) - 0.5*e1^2, pi2 = e1 - 0.5*pmax(e2,0)^2 ) %>% rel_transition(xs = 0:4,xd=1:5, inc_vul=TRUE,prob=1) # Solve SPE g %>% rel_spe(delta=0.3) %>% get_eq() %>% select(x, ae.lab)

```
## # A tibble: 6 x 2
## x ae.lab
## <int> <chr>
## 1 0 0.6 1 | 0.6
## 2 1 0.7 1 | 0.7
## 3 2 0.7 1 | 0.8
## 4 3 0.8 1 | 0.8
## 5 4 0.8 1 | 0.9
## 6 5 0.9 0 | 0.9
```

The function `rel_states`

is just a synonym for `rel_state`

and can be used to specify several states simultaneously. A state `x`

is here identified by an integer between 0 and 5 that relates to player 1’s vulnerability.

Note that the formula for `pi1`

refers to the current state `x`

.

The function `rel_transition`

allows to specify multiple source states `xs`

and multiple destination states `xd`

. Here choosing `inc_vul=TRUE`

increases the state number, as long as we have not reached yet state `x=5`

.

The specification above specifies the same action space for all states, even though in state `x=5`

the action `inc_vul`

has no effect.

One way to specify different action spaces for different subsets of states is to add multiple `rel_states`

commands as in the example below:

effort.seq = seq(0,1,by=0.1) g = rel_game() %>% rel_states(x = 0:4, A1 = list(e1=effort.seq, inc_vul = c(FALSE, TRUE)), A2 = list(e2=c(-1,effort.seq)), pi1 = ifelse(e2 != -1,e2, -x/5) - 0.5*e1^2, pi2 = e1 - 0.5*pmax(e2,0)^2 ) %>% # Specify state x=5 separately without inc_vul action rel_states(x = 5, A1 = list(e1=effort.seq), A2 = list(e2=c(-1,effort.seq)), pi1 = ifelse(e2 != -1,e2, -x/5) - 0.5*e1^2, pi2 = e1 - 0.5*pmax(e2,0)^2 ) %>% rel_transition(xs = 0:4,xd=1:5, inc_vul=TRUE,prob=1)

If you want to specify several states with different action spaces in a single call to `rel_states`

you should use the argument `A.fun`

instead of `A1`

and `A2`

. Below is an example:

effort.seq = seq(0,1,by=0.1) # Function that specifies action spaces A.fun = function(x,...) { list( A1 = list(e1=effort.seq, inc_vul = c(FALSE, if (x<5) TRUE)), A2 = list(e2=c(if (x>0) -1,effort.seq)) ) } g = rel_game() %>% rel_states(x = 0:5, A.fun = A.fun, pi1 = ifelse(e2 != -1,e2, -x/5) - 0.5*e1^2, pi2 = e1 - 0.5*pmax(e2,0)^2 ) %>% rel_transition(xs = 0:4,xd=1:5, inc_vul=TRUE,prob=1) # Solve SPE g %>% rel_spe(delta=0.3) %>% get_eq() %>% select(x, ae.lab)

```
## # A tibble: 6 x 2
## x ae.lab
## <int> <chr>
## 1 0 0.6 1 | 0.6
## 2 1 0.7 1 | 0.7
## 3 2 0.7 1 | 0.8
## 4 3 0.8 1 | 0.8
## 5 4 0.8 1 | 0.9
## 6 5 0.9 0 | 0.9
```

The function `A.fun`

will be called separately for each state `x`

and should return a list with elements `A1`

and `A2`

describing the action spaces of both players for the current state.

The argument `pi.fun`

of `rel_states`

allows to specify payoffs via a function instead of providing formulas to the arguments `pi1`

and `pi2`

. Here is an example:

effort.seq = seq(0,1,by=0.1) pi.fun = function(ax.df, ...) { mutate(ax.df, pi1 = ifelse(e2 != -1,e2, -x/5) - 0.5*e1^2, pi2 = e1 - 0.5*pmax(e2,0)^2 ) } g = rel_game() %>% rel_states(x = 0:5, A1 = list(e1=effort.seq, inc_vul = c(FALSE, TRUE)), A2 = list(e2=c(-1,effort.seq)), pi.fun = pi.fun ) %>% rel_transition(xs = 0:4,xd=1:5, inc_vul=TRUE,prob=1) # Solve SPE g %>% rel_spe(delta=0.3) %>% get_eq() %>% select(x, ae.lab)

```
## # A tibble: 6 x 2
## x ae.lab
## <int> <chr>
## 1 0 0.6 1 | 0.6
## 2 1 0.7 1 | 0.7
## 3 2 0.7 1 | 0.8
## 4 3 0.8 1 | 0.8
## 5 4 0.8 1 | 0.9
## 6 5 0.9 0 | 0.9
```

While `A.fun`

will be called separately for each state `x`

, the function `pi.fun`

will be called only once with an argument `ax.df`

(and possible some parameters specified in the game as explained in Section 11). `ax.df`

is a tibble that contains one row for every action profile in every state. In our example, its head and tail looks as follows:

```
head(ax.df,3)
# A tibble: 1,584 x 5
x .a e1 inc_vul e2
<int> <int> <dbl> <lgl> <dbl>
1 0 1 0 FALSE -1
2 0 2 0 FALSE 0
3 0 3 0 FALSE 0.1
tail(ax.df,3)
# A tibble: 3 x 5
x .a e1 inc_vul e2
<int> <int> <dbl> <lgl> <dbl>
1 5 262 1 TRUE 0.8
2 5 263 1 TRUE 0.9
3 5 264 1 TRUE 1
```

The column `x`

specifies a state, the column `.a`

will probably not be used, it is just a unique index of the action profile number. The other columns correspond to the action names. (If some action is not present in some state, it is filled with `NA`

)

Your function basically should add the columns `pi1`

and `pi2`

to each row of this data frame. You can drop some columns, but should keep `x`

and not change the order of rows.

As an alternative to specifying state transitions with one or several calls to `rel_transition`

, one can use the argument `trans.fun`

in the call to `rel_states`

. Here is an example:

trans.fun = function(ax.df, ...) { tibble(xs=0:4,xd=1:5, inc_vul=TRUE, prob=1) } g = rel_game() %>% rel_states(x = 0:5, A1 = list(e1=effort.seq, inc_vul = c(FALSE, TRUE)), A2 = list(e2=c(-1,effort.seq)), pi1 = ifelse(e2 != -1,e2, -x/5) - 0.5*e1^2, pi2 = e1 - 0.5*pmax(e2,0)^2, trans.fun = trans.fun )

`trans.fun`

is a function that takes the same arguments as explained in the subsection about `pi.fun`

above. It returns a data frame whose columns are essentially the same as the arguments of `rel_transition`

. Each row specifies a transition from the state in column `xs`

to the state in column `xd`

with probability in column `prob`

given that the actions take the values specified in additional columns.

You may add columns for all actions and set a value of `NA`

if this action is not relevant in a particular row. So we could also have specified the state transitions as

trans.fun = function(ax.df, ...) { tibble(xs=0:4,xd=1:5, inc_vul=TRUE,e1=NA, e2=NA, prob=1) }

In the current example, there is little value of using the `trans.fun`

argument instead of `rel_transition`

. Yet, in more complex games with multidimensional state spaces and complex state transitions `trans.fun`

can be more tractable. We will provide examples below.

The following examples will be variants of a dynamic Cournot duopoly with capacity investments. A state `x`

is characterized by a tuple `(x1,x2)`

that describes the production capacities of each player. In each period players simultaneously choose integer outputs `q1`

and `q2`

between 0 and their capacity and decide whether or not to invest into new capacity. A player can invest until a maximum capacity `x.max`

has been reached.

Product market prices in a period are given by `a-q1-q2`

where `a`

is an exogenous parameter.

The following code specifies such a Cournot duopoly:

# Exogenous paramaters x.max = 5 a = 8 i.cost = 1 # State matrix x.df = tidyr::expand_grid(x1=0:x.max, x2=0:x.max) %>% mutate(x=paste0(x1,"_",x2)) # Action space A.fun = function(x1,x2,...) { list( A1=list(q1 = 0:x1, i1=c(0, if (x1 < x.max) 1)), A2=list(q2 = 0:x2, i2=c(0, if (x2 < x.max) 1)) ) } # State transitions trans.fun = function(ax.df,...) { restore.point("trans.fun") ax.df %>% select(x,x1,x2,i1,i2) %>% unique() %>% mutate( new_x1 = pmin(x1+i1,x.max), new_x2 = pmin(x2+i2,x.max), xd = paste0(new_x1,"_",new_x2), xs=x, prob = 1 ) } g = rel_game("Cournot with Investment") %>% rel_states(x=x.df, A.fun=A.fun, pi1 = (a-(q1+q2))*q1 - i.cost*i1, pi2 = (a-(q1+q2))*q2 - i.cost*i2, trans.fun=trans.fun ) # g %>% rel_spe(delta=0.3) %>% get_eq() %>% select(x, ae.lab,U)

First note that in the call to `rel_states`

, the argument `x`

is not a vector of state names, but instead the data frame `x.df`

specified further above. The data frame has the columns `x1`

and `x2`

that provide additional information about each state, namely the capacities of each player. The additional column `x`

uniquely identifies each state as a label that just pastes `x1`

and `x2`

together.

The additional state variables `x1`

and `x2`

can be used in the formula’s for `pi1`

and `pi2`

, are passed as additional arguments to `A.fun`

, and are additional columns in the `ax.df`

argument passed to `trans.fun`

. You can add as many columns to such a state data frame as you like. The only requirement is that there is a column `x`

with unique values in each row.

The specification of `A.fun`

is pretty straightforward. Note how the action space depends on the current capacity of each player.

More complex is the specification of state transitions in `trans.fun`

. In general it is not easy to specify state transitions correctly on a first trial. I recommend to use debugging via restore points (or some other debugging approach) to build a correct `trans.fun`

. Let me explain, step by step, what we have done.

We start with `ax.df`

which contains one row for each action profile in each state. It looks as follows

```
> ax.df
# A tibble: 1,296 x 8
x1 x2 x .a q1 i1 q2 i2
<int> <int> <chr> <int> <int> <dbl> <int> <dbl>
1 0 0 0_0 1 0 0 0 0
2 0 0 0_0 2 0 0 0 1
3 0 0 0_0 3 0 1 0 0
4 0 0 0_0 4 0 1 0 1
5 0 1 0_1 1 0 0 0 0
6 0 1 0_1 2 0 0 1 0
7 0 1 0_1 3 0 0 0 1
8 0 1 0_1 4 0 0 1 1
9 0 1 0_1 5 0 1 0 0
10 0 1 0_1 6 0 1 1 0
# ... with 1,285 more rows
```

Relevant to compute state transitions are only the investment actions and the state variables. We thus select the relevant columns and reduce to unique rows. We get:

```
ax.df %>%
select(x,x1,x2,i1,i2) %>%
unique()
# A tibble: 121 x 5
x x1 x2 i1 i2
<chr> <int> <int> <dbl> <dbl>
1 0_0 0 0 0 0
2 0_0 0 0 0 1
3 0_0 0 0 1 0
4 0_0 0 0 1 1
5 0_1 0 1 0 0
6 0_1 0 1 0 1
# ... with 115 more rows
```

Starting with this data frame, we can easily compute the new capacities of both players by adding their investments to the current capacities. The new state `xd`

is then simply created by pasting the new capacities together. We also have to add the transition probability of `prob=1`

since state transitions are deterministic and set the source state column `xs`

just to the original state `x`

.

`irv_joint_dist`

: Cournot duopoly where investments are not always successfulConsider now a variant of our previous game in which an investment leads to a successful capacity expansion only with an exogenous success probability `sp`

.

Specifying state transitions becomes more complicated now. Assume both players invest, then there are 4 different possible outcomes: no investment is successful, only player 1’s investment is successful, only player 2’s investment is successful, or both investments are successful.

Relational Contracts has a helper function `irv_joint_dist`

that allows to compute joint distributions of independent discrete random variables using a format suitable to specify state transitions. Consider the following example.

# success probability of investment sp = 0.7 # An example row for which we want # to compute transition probabilities df = tibble(x="0_0",x1=0,x2=0,i1=1,i2=1) # Compute joint distribution of independent # random varibles irv_joint_dist(df, irv("new_x1",default=x1, irv_val(val=x1+1,prob=i1*sp) ), irv("new_x2",default=x2, irv_val(val=x2+1,prob=i2*sp) ) )

```
## # A tibble: 4 x 8
## x x1 x2 i1 i2 prob new_x1 new_x2
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0_0 0 0 1 1 0.490 1 1
## 2 0_0 0 0 1 1 0.21 0 1
## 3 0_0 0 0 1 1 0.21 1 0
## 4 0_0 0 0 1 1 0.09 0 0
```

Inside the call to `irv_joint_dist`

we specify with `irv`

two discrete valued random variables `new_x1`

and `new_x2`

that shall be independently distributed from each other. Inside `irv`

we call `irv_val`

to specify values that the variable can take and their realiziation probabilities. These values and probabilities are computed using the columns of the data frame `df`

passed to `irv_joint_dist`

using lazy evaluation.

For convenience, we can also set a default value for each random variables that is realized with probability 1 minus the sum of probabilities of all explicitly specified probabilities via `irv_val`

. E.g. without default values, we could have equivalently specified `new_x1`

by

For each row of the passed data frame `df`

, `irv_joint_dist`

creates several rows: one for each possible outcome combination of the specified independent random variables. Since `df`

only has a single row and there are 4 combinations of `new_x1`

and `new_x2`

, we get a data frame with 4 rows. The column `prob`

contains the probability of the particular outcome combination.

If `df`

contains multiple rows, these computations will be performed separately for each row and the resulting rows are combined together. Consider this example where in one row player 1 invests and in the other not:

# success probability of investment sp = 0.7 # Two example rows for which we want # to compute transition probabiluties df = tibble(x="0_0",x1=0,x2=0,i1=c(0,1),i2=1) df

```
## # A tibble: 2 x 5
## x x1 x2 i1 i2
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 0_0 0 0 0 1
## 2 0_0 0 0 1 1
```

# Compute joint distribution of independent # random varibles irv_joint_dist(df, irv("new_x1",default=x1, irv_val(val=x1+1,prob=i1*sp) ), irv("new_x2",default=x2, irv_val(val=x2+1,prob=i2*sp) ) )

```
## # A tibble: 6 x 8
## x x1 x2 i1 i2 prob new_x1 new_x2
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0_0 0 0 1 1 0.490 1 1
## 2 0_0 0 0 0 1 0.7 0 1
## 3 0_0 0 0 1 1 0.21 0 1
## 4 0_0 0 0 1 1 0.21 1 0
## 5 0_0 0 0 0 1 0.3 0 0
## 6 0_0 0 0 1 1 0.09 0 0
```

The result has now 2+4=6 rows. If player 1 does not invest (`i1==0`

), the variable `new_x1`

always is 0 and there are only two outcomes.

Note that the order of the resulting rows is not very intutive. Internally `irv_joint_dist`

tries to use vectorization for fast computation that sorts the rows in a peculiar way and for time reasons there is no unneccessary rearrangement afterwards.

Below is a specification of the transition function for our Cournot game using `irv_joint_dist`

:

sp = 0.7 trans.fun = function(ax.df,...) { restore.point("trans.fun") ax.df %>% select(x,x1,x2,i1,i2) %>% unique() %>% irv_joint_dist(df, irv("new_x1",default=x1, irv_val(val=x1+1,prob=i1*sp) ), irv("new_x2",default=x2, irv_val(val=x2+1,prob=i2*sp) ) ) %>% mutate( xd = paste0(new_x1,"_",new_x2), xs=x ) }

This code may look complicated, but specifying transition probabilities correctly is typically the most difficult task in a game specificiation. And while it requires some time to learn, in my experience, `irv_joint_dist`

is often quite a useful tool for this task.

`irv_joint_dist`

: Cournot duopoly where investments are not always successful and capacity may depreciateConsider now a variant in which existing capacity can also depricate with positive depreciation probability `dp`

.

The following code specifies the transition function:

trans.fun = function(ax.df,...) { restore.point("trans.fun") ax.df %>% select(x,x1,x2,i1,i2) %>% unique() %>% irv_joint_dist( irv("add_x1",default=0, irv_val(1,prob=i1*sp) ), irv("add_x2",default=0, irv_val(1,prob=i2*sp) ), irv("rem_x1",default=0, irv_val(1,prob=(x1>0)*dp) ), irv("rem_x2",default=0, irv_val(1,prob=(x2>0)*dp) ) ) %>% mutate( new_x1 = x1+add_x1 - rem_x1, new_x2 = x2+add_x2 - rem_x2, xd = paste0(new_x1,"_",new_x2), xs=x ) %>% group_by(xs,xd,i1,i2) %>% summarize(prob=sum(prob)) }

We now specify 4 independent random variables. Each new capacity now depends on two random variables describing whether or nor investment successful and whether or not there is depreciation.

To understand why the final `group_by`

and `summarize`

is neccessary let us take a look at the computation before for a single intial row:

sp = 0.7 dp = 0.1 tibble(x="1_0",x1=1,x2=0,i1=1,i2=0) %>% select(x,x1,x2,i1,i2) %>% unique() %>% irv_joint_dist( irv("add_x1",default=0, irv_val(1,prob=i1*sp) ), irv("add_x2",default=0, irv_val(1,prob=i2*sp) ), irv("rem_x1",default=0, irv_val(1,prob=(x1>0)*dp) ), irv("rem_x2",default=0, irv_val(1,prob=(x2>0)*dp) ) ) %>% mutate( new_x1 = x1+add_x1 - rem_x1, new_x2 = x2+add_x2 - rem_x2, xd = paste0(new_x1,"_",new_x2), xs=x ) %>% select(xs,xd,i1,i2,prob,add_x1,rem_x1)

```
## # A tibble: 4 x 7
## xs xd i1 i2 prob add_x1 rem_x1
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1_0 1_0 1 0 0.0700 1 1
## 2 1_0 0_0 1 0 0.03 0 1
## 3 1_0 2_0 1 0 0.63 1 0
## 4 1_0 1_0 1 0 0.27 0 0
```

We see that both the first and last row transist to the same state. In the first row both investment and depreciation for player 1 happens, and in the last row neither one happens. Both yield the same net result: no change of capacity. The final `group_by`

and `summarize`

command inside `trans.fun`

add up the probabilities of such rows with the same outcomes.

Consider the following variant of the dynamic Cournot duopoly, where we have splitted the “static” actions `q1`

and `q2`

which don’t affect the state transitions from the “dynamic” actions `i1`

and `i2`

:

x.max = 5 # State matrix x.df = tidyr::expand_grid(x1=0:x.max, x2=0:x.max) %>% mutate(x=paste0(x1,"_",x2)) # static action space static.A.fun = function(x1,x2,...) { list( A1=list(q1 = 0:x1), A2=list(q2 = 0:x2) ) } # dynamic action space A.fun = function(x1,x2,x.max,...) { list( A1=list(i1=c(0, if (x1 < x.max) 1)), A2=list(i2=c(0, if (x2 < x.max) 1)) ) } # State transitions: deterministic investments trans.fun = function(ax.df,x.max,...) { restore.point("trans.fun") ax.df %>% select(x,x1,x2,i1,i2) %>% unique() %>% mutate( new_x1 = pmin(x1+i1,x.max), new_x2 = pmin(x2+i2,x.max), xd = paste0(new_x1,"_",new_x2), xs=x, prob = 1 ) } g = rel_game("Cournot with Investment") %>% rel_param(a = 10,i.cost = 1.5,x.max=x.max) %>% rel_states(x=x.df, A.fun=A.fun, static.A.fun = static.A.fun, static.pi1 = (a-(q1+q2))*q1, static.pi2 = (a-(q1+q2))*q2, pi1 = - i.cost*i1, pi2 = - i.cost*i2, trans.fun=trans.fun ) g %>% rel_spe(delta=0.3) %>% get_eq() %>% select(x, ae.lab,U)

```
## x ae.lab U
## 1 0_0 0 | 0 | 1 | 1 2.835
## 2 0_1 0 | 1 | 1 | 1 10.500
## 3 0_2 0 | 2 | 1 | 0 16.450
## 4 0_3 0 | 3 | 1 | 0 20.850
## 5 0_4 0 | 4 | 0 | 0 24.000
## 6 0_5 0 | 5 | 0 | 0 25.000
## 7 1_0 1 | 0 | 1 | 1 10.500
## 8 1_1 1 | 1 | 0 | 1 16.450
## 9 1_2 1 | 2 | 0 | 0 21.000
## 10 1_3 1 | 3 | 0 | 0 24.000
## 11 1_4 1 | 4 | 0 | 0 25.000
## 12 1_5 1 | 4 | 0 | 0 25.000
## 13 2_0 2 | 0 | 0 | 1 16.450
## 14 2_1 2 | 1 | 0 | 0 21.000
## 15 2_2 2 | 2 | 0 | 0 24.000
## 16 2_3 2 | 3 | 0 | 0 25.000
## 17 2_4 2 | 3 | 0 | 0 25.000
## 18 2_5 2 | 3 | 0 | 0 25.000
## 19 3_0 3 | 0 | 0 | 1 20.850
## 20 3_1 3 | 1 | 0 | 0 24.000
## 21 3_2 3 | 2 | 0 | 0 25.000
## 22 3_3 2 | 3 | 0 | 0 25.000
## 23 3_4 3 | 2 | 0 | 0 25.000
## 24 3_5 3 | 2 | 0 | 0 25.000
## 25 4_0 4 | 0 | 0 | 0 24.000
## 26 4_1 4 | 1 | 0 | 0 25.000
## 27 4_2 3 | 2 | 0 | 0 25.000
## 28 4_3 2 | 3 | 0 | 0 25.000
## 29 4_4 2 | 3 | 0 | 0 25.000
## 30 4_5 2 | 3 | 0 | 0 25.000
## 31 5_0 5 | 0 | 0 | 0 25.000
## 32 5_1 4 | 1 | 0 | 0 25.000
## 33 5_2 3 | 2 | 0 | 0 25.000
## 34 5_3 2 | 3 | 0 | 0 25.000
## 35 5_4 2 | 3 | 0 | 0 25.000
## 36 5_5 2 | 3 | 0 | 0 25.000
```

If we specify static actions via `static.A.fun`

, or`static.A1`

and `static.A2`

it means that each period consists of two stages in which actions can be chosen (each preceded by a stage in which transfers can be performed). First, the static actions are chosen and then the dynamic actions. Splitting up actions in this fashion can substantially reduce numerical complexity in form of memory requirements and run time of the solution algorithms.

Note that we have also have specified here the parameters `x.max`

, `i.cost`

and `a`

via the function `rel_param`

. All the specified parameters will be passed to the different functions like `trans.fun`

that specify the game and can be used in expressions like `pi1`

that will be lazily evaluated.

There are some advantages to specify the game such that each period only a randomly selected player is able to make investment. For example, with simultaneous investment choices sometimes no pure strategy equilibria may exist. See the 2nd vignette how to implement and analyse such games with staggered moves.

So far we have specified the parameters `x.max`

, `i.cost`

and `a`

as global variables. Alternatively, you could also specify them in the game using the function `rel_param`

. Consider the following variant:

# Action space A.fun = function(x1,x2,x.max,...) { list( A1=list(q1 = 0:x1, i1=c(0, if (x1 < x.max) 1)), A2=list(q2 = 0:x2, i2=c(0, if (x2 < x.max) 1)) ) } # State transitions trans.fun = function(ax.df,x.max,...) { restore.point("trans.fun") ax.df %>% select(x,x1,x2,i1,i2) %>% unique() %>% mutate( new_x1 = pmin(x1+i1,x.max), new_x2 = pmin(x2+i2,x.max), xd = paste0(new_x1,"_",new_x2), xs=x, prob = 1 ) } # State matrix x.max = 5 x.df = tidyr::expand_grid(x1=0:x.max, x2=0:x.max) %>% mutate(x=paste0(x1,"_",x2)) g = rel_game("Cournot with Investment") %>% rel_param(a = 10,i.cost = 1.5,x.max=x.max) %>% rel_states(x=x.df, A.fun=A.fun, pi1 = (a-(q1+q2))*q1 - i.cost*i1, pi2 = (a-(q1+q2))*q2 - i.cost*i2, trans.fun=trans.fun ) g %>% rel_spe(delta=0.3) %>% get_eq() %>% select(x, ae.lab,U)

```
## # A tibble: 36 x 3
## x ae.lab U
## <chr> <chr> <dbl>
## 1 0_0 0 1 | 0 1 2.84
## 2 0_1 0 1 | 1 1 10.5
## 3 0_2 0 1 | 2 0 16.4
## 4 0_3 0 1 | 3 0 20.8
## 5 0_4 0 0 | 4 0 24.0
## 6 0_5 0 0 | 5 0 25
## 7 1_0 1 1 | 0 1 10.5
## 8 1_1 1 0 | 1 1 16.4
## 9 1_2 1 0 | 2 0 21
## 10 1_3 1 0 | 3 0 24.0
## # ... with 26 more rows
```

The specified parameters will then be passed as additional arguments to `A.fun`

, `trans.fun`

etc and will also be used when `pi1`

and `pi2`

are evaluated.

If you want to create at the same time several game obects with different parameters, it seems advisable to store parameters inside the game and not rely on global variables. Otherwise it is a matter of taste, which style you want to use.