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. General resolve fits 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.
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 requiresinputs[0].code.stabilizers[1]. Callers must translate between them.For a loaded
protocolwith ameasure_zgadget, current code looks like:Referenceexposes the parsed parts, but cannot be passed directly to thelookup. This is an API convenience gap, not a need for new protocol semantics.
Describe the solution you'd like
Use one
Referencetype for addresses throughout a qodec. Letresolveon aprotocol, node, or gadget accept either
Referenceorstrthrough the existingReferenceLikealias. Strings use the same grammar; aReferencereuses itsparsed form. For a single target, return the existing
Nodetype.Proposed usage, not supported by the current API:
The root-relative form should also work:
And a gadget obtained directly should offer the same operation:
This broadens Python/Rust addressing, not which references are legal in gadget
equations.
Reference('metadata["description"]')could be resolved as a modeladdress 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
the same work repeatedly.
resolve_operator: useful only for encoding operators, not other modelvalues. General
resolvefits the existing navigation API better.Reuse
Reference,resolve, andNode. The new method isGadget.resolve;existing protocol and node methods gain
Referenceinput support. No newresult type is proposed. Shared behavior belongs in Rust, with thin bindings.
Additional context
A few choices still need settling:
in[0].stabilizers[1]as an alias for the model path, or choose aconsistent spelling. Do not silently rewrite authored references on save.
circuit.readouts[i]needs interpretation,whereas ordinary model lookup must work with unsupported circuit source.
existing protocol-node identity, mutation behavior, and optional source locations.
should raise rather than produce partial results.