QuantEcon / QuantEcon/ContinuousDPs.jl
ENH: Accept a function for v_init, evaluated at the solver's basis nodes
Nobody has claimed this yet.
- Dominant language
- Julia
- Stars
- 17
- Forks
- 11
- PR merge metrics
- No merged PRs in 30d
Description
Motivation
A good v_init is naturally a function of the state, but the keyword takes a vector of values at the solver's collocation nodes, which couples the caller to two pieces of solver-internal information: the node count (length(basis)) and the node ordering (the gridmake convention, first dimension fastest). The canonical construction is boilerplate that every user has to rediscover:
S = nodes(basis)[1]
v_init = [v_guess(S[i, :]) for i in 1:size(S, 1)]
The need is not hypothetical: for the monetary policy model (MF §9.7.5), PFI from the default v_init = zeros(...) fails — the reward is independent of x, so with a constant value guess the inner objective is flat and the first greedy policy is indeterminate, after which Newton-style policy iteration cycles between corner policies (unstable uncontrolled dynamics + out-of-domain extrapolation in the policy evaluation). Any reasonable non-constant shape (e.g. a rough quadratic $-|s - s^*|^2$, or the LQA solution) fixes it. Users should be able to express such a guess directly as a function, robustly to later changes of the basis size.
Proposal
Let v_init also accept a callable, evaluated internally at the solver's nodes:
res = solve(cdp, solver; v_init = s -> -norm(s - s_target)^2)
- The callable receives one state point per node, following the same convention as
fandg(a scalar forN == 1, a length-Nvector forN >= 2), and must return a real number. - The vector form stays as is (values at
nodes(solver.basis)[1], in order), including its length validation and error message. - Applies to both
CollocationSolverandLQASolverentrances (they share the samev_inithandling).
Implementation sketch
A new _check_v_init(v_init, interp::Interp) method for the callable case: evaluate at _row(interp.S, i) for i in 1:interp.length into a Vector{Float64}; dispatch keeps nothing (zeros) and AbstractVector behavior untouched. Non-breaking 0.3.x addition.
Tests
- Callable vs. manually evaluated vector give identical results (
N = 1andN = 2). - The flat-degeneracy case: a non-constant callable
v_initas the documented remedy (cf. the monetary policy example). - Wrong-length vector error unchanged; a callable returning a non-real value errors informatively.
🤖 Generated with Claude Code (Claude Fable 5)
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the shared v_init handling and the proposed _check_v_init(v_init, interp::Interp) entry point, then trace how CollocationSolver and LQASolver pass through it. Run the existing solver tests first, add coverage for N = 1 and N = 2 callable inputs, and verify vector behavior and invalid callable results remain clear and unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- julia
- Domain
- backend
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 72/100