# Your first register program
**English** · 简体中文
This tutorial generates a Bell state. You will use one register, two gate operations, and the reference executor. Afterwards, the same program is saved as RIR and exported as OriginIR-ext.
## Defining the operations
{obj}`Bits(2) ` defines a two-bit register. We first put the low bit into a superposition, then use it as the control of an XOR applied to the high bit.
```{testcode}
from oracq import Bits, Builder, simulate
# Declare a module named bell_pair whose public interface is a two-bit bits register named pair.
b = Builder("bell_pair", {"pair": Bits(2)})
# Broadcast an H gate over bit 0 (the least significant bit) of pair: |0> -> (|0>+|1>)/sqrt(2).
b.h(b["pair"][0])
# XOR (bitwise CNOT) with bit 0 as source and bit 1 as target: yields (|00>+|11>)/sqrt(2).
b.xor(b["pair"][0], b["pair"][1])
# Finish building and obtain an immutable Operation (module plus instruction body).
operation = b.finish()
# Take out its RIR Program: entry points to bell_pair, and modules holds exactly this one module.
program = operation.program()
# Simulate with the dependency-free reference executor; it returns sparse amplitudes.
state = simulate(program)
# Print the execution result; the output block below reproduces this print verbatim.
print(state.amplitudes)
# Amplitude keys are integer tuples formed by concatenating the entry registers in declaration order; (0,) is 00 and (3,) is 11.
assert set(state.amplitudes) == {(0,), (3,)}
# Both basis states should have magnitude 1/sqrt(2).
assert abs(state.amplitudes[(0,)] - 2**-0.5) < 1e-12
assert abs(state.amplitudes[(3,)] - 2**-0.5) < 1e-12
```
```{testoutput}
{(0,): (0.7071067811865475+0j), (3,): (0.7071067811865475+0j)}
```
{obj}`Builder ` collects the calls above one by one, and `finish()` returns the immutable {obj}`Operation `. The printed dictionary is the execution result: keys are tuples of the entry registers' integer values, with `0` meaning `00` and `3` meaning `11`; `0.7071067811865475` is the double-precision rendering of `1/√2`.
## Saving and exporting
```{testcode}
from oracq import dumps, loads, export_originir
# Serialize to canonical YAML: keys sorted, two-space indentation, module and instruction structure preserved as is.
text = dumps(program)
# Print the whole text; the output block abbreviates the repeated middle section with ...
print(text)
# Deserialize back into a Program object; decoding is strict and re-runs semantic validation.
restored = loads(text)
# The round trip must be equal: register names, views, and module structure are all preserved.
assert restored == program
# Export as modular OriginIR-ext text.
artifact = export_originir(restored)
# The text should contain a DEF module definition: export neither inlines calls nor flattens them into a bare gate list.
assert "DEF" in artifact.text
# Print the OriginIR-ext text; it already ends with a trailing newline, hence end="".
print(artifact.text, end="")
```
```{testoutput}
entry: bell_pair
modules:
- attributes: []
body:
- angle: null
op: h
operands:
- parts:
- register: pair
start: 0
...
...
tag: Primitive
value: null
...
locals: []
name: bell_pair
...
tag: Program
version: '0.1'
QINIT 2
CREG 0
DEF m_bell_pair_d029b74cecc4332d414ece8a(v_pair[2])
H v_pair[0]
CNOT v_pair[0], v_pair[1]
ENDDEF
m_bell_pair_d029b74cecc4332d414ece8a(q[0], q[1])
```
{obj}`dumps ` produces the text in the first half, and {obj}`loads ` re-runs the semantic validation of {obj}`validate ` while decoding; the {obj}`OriginIRArtifact ` returned by {obj}`export_originir ` carries the text in the second half. The first half is the skeleton of canonical YAML: the {obj}`Program ` holds the module table, a module's `body` holds the instructions, and an instruction's operands keep the register names and views in fields such as `register` and `start`; everything outside the `...` matches the actual print verbatim. The second half is OriginIR-ext text: `QINIT 2` declares a two-qubit register and `CREG 0` says there is no classical register; `DEF m_bell_pair_` defines the module — the suffix is a fingerprint determined by the module's content, and a given module is exported with only one definition — and the last line binds the entry qubits `q[0], q[1]` to the module's formal parameters. The export does not first copy all calls into a flat gate list.
{obj}`simulate ` is well suited to small-scale checks like this one. When a real backend is needed, keep using the same {obj}`Program ` and call {obj}`run_pysparq ` or {obj}`run_originir ` instead.
## Related pages
- Manual: [Operations, registers, and the generation process](../manual/concepts.md), [Source code structure](../manual/architecture.md), [Export and execution backends](../manual/backends.md)
- Specification: [RIR specification](../reference/rir.md) (JSON structure and the OriginIR-ext grammar)
- API reference: [RIR objects](../api/infrastructure/ir.rst), [module builder](../api/infrastructure/builder.rst), [register reference executor](../api/infrastructure/execution.rst), [RIR serialization](../api/infrastructure/serialization.rst)
- Continue with: [Replacing an algorithm's oracle](oracle-binding.md), [Running and modifying the algorithm gallery](gallery.md)