sindae.solvers
Backend selection for the two solver roles in SiNDAE. The NLP solver optimises each Pyomo model; the linear (KKT) solver runs the sparse back-solve inside the decomposition gradient.
make_nlp_solverselects the NLP backend:pounce(the pip-installable default),ipopt, orcyipopt.make_linear_solverselects the linear/KKT backend:feral(the pip-installable default),ma27, orscipy.NLPSolveris the abstract backend interface returned bymake_nlp_solver;NLPResultis what itssolvemethod returns.SolverConfigis the typed home for NLP solver options (tol,max_iter, ...);HybridDAE(solver_options=)requires it, and everything else accepts it interchangeably with a plain option dict.
The stage functions take these selectors directly, so a backend can be chosen without
touching the package internals. solve_smoother, generate_data, solve_simultaneous
(both the expression-writing and grey-box paths), solve_inference, and train_decomp
all accept nlp_solver= (default pounce) and solver_options= (a plain dict or a
SolverConfig), and train_decomp takes
linear_solver= for the KKT back-solve.
POUNCE solves the grey-box (ExternalGreyBoxBlock) models too, through its cyipopt-style
interface, so cyipopt is no longer required for the decomposition, inference, or grey-box
simultaneous solves. cyipopt and ipopt remain selectable, not removed.
Usage¶
import sindae as sd
from sindae.algorithms.smoother import solve_smoother
from sindae.algorithms.decomp.train import train_decomp
# Pick the NLP backend for a stage (default is "pounce"):
smoother_m = solve_smoother(problem, mlp, smooth_coef=1.0, nlp_solver="ipopt")
# Pick the KKT linear solver for decomposition training (default is "feral"):
trained_m, mlp, history = train_decomp(
problem, mlp, cfg, data=smoother_data, linear_solver="ma27",
)
# Build a configured solver directly (power-user path):
solver = sd.make_nlp_solver("cyipopt", options={"tol": 1e-8})
result = solver.solve(model) # returns an NLPResultAPI reference¶
SolverConfig¶
class SolverConfig(
tol: Optional[float] = None,
max_iter: Optional[int] = None,
mu_strategy: Optional[str] = None,
hessian_approximation: Optional[str] = None,
print_level: Optional[int] = None,
extra_options: dict = dict(),
)Typed options for an NLP backend.
Named fields cover the common IPOPT-family options; anything else goes in
extra_options (a plain option-name -> value dict). Fields left as
None are omitted, so the backend’s own defaults apply. On a name
collision the named field wins over extra_options.
Accepted anywhere solver options are taken: HybridDAE(solver_options=)
requires it, and :func:make_nlp_solver / the stage functions accept it
interchangeably with a plain dict.
Fields
tol(Optional[float], defaultNone)max_iter(Optional[int], defaultNone)mu_strategy(Optional[str], defaultNone)hessian_approximation(Optional[str], defaultNone)print_level(Optional[int], defaultNone)extra_options(dict, defaultdict())
make_nlp_solver¶
make_nlp_solver(
backend: Union[str, NLPSolver] = 'pounce',
options: Union[dict, SolverConfig, None] = None,
) -> NLPSolverBuild an :class:NLPSolver for backend.
backend may be a name ("pounce" (default), "ipopt",
"cyipopt"; case-insensitive) or an existing :class:NLPSolver, which is
returned unchanged (options are ignored in that case — a warning is
logged if any were passed). options may be a plain option dict or a
:class:SolverConfig.
Parameters
backend(Union[str, NLPSolver], default'pounce')options(Union[dict, SolverConfig, None], defaultNone)
Returns
NLPSolver
make_linear_solver¶
make_linear_solver(name: Union[str, object] = 'feral', **kwargs)Build a linear / KKT solver implementing Pyomo’s
IPLinearSolverInterface.
name may be "feral" (default), "ma27", "scipy"
(case-insensitive) or an already-constructed interface, which is returned
unchanged (keyword arguments are ignored in that case — a warning is
logged if any were passed). Extra keyword arguments are forwarded to the
constructor (used by FERAL’s max_steps / refine_tol /
residual_tol).
Parameters
name(Union[str, object], default'feral')**kwargs(default{})
NLPSolver¶
class NLPSolver(options: Optional[dict] = None)Abstract NLP backend wrapping a configured Pyomo solver.
Concrete subclasses set name (the SolverFactory name) and, when
applicable, the is_cyipopt / supports_return_nlp capability flags.
The underlying Pyomo solver is built once at construction and reused across
:meth:solve calls (matching the decomposition loop, which solves the same
model hundreds of times).
Parameters
options(Optional[dict], defaultNone)
Properties
name— TheSolverFactoryname for this backend.pyomo_solver— The underlying configured Pyomo solver (for advanced tuning).
Methods
solve¶
solve(
model,
*,
tee: bool = False,
extra_options: Optional[dict] = None,
return_nlp: bool = False,
) -> NLPResultSolve model, capturing solver timing from its log output.
The ASL executables do not all honour IPOPT’s output_file option
(POUNCE ignores it), so on the ASL path the subprocess stdout is
captured to a temporary file via pyomo’s logfile= mechanism
(tee=True still streams to the console). cyipopt runs in-process
and IPOPT itself writes the log via output_file.
Parameters
modeltee(bool, defaultFalse) — Stream solver output to stdout.extra_options(Optional[dict], defaultNone) — Per-call options overlaid on the persistent solver options for this solve only (the persistent options are left untouched).return_nlp(bool, defaultFalse) — Return the populated NLP alongside the results (raisesValueErrorfor backends that do not support it).
Returns
NLPResult
NLPResult¶
class NLPResult(result: object, timing: dict, nlp: object = None)Outcome of one :meth:NLPSolver.solve call.
Fields
result(object)timing(dict)nlp(object, defaultNone)