Skip to content

Model Structure

The Dolo Model Object

The Model class (dolo/compiler/model.py) is the central data structure in dolo. It contains everything about your economic model.

Core Components

1. Symbols (model.symbols)

A dictionary categorizing all variables in your model:

model.symbols = {
    'exogenous': ['y'],        # Exogenous shocks
    'states': ['w'],           # State variables
    'controls': ['c'],         # Choice/control variables
    'expectations': ['mr'],    # Expectation variables
    'poststates': ['a'],       # Post-decision states
    'parameters': ['β', 'γ', 'σ', 'ρ', 'r']  # Fixed parameters
}

Key Points: - Each category can have multiple variables: states: [k, h, z] - Order matters - it determines array indexing - Parameters are treated separately from dynamic variables

2. Equations (model.equations)

Dictionary of equation blocks from your YAML:

model.equations = {
    'transition': 'w[t] = exp(y[t]) + (w[t-1]-c[t-1])*r',
    'arbitrage': 'β*(c[t+1]/c[t])^(-γ)*r - 1',
    'auxiliary_direct_egm': 'a[t] = w[t] - c[t]',
    # ... more equation blocks
}

Types of Equations: - transition - State evolution - arbitrage - Optimality conditions (Euler equations) - expectation - Computing expectations - auxiliary_* - Helper equations for solution methods - Custom blocks for specific algorithms

3. Calibration (model.calibration)

Parameter values and initial conditions:

model.calibration = CalibrationDict({
    # Parameters
    'β': 0.96,
    'γ': 4.0,
    'σ': 0.1,
    'ρ': 0.0,
    'r': 1.0,

    # Initial values for variables
    'w': 1.0,
    'c': 0.9,
    # ...
})

Access Methods:

# Get flat dictionary
params = model.calibration.flat

# Access individual values
beta = model.calibration['β']

# Iterate
for param_name in model.calibration:
    value = model.calibration[param_name]

4. Functions (model.functions)

Compiled, vectorized versions of equations:

model.functions = LoosyDict({
    'transition': <standard_function>,
    'arbitrage': <standard_function>,
    'expectation': <standard_function>,
    # ... one for each equation block
})

Properties of Functions: - Type: dolang.vectorize.standard_function - Wraps numpy ufuncs for vectorization - Callable with array inputs - Support automatic differentiation

5. Domain (model.domain)

State space bounds and constraints:

model.domain = {
    'w': [0.01, 4.0]  # wealth bounds [min, max]
}

6. Exogenous Process (model.exogenous)

Stochastic process specification:

model.exogenous = UNormal(sigma=0.1)  # IID normal shocks
# or
model.exogenous = VAR1(...)  # AR(1) process
# or
model.exogenous = MarkovChain(...)  # Discrete Markov chain

7. Options (model.options)

Solver and grid specifications:

model.options = {
    'grid': Cartesian(
        orders=[100],           # Grid points
        bounds=[[0.0, 4.0]]    # Grid bounds
    )
}

Model Class Hierarchy

Model (main class)
├── SymbolicModel (handles symbolic expressions)
│   ├── symbols
│   ├── equations
│   └── definitions
└── NumericModel (handles numeric operations)
    ├── calibration
    ├── functions (compiled)
    ├── domain
    └── exogenous

Key Methods

Property Methods (Lazy Evaluation)

@property
def functions(self):
    if self.__functions__ is None:
        self.__compile_functions__()
    return self.__functions__

Functions are compiled on first access, not at model creation.

Compilation Methods

def __compile_functions__(self):
    # 1. Get all equation names
    funnames = [*self.equations.keys()]

    # 2. For each equation, create compiled function
    for funname in funnames:
        factory = get_factory(self, funname)
        fun, gufun = make_method_from_factory(factory)
        functions[funname] = standard_function(gufun, n_output)

Internal Storage

The Model uses several private attributes for caching:

self.__functions__ = None      # Compiled functions (lazy)
self.__symbols__ = None        # Symbol dictionary (lazy)
self.__equations__ = None      # Parsed equations (lazy)
self.__calibration__ = None    # Calibration dict (lazy)

These are populated on first access to avoid unnecessary computation.

Data Flow

YAML Data (self.data)
Symbol Extraction (self.symbols)
Equation Parsing (self.equations)
Function Compilation (self.functions)
Ready for Numerical Methods

Special Features

LoosyDict

Custom dictionary with equivalence mappings:

functions = LoosyDict(equivalences={'equilibrium': 'arbitrage'})
# Can access functions['equilibrium'] or functions['arbitrage']

CalibrationDict

Special dictionary for parameters that: - Handles symbolic expressions - Provides flat access - Supports dependencies between parameters

Next: YAML to Model Conversion →