qodec: Unify Reference and model-path resolution
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 64
- Forks
- 16
- Avg merge
- 1d 5h
- Merged PRs (30d)
- 5
Description
Is your feature request related to a problem? Please describe.
qodec has two ways to address the same declaration. A gadget equation uses
in[0].stabilizers[1], while model navigation requires
inputs[0].code.stabilizers[1]. Callers must translate between them.
For a loaded protocol with a measure_z gadget, current code looks like:
from qodec.gadgets import Encoding, Reference
reference = Reference("in[0].stabilizers[1]")
node = protocol.resolve('layers[0].gadgets["measure_z"]')
encoding = node.resolve("inputs[0]").value(Encoding)
operator = encoding.code.stabilizers[1]
Reference exposes the parsed parts, but cannot be passed directly to the
lookup. This is an API convenience gap, not a need for new protocol semantics.
Describe the solution you'd like
Use one Reference type for addresses throughout a qodec. Let resolve on a
protocol, node, or gadget accept either Reference or str through the existing
ReferenceLike alias. Strings use the same grammar; a Reference reuses its
parsed form. For a single target, return the existing Node type.
Proposed usage, not supported by the current API:
gadget_node = protocol.resolve('layers[0].gadgets["measure_z"]')
operator_node = gadget_node.resolve("in[0].stabilizers[1]")
operator = operator_node.value(str)
assert gadget_node.resolve(reference) == operator_node
The root-relative form should also work:
operator = protocol.resolve(
'layers[0].gadgets["measure_z"].in[0].stabilizers[1]'
).value(str)
And a gadget obtained directly should offer the same operation:
from qodec import Gadget
gadget = gadget_node.value(Gadget)
operator = gadget.resolve(reference).value(str)
This broadens Python/Rust addressing, not which references are legal in gadget
equations. Reference('metadata["description"]') could be resolved as a model
address but must remain invalid as a parity term. Keep serialized references
and parity meanings unchanged.
Lookup returns a declaration, not a sampled bit or an evaluated equation. The
operator above still uses code-local indices; its encoding support supplies
the circuit block labels. Resolution does not compute global placement.
Describe alternatives you've considered
- Document the manual translation: possible today, but leaves callers doing
the same work repeatedly. - Add
resolve_operator: useful only for encoding operators, not other model
values. Generalresolvefits the existing navigation API better. - Add a second reference type: preserves the split instead of removing it.
Reuse Reference, resolve, and Node. The new method is Gadget.resolve;
existing protocol and node methods gain Reference input support. No new
result type is proposed. Shared behavior belongs in Rust, with thin bindings.
Additional context
A few choices still need settling:
- Treat
in[0].stabilizers[1]as an alias for the model path, or choose a
consistent spelling. Do not silently rewrite authored references on save. - Define results for slices and unions, preserving order and duplicates.
- Keep circuit parsing explicit:
circuit.readouts[i]needs interpretation,
whereas ordinary model lookup must work with unsupported circuit source. - Define node ownership and paths for standalone gadgets, while retaining
existing protocol-node identity, mutation behavior, and optional source locations. - Preserve string-based lookup and reference equality/hashing. Missing targets
should raise rather than produce partial results.
Contributor guide
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 with the existing Reference, ReferenceLike, resolve, Node, and Gadget entry points, then trace how Rust implementations are exposed through the Python bindings. Define and test the shared resolution behavior, including relative and root-relative addresses, slices and unions, standalone gadget ownership, and missing targets, while preserving serialized references and parity meanings.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, rust
- Domain
- backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100