Composing PDE inputs and solve instances¶
English · 简体中文
PDEProblem describes an equation, a grid, physical initial data, and the final
time. qpde_solve selects a method; prepare() checks its input requirements
and generates a reusable modular RIR circuit. Export, resource estimation, and
native execution all use that same prepared circuit. Neither problem creation
nor preparation imports a quantum backend.
Prepare, inspect, and execute¶
import oracq
problem = oracq.PDEProblem(
type="heat",
grid=oracq.UniformGrid1D(0, 2, 2),
initial=oracq.ArrayInput([0.2, 0.1]),
viscosity=0.1,
final_time=0.01,
)
instance = oracq.qpde_solve(
problem, method="QHAM",
config=oracq.QHAMConfig(order=1, eta=-1, taylor_degree=1),
)
instance.prepare()
circuit = instance.circuit()
assert instance.prepared.report.ok
assert oracq.loads(circuit.dumps()) == circuit.program
assert circuit.resource_estimate(basic_gates="clifford+t+qram").complete
assert "DEF " in circuit.originir_ext().text
prepare() is cached. Inspection or execution before preparation raises an
error. For a different configuration, create another instance. An invalid
initial width, missing derivative table, unbound oracle, or missing memory
snapshot fails preparation before backend execution.
With real optional backends installed, execute either path:
results = instance.run_pysparq()
results = instance.run_originir_ext()
print(results.success_probability)
print(results.physical_amplitudes()) # conditional normalized amplitudes
print(results.physical_values()) # magnitude of the generated approximation
Both return PDEResult with the public register state and field-major physical
readout. Padding addresses are excluded. A zero physical solution has zero
success probability, recoverable zero values, and no normalized conditional
state. run_originir_ext executes the exported artifact through UnifiedQuantum;
originir_ext() only exports text. Execution has explicit state, instruction,
or qubit budgets; preparing and estimating a circuit does not guarantee it fits
a simulator’s budget.
The default QHAM configuration uses a finite Taylor polynomial of the lifted
linear generator. physical_values() recovers that polynomial’s known LCU
normalization; it does not assert convergence to the continuous PDE. Spatial
discretization error, HAM truncation/convergence, angle quantization, and linear
solver error must be assessed independently.
Replace the initial input independently¶
Input |
Access supplied |
Physical norm |
|---|---|---|
|
Constant amplitudes over physical nodes and fields |
Computed |
|
Gate preparation of real or complex samples |
Computed |
|
Quantized rotation-tree preparation of nonnegative real samples |
Computed before angle quantization |
|
Existing rotation-tree angle words, with a base offset |
Explicit |
|
An existing reversible amplitude-preparation oracle |
Explicit |
The same initial input can be combined with a uniform grid or a QRAM grid.
Arrays describe physical nodes only, with one contiguous array per field.
For a coupled PDE, use ArrayInput({"u": u_samples, "v": v_samples});
register padding is inserted automatically. Custom signed or complex QRAM
loaders can be wrapped in OracleInput along with their memory banks.
Raw value access |i,0> -> |i,data[i]> does not itself prepare the amplitude
state sum_i data[i]|i>. register_qram therefore returns a host-side bank,
not an amplitude oracle. Its database() method supplies XOR value access.
An input’s adapter explicitly chooses the preparation circuit and norm.
This example prepares uniform physical amplitudes from an externally stored root angle, using a four-bit address bank for a one-bit target:
import math
bank = oracq.register_qram({3: 16}, address_length=4, word_length=6,
name="initial_angles")
initial = oracq.QRAMInput(
bank, oracq.QRAMInputConfig(state_width=1, norm=math.sqrt(0.08), offset=3),
)
prepared = initial.prepare_initial(oracq.InitialLayout(problem.grid, ("u",)))
state = oracq.simulate(prepared.preparation.operation.program(),
{bank.name: bank.snapshot()})
assert abs(state.amplitudes[(0, 0)] - 1 / math.sqrt(2)) < 1e-12
assert abs(state.amplitudes[(1, 0)] - 1 / math.sqrt(2)) < 1e-12
Rotation-tree addresses are offset + 2**depth - 1 + prefix; words encode Ry
angles in units of 2*pi/2**word_length. The tree must represent the intended
physical state, including zero amplitudes at padded addresses. The declared
norm is a physical input promise, separate from normalized amplitudes.
Choose the grid representation¶
UniformGrid1D(0, 10, 10) has ten physical samples and a four-bit address
register. Periodic coordinates cover [0, 10) with spacing 1; zero Dirichlet
coordinates are interior nodes with spacing (stop-start)/(points+1).
Power-of-two periodic grids use shift circuits. Other sizes and zero Dirichlet
boundaries currently use a spatial Pauli expansion of at most five qubits.
This bounded implementation supports ten samples but is not an efficient
large-grid implementation. It expands individual spatial derivatives rather
than a complete nonlinear port or lifted matrix. An application-defined
PDEGrid can provide larger-grid encodings directly.
For an unstructured mesh, store the discrete derivative operators after choosing the geometric discretization and boundary treatment. Coordinates or connectivity alone do not determine these operators. The provided layout uses real matrices in an angle bank and supports nonsymmetric operators:
d2 = (("x", 2),)
layout = oracq.UnstructuredGridConfig(
size=2, derivative_offsets={d2: 0}, value_scale=3,
)
data = layout.encode_matrices({d2: [[-2, 2], [2, -2]]}, word_length=8)
mesh_bank = oracq.register_qram(data, address_length=2, word_length=8, name="mesh")
mesh = oracq.UnstructuredGrid(mesh_bank, layout)
mesh_problem = oracq.PDEProblem(type="heat", grid=mesh,
initial=oracq.UniformInput(0.2), final_time=0.01)
mesh_instance = oracq.qpde_solve(mesh_problem).prepare()
assert mesh_instance.circuit().memory
assert mesh_instance.circuit().resource_estimate().qram_total > 0
A derivative table uses base + row*2**spatial_width + column. Each word
represents value_scale*cos(pi*word/2**word_length); in particular, a zero
matrix element uses a half-turn word, whereas a zero word represents positive
value_scale. encode_matrices inserts padding and saturates the negative
endpoint instead of wrapping its sign. Its per-entry error bound is
value_scale*pi/2**word_length. The coherent encoding uses two queries and
normalization 2**spatial_width*value_scale; QRAM storage does not imply a
sparse-access speedup. Layouts using neighbor lists or other matrix-access
models should implement PDEGrid with their own verified block encoding.
Memory snapshots are immutable host data outside RIR. During preparation,
resource arguments are traced through the module graph to obtain all entry
bindings, including multiple aliases of a shared bank. This traversal does not
expand Repeat. Conflicting bank names or incompatible widths fail explicitly.
Algorithms own their requirements¶
QHAM requires reversible, controlled block encodings for every multilinear
port and an initial preparation with matching width, adjoint/control support,
zero-input semantics, and clean work. The contract report is available as
instance.prepared.report; the lifted model is instance.prepared.model.
To use an existing PDE expression, pass a PolynomialPDE as PDEProblem.type.
The string presets are currently burgers and heat. To choose the linear
evolution separately, supply a three-argument QODE callable as
QHAMConfig(linear_solver=...). Its Hermiticity or dissipation requirements
still apply; the wrapper does not silently shift a generator. Such a callable
does not automatically supply magnitude recovery to this instance, so
physical_values() raises while conditional amplitude readout remains usable.
Other PDE algorithms implement PDEMethod.prepare(problem) -> PreparedPDE.
They own their grid restrictions, oracle adaptations, input contract report,
and mathematical promises. Pass the method object to qpde_solve; it shares
the cached lifecycle, RIR export, resource estimation, backend execution, and
physical readout. QHAM is currently the only built-in named PDE method.
clifford+t+qram estimates include a seven-T Toffoli decomposition;
toffoli+clifford+t+qram retains Toffoli as a separate atom. Arbitrary rotations
remain pending synthesis and t_total(epsilon) estimates their T cost. QRAM
queries are reported separately from physical QRAM hardware costs.
Run the complete example, with native execution optional:
python examples/pde_instances.py
python examples/pde_instances.py --grid qram --initial qram --backend pysparq
python examples/pde_instances.py --backend originir_ext
See also QHAM expression assembly, QHAM implementation, PDE input API, and solve instance API.