Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Parameters

Parameters are the numerical inputs to your model — discount factors, wages, risk aversion coefficients, and so on. pylcm discovers parameters automatically from function signatures.

Always start from model.get_params_template(). Specialized solver declarations, certainty equivalents, collective value constraints, and per-target transitions add branches that are easy to miss in a hand-written parameter dictionary.

Getting the Parameter Template

template = model.get_params_template()

This returns a mutable nested dict showing every parameter the model expects, organized as {regime_name: {function_name: {param_name: type_name}}}. Parameters of callables declared in Model(edges=...) sit under one more root, "edges"; see Edge parameters. Use the template as a starting point to see what values you need to provide.

Inspect the template, then write each parameter value deliberately. Filling every entry with a blanket default can hide a misspelled argument: an unresolved name is still a runtime parameter. When a name resembles a state, action or function in its regime, the displayed entry includes a hint, for example "consumptioz": "FloatND [close to action 'consumption'; typo?]". These hints do not change parameter resolution or emit a warning at model build.

For profiles indexed by age or period, use explicit temporal declarations and labelled values; see Periods and temporal parameters.

Only free parameters appear in the template — arguments that are states, actions, or outputs of other functions in the DAG are resolved automatically and do not show up here.

Parameter Structure

Parameters follow a three-level hierarchy. You can specify a parameter at whichever level is most convenient.

Function level (most specific)

params = {
    "working_life": {
        "utility": {"risk_aversion": 1.5},
        "earnings": {"wage": 20.0},
    },
}

Regime level

A parameter specified at regime level applies to all functions within that regime that need it:

params = {
    "working_life": {"risk_aversion": 1.5},
}

Model level (most general)

A parameter specified at model level applies everywhere it is needed:

params = {
    "risk_aversion": 1.5,
    "discount_factor": 0.95,
}

All parameters at model level

When every parameter has a single value across all regimes and functions, you can specify everything at the top level:

params = {
    "discount_factor": 0.95,
    "risk_aversion": 1.5,
    "wage": 20.0,
    "interest_rate": 0.03,
    "consumption_floor": 2.0,
    "tax_rate": 0.2,
    "disutility_of_work": 1.0,
    "last_working_age": 45,
}

Mixing Levels

You can mix levels freely — just avoid ambiguity:

params = {
    "discount_factor": 0.95,  # model level
    "interest_rate": 0.03,  # model level
    "working_life": {
        "utility": {
            "disutility_of_work": 1.0,  # function level
        },
        "earnings": {"wage": 20.0},  # function level
    },
}

The Ambiguity Rule

A parameter cannot appear at multiple levels within the same subtree. pylcm raises an InvalidNameError if a parameter value could be resolved from more than one level:

Edge parameters

The regime-transition law, gates and route fallbacks are declared in Model(edges=...), and their parameters live at their declaration path under params["edges"] rather than under a regime:

params = {
    "discount_factor": 0.95,
    "working_life": {"utility": {"disutility_of_work": 1.0}},
    "edges": {"working_life": {"last_working_age": 45}},
}

A law over all targets reads params["edges"][source][arg]; a per-target cell reads params["edges"][source][target][arg]. Their values resolve from the exact path, from params["edges"][source][arg] (every edge callable of that source), or from the model level. A value under the regime, params["working_life"]["last_working_age"], feeds only that regime’s own functions and never an edge callable. Per-target state laws belong to their regime and keep their paths there. The full path table: Edge parameter paths.

Special Parameters

discount_factor

Used by the default Koopmans aggregator W(utility,CE,discount_factor)=utility+discount_factor⋅CEW(\text{utility}, \text{CE}, \text{discount\_factor}) = \text{utility} + \text{discount\_factor} \cdot \text{CE}.

Typically set at model level:

params = {"discount_factor": 0.95}

Not needed if you supply a custom koopmans_aggregator that takes no discount_factor.

Shock parameters

Shock grids with None parameters (deferred to runtime) expect their values in the params dict. They follow the same hierarchy rules. See Continuous stochastic processes for details.

Fixed parameters

Parameters can be baked into the model at initialization time via fixed_params:

model = Model(
    ...,
    fixed_params={"discount_factor": 0.95, "interest_rate": 0.03},
)

Fixed parameters are partialled into compiled functions and removed from the template. You don’t need to supply them at solve() / simulate() time.

Recommended workflow for estimation: In estimation contexts, fixed_params should contain everything except the parameters you are estimating. This avoids passing a large params dict on every likelihood evaluation and makes the estimated parameter set explicit.

# During estimation, only risk_aversion and disutility_of_work are free
model = Model(
    ...,
    fixed_params={
        "discount_factor": 0.95,
        "interest_rate": 0.03,
        "wage": 20.0,
        "consumption_floor": 2.0,
        "tax_rate": 0.2,
        "last_working_age": 45,
    },
)

# The solve/simulate calls only need the estimated parameters
params = {"risk_aversion": 1.5, "disutility_of_work": 1.0}
result = model.simulate(
    params=params,
    initial_conditions=...,
    log_level="debug",
)

What Counts as a Parameter?

pylcm inspects function signatures and classifies each argument:

Functions retained only for reporting use the same parameter rules. Declare them with output_only_functions= on the model or regime; their unresolved arguments appear in this template and must be supplied even when solving without reporting those functions. See Output-only functions.

See Also