Library Quickstart#

Use this page when you want the shortest route from a working installation to a first direct finhjb solve, without going through the BCW examples.

The example below is deliberately small. It is not meant to be an economic model; it is meant to show the package object split clearly.

Before You Start#

Smallest Useful Solve#

The following example is intentionally tiny. It is not a research model. It is a package smoke test that shows the Parameter / Boundary / PolicyDict / Policy / Model split clearly.

from dataclasses import dataclass

import jax.numpy as jnp
import finhjb as fjb


class Parameter(fjb.AbstractParameter):
    offset: float = 0.0


class PolicyDict(fjb.AbstractPolicyDict):
    control: object


@dataclass
class Boundary(fjb.AbstractBoundary[Parameter]):
    pass


@dataclass
class Policy(fjb.AbstractPolicy[Parameter, PolicyDict]):
    @staticmethod
    def initialize(grid: fjb.Grid, p: Parameter) -> PolicyDict:
        return PolicyDict(control=jnp.zeros_like(grid.s))

    @staticmethod
    @fjb.explicit_policy(order=1)
    def keep_zero(grid: fjb.Grid) -> fjb.Grid:
        grid.policy["control"] = jnp.zeros_like(grid.s)
        return grid


@dataclass
class Model(fjb.AbstractModel[Parameter, PolicyDict]):
    @staticmethod
    def hjb_residual(v, dv, d2v, s, policy, jump, boundary, p):
        return v - (s + p.offset)

    @staticmethod
    def auxiliary(grid: fjb.Grid):
        return {"value_mean": jnp.mean(grid.v)}


parameter = Parameter()
boundary = Boundary(
    p=parameter,
    s_min=0.0,
    s_max=1.0,
    v_left=0.0,
    v_right=1.0,
)
solver = fjb.Solver(
    boundary=boundary,
    model=Model(policy=Policy()),
    policy_guess=True,
    number=200,
    config=fjb.Config(derivative_method="central"),
)

state, history = solver.solve()
grid = state.grid

print(type(state).__name__)
print(history.shape)
print(grid.df.head())
print(grid.aux)

What This Example Shows#

  • Parameter holds model inputs.

  • Boundary defines the state and value boundaries.

  • PolicyDict declares the policy arrays the solver will manage.

  • Policy provides initialization and policy updates.

  • Model.hjb_residual(...) is the core equation the solver tries to drive to zero.

This is the minimum direct package workflow. It is the right starting point when you want to build your own model instead of reproducing BCW first.

What To Inspect First#

After a first solve, check these objects first:

  • type(state).__name__

  • history

  • state.grid.boundary

  • state.grid.df.head()

  • state.grid.df.tail()

  • state.grid.aux if your model implements auxiliary(grid)