# QODE Problem and Protocol **English** · 简体中文 > Category C2 · Module [`oracq.algorithms.qode.ode`](../../api/algorithms/qode/ode.rst) · Stage V2 ## Overview This module does not implement a concrete solving algorithm; instead, for the autonomous homogeneous linear ODE $$ u'(t) = G\,u(t),\qquad u(0)=u_0 $$ it defines three composable building blocks: the problem object {obj}`QODEProblem ` (generator, initial state, dissipation declaration, and evidence note), the replaceable protocol {obj}`QODEProtocol ` (contract checks and declaration pass-through), and the generic entry {obj}`linear_qode `, which routes $G$ to a concrete method such as LCHS, CBMD, or Schrödingerization. It also provides {obj}`make_euler_history_qode `, which writes implicit Euler time marching as one quantum linear-system solve. The design stance is "declaration first": `dissipative` is the mathematical declaration $\mathrm{Hermitian}(G)\le 0$, not a language proof; the `evidence` field forces the source of the declaration to be recorded. For the full user-facing workflow (input paradigm adaptation, batched binding) see [the differential equations chapter](../differential-equations.md). ## Interface and input model ```python QODEProblem(generator, initial, dissipative=None, initial_norm=None, evidence="caller_declared_unverified") linear_qode(method, *, hamiltonian_function=taylor_hamiltonian, **options) make_euler_history_qode(qlss, *, steps=2) ``` API entries: {obj}`QODEProblem `, {obj}`linear_qode `, {obj}`make_euler_history_qode ` - `generator`: a {obj}`BlockEncoding ` of $G$ (the input model is a BE); it must have adjoint/controlled capabilities. - `initial`: a {obj}`StatePreparation ` (SP) with zero input and clean work, of the same width as `generator`. - `dissipative` / `initial_norm`: a `bool | None` dissipation declaration and the non-negative initial-value norm. - `evidence`: a non-empty string describing the source of the declaration. - `method`: `"lchs"` / `"cbmd"` / `"schrodingerization"`; `options` accepts only `plan`, whose type must match the chosen method. - `qlss`: a callable linear-system solver (such as the Costa route in `qlss.py`) with signature `(matrix, rhs)`. `linear_qode` returns a `QODEProtocol` (fields `name`, `kernel`, `requires_dissipative`, which is `True` for lchs/cbmd). Protocol methods: | Method | Behavior | |---|---| | `check(generator, initial=None, time=None)` | contract report: BE/SP capabilities, equal widths, non-negative time, dissipation premise | | `__call__(generator, initial, time)` | compatibility entry: generates after check passes, returns {obj}`StateOracle ` | | `solve(problem, time)` | problem-level entry: validates the `QODEProblem`, then generates (recommended) | The `StateOracle` returned by `solve` (`target`/`signal`, width equal to `generator.width`) passes the problem declarations through, on top of the method's own attributes: | Attribute | Meaning | |---|---| | `qode_input_evidence` | the `evidence` of the problem object | | `qode_dissipative_promise` | the declared `dissipative` (only when not None) | | `qode_initial_norm` | the declared initial-value norm (only when not None) | ## Implementation notes `QODEProtocol.contract` adds per-method assumptions on top of the shared {obj}`operator_state_contract `: lchs/cbmd append "Hermitian(G)<=0; problem-level solve must declare dissipative=True", and schrodingerization appends the application-layer validation responsibility for the auxiliary window, the Fourier convention, and the recovery region. `_generate` forces the output to be a `StateOracle`, of the same width as the input, that keeps adjoint/controlled capabilities; violations raise {obj}`ContractError ` at generation time. The lchs/cbmd routes internally first construct {obj}`LinearODE(HermitianParts.from_operator(scale(-1, generator)), initial) `, i.e. the $L+iH$ decomposition of $A=-G$; schrodingerization consumes $G$ directly. Hermitian/positive-semidefinite properties are all borne by the caller. The history-state layout of `make_euler_history_qode`: the time register `nt = steps.bit_length()` bits sits in the high bits, the physical register in the low bits. The system matrix is the LCU symbolic sum $$ C = I - \Delta t\,(q\otimes G) - (S\otimes I),\qquad \Delta t = T/\text{steps}, $$ where `q = projector(nt, range(1, steps + 1))` restricts $G$ to the time slots $1..\text{steps}$ and `S = truncated_shift(nt, steps)` is the inter-slot raising shift; expanded, the equation of each slot is exactly implicit Euler $(I-\Delta t\,G)\,u_k = u_{k-1}$, and slot 0 is filled with the initial state by {obj}`extend_initial `. After `qlss(c, rhs)` solves, {obj}`select_subspace ` selects the snapshot of time slot `steps`, with the selection condition folded into the signal. Not implemented: the inhomogeneous $u'=Gu+f$, time-dependent $G(t)$, and a unified physical-norm recovery object have no ready interface; `solve` only stores the source of the declarations and does not add fabricated norm-recovery capabilities. ## Validation approach Category C2 (approximately continuous semantics; the acceptance criteria are in `../development/validation-plan.md` §2). This page covers the assembly and contract layers; the numerical witnesses of each concrete method are on the method pages. Three layers of evidence: - Structure: `tests/core/test_differential.py:DifferentialStructureTests.test_four_methods_keep_input_oracles` — after generation with abstract BE/SP inputs, all three `linear_qode` methods keep the open slots (`input_A`/`input_b`) as is, the `algorithm` attribute is correct, and the RIR round-trips through serialization. - Numerical: `tests/core/test_sde.py:SolverContractTests.test_qode_problem_accepted_by_lchs` — a `QODEProblem` on a 4-point OU grid goes through `check().require()` and `solve`; the output width, the `qode_dissipative_promise` pass-through, and the program serialization round trip are all correct. - Binding: same-type registration and contract checks; the assembly of `make_euler_history_qode` enters the catalog-level round trip, closure, and export checks of `tests/core/test_workloads.py:WorkloadTests.test_every_catalog_case_has_a_closed_description` through the catalog's QHAM m=1 case (`applications/catalog.py`, `steps=1` connected to the Costa QLSS). ## Known gaps and planned stages A unified "analytically solvable ODE family" convergence benchmark is missing (a batch cross-check running the same analytically solvable problem through all solvers has not been established); it is assigned to the stage V2 convergence-sweep framework, consistent with the ode.py row of `validation-coverage.md`. ## Numerical validation Paper-grade numerical experiments are in `tests/verification/verify_ode.py` (the ode group; this file covers the parts of `ode.py` and `ode_models.py`). The numerical behavior of `QODEProtocol`/`linear_qode` routing and `QODEProblem.solve` is validated by the end-to-end cases of each method (see the numerical validation sections of [LCHS](lchs.md), [CBMD](cbmd.md), [Schrödingerization](schrodingerization.md), and [Carleman linearization](carleman.md)). **Experiment design**: (a) `linear_qode("lchs")` routing — end-to-end cross-checks of five input models (the $A=-G$ alignment of `HermitianParts.from_operator(scale(-1, G))` confirmed by an independent numpy simulation); (b) `QODEProblem.solve` — a 4-point OU zero-flux Fokker–Planck problem (`dissipative=True`, evidence pass-through) goes through `check().require()` and `solve`, with the output width, the `qode_dissipative_promise` pass-through, and the numerical solution verified together; (c) declaration pass-through — the `qode_input_evidence`/`qode_dissipative_promise` attributes appear in the output module's attributes as declared. **Key metrics**: | Case | Scale | Paths | Metric | Value | |---|---|---|---|---| | lchs-given-be-scalar-decay | 7 qubits | four paths | implementation error (routing + assembly vs independent simulation) | 1.2e-16 | | lchs-fokker-planck-ou | 16 qubits | reference, originir | implementation error / cross-check between classical references / `qode_dissipative_promise` | 1.1e-16 / 1.1e-16 / True pass-through | | cbmd-parts-noncommuting | 15 qubits | reference, originir | implementation error (CBMD routing) | 1.1e-16 | | schrodingerization-* | 21 qubits | reference, originir (decay-grid) / reference (the rest) | assembly fidelity (Schrödingerization routing) | 8.7e-19 | The implicit Euler history assembly of `make_euler_history_qode` (the LCU symbolic sum $C=I-\Delta t(q\otimes G)-(S\otimes I)$) is covered by the catalog's QHAM m=1 case structure test; this group does not run a numerical end-to-end validation of it (that requires a complete QLSS kernel, which is out of scope for this group). **Reproduction**: ```bash PYTHONPATH=src /home/agony/projects/qcfd-dev/quantum-cfd-software/.venv/bin/python tests/verification/verify_ode.py ``` Artifacts: `out/verification/ode.json`. ## Related links - Source: `src/oracq/algorithms/qode/ode.py` - Tutorial: [Swapping QODE methods for the same linear problem](../../tutorials/differential-equations.md) - API reference: [QODE assembly interface](../../api/algorithms/qode/ode.rst) - Pages in the same group: [LCHS](lchs.md) · [CBMD](cbmd.md) · [Schrödingerization](schrodingerization.md) · [Carleman linearization](carleman.md) · [Fokker–Planck input model](fokker-planck.md) - Concepts: [Conventions owned by algorithms: starting from one gate](../contracts.md) - Validation matrix: [Validation coverage matrix](../../development/validation-coverage.md)