Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f40f340
clean: Move math into atomic compiler
vishnu-m77 Jun 18, 2026
8232c4c
feat: Fix atomic canonicalization passes
vishnu-m77 Jun 19, 2026
f5c87f7
fix: minor bugs in atomic compiler passes
vishnu-m77 Jun 29, 2026
60e6f90
Add resolution of relative time in atomic compiler pass
vishnu-m77 Jun 29, 2026
471057c
Merge remote-tracking branch 'origin/v1.0' into compiler_passes
vishnu-m77 Jun 29, 2026
a5ef201
feat: Add compiler passes for atomic interface
vishnu-m77 Jul 7, 2026
49b4df1
clean: Update docs
vishnu-m77 Jul 7, 2026
e8f970a
fix: Modify Pulse as an AtomicExpr similar to Beam in Atomic interfac…
vishnu-m77 Jul 7, 2026
b840b30
fix: Atomic tests
vishnu-m77 Jul 7, 2026
868e338
clean: Atomic compiler CFG passes
vishnu-m77 Jul 7, 2026
c389420
clean: Add documentation for atomic compiler passes
vishnu-m77 Jul 7, 2026
660b3a8
clean: Update docs for analog and atomic compiler passes
vishnu-m77 Jul 7, 2026
2cf6e55
fix: Do not resolve access of scalars in atomic compiler
vishnu-m77 Jul 7, 2026
aeb0278
Merge remote-tracking branch 'origin/v1.0' into compiler_passes
vishnu-m77 Jul 8, 2026
6fdca24
clean: Simplify atomic compiler passes. Update docs
vishnu-m77 Jul 8, 2026
0fff144
feat: compiler passes modify the control flow graph
vishnu-m77 Jul 9, 2026
57e19ce
feat: Add visualization for CFG
vishnu-m77 Jul 9, 2026
05af9d4
clean: Use pydantic for control flow graph and blocks
vishnu-m77 Jul 10, 2026
22e28ca
feat: Compiler passes return updated control flow graph and circuit
vishnu-m77 Jul 14, 2026
9bc47a6
clean: Update docs
vishnu-m77 Jul 14, 2026
27e5c49
clean: Update docs and add tests for compiler passes
vishnu-m77 Jul 14, 2026
b9bb328
fix: output of analog compiler, update docs
vishnu-m77 Jul 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ jobs:
uv sync --extra tests
- name: Run tests
run: |
uv run pytest tests/test_frontend tests/test_analog tests/test_analysis -v
uv run pytest tests/ -v
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,5 @@ tests/test.bat


.pre-commit-config.yaml
*.antlr/
*.antlr/
examples/*
2 changes: 1 addition & 1 deletion docs/analysis/analog_analysis.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ symbol_table = AnalogSymbolTableBuilder(cfg, type_checker.dataflow_result).symbo

///

The type checker dataflow result is available at `type_checker.dataflow_result`.
The type checker dataflow result is available at `type_checker.dataflow_result`. This result is used to build the Symbol Table. Note that the Symbol Table will run the Type Checker to get the dataflow result if the result is not provided.
12 changes: 10 additions & 2 deletions docs/analysis/atomic_analysis.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ The atomic Control Flow Graph (CFG) is implemented by the `AtomicCFGBuilder` cla

The atomic type checker is implemented by the `AtomicTypeChecker` class in [`type_checker.py`](../../src/oqd_core/analysis/atomic/type_checker.py). The `AtomicTypeLattice` class defines a concrete lattice for atomic types with `leq`, `join`, and `meet` methods. Type inference rules are implemented by the `AtomicSemantics` class in [`semantics.py`](../../src/oqd_core/analysis/atomic/semantics.py). The type checker runs forward dataflow analysis over the CFG.

Protocol blocks (`parallel` / `serial`) accept only pulse statements: `Pulse` nodes, pulse declarations, pulse variable references, and nested protocols. In `serial` blocks, pulse declarations update the local environment for later statements in the same block.

## Symbol Table

The atomic symbol table is implemented in [`symbol_table.py`](../../src/oqd_core/analysis/atomic/symbol_table.py). The `AtomicSymbolTableBuilder` class runs a second forward dataflow pass over the CFG, using the type checker output to track register and target dimensions. The result is an `AtomicSymbolTable` with register environments per block and a statement index.

`SymbolBinding.target_dim` is an `int` giving the total ion-target dimension (register size, extracted ion, or sum of list elements). Unlike the analog symbol table, atomic targets do not use a `(qreg, qmode)` tuple.

## Usage of the type checker

Expand All @@ -19,7 +26,7 @@ The atomic type checker is implemented by the `AtomicTypeChecker` class in [`typ

```py
from oqd_core.frontend.atomic import parse_atomic
from oqd_core.analysis.atomic import AtomicCFGBuilder, AtomicTypeChecker
from oqd_core.analysis.atomic import AtomicCFGBuilder, AtomicTypeChecker, AtomicSymbolTableBuilder

source = """
ions = ionreg(1)
Expand All @@ -30,8 +37,9 @@ pulse(mw, 1e-5, ions[0], true)
circuit = parse_atomic(source)
cfg = AtomicCFGBuilder().run(circuit)
type_checker = AtomicTypeChecker(cfg)
symbol_table = AtomicSymbolTableBuilder(cfg, type_checker.dataflow_result).symbol_table
```

///

The output of the type checker is stored in `type_checker.dataflow_result`.
The type checker dataflow result is available at `type_checker.dataflow_result`. This result is used to build the Symbol Table. Note that the Symbol Table will run the Type Checker to get the dataflow result if the result is not provided.
4 changes: 2 additions & 2 deletions docs/grammar/atomic_grammar.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ The grammar supports the core atomic statements through `beam`, `pulse`, `parall
- `target`: target expression (`aexpr`)
- `measured`: boolean expression (`aexpr`), optional, defaults to `false`
- `parallel { ... }`
- `...`: block (`block`) containing pulse statements to run in parallel
- `...`: block (`block`) containing pulse statements, pulse declarations, pulse references, and nested protocols that will be run in parallel.
- `serial { ... }`
- `...`: block (`block`) containing pulse statements to run in serial
- `...`: block (`block`) containing pulse statements, pulse declarations, pulse references, and nested protocols that will be run in a serial sequence.

## Generate Parser Files for Frontend

Expand Down
8 changes: 4 additions & 4 deletions docs/interfaces/analog_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ The basis of operators for the bosonic degree of freedom are the ladder operator

The basis operators can be combined with the operations:

- Addition <div style="float:right"> [![](https://img.shields.io/badge/Implementation-7C4DFF)][oqd_core.interface.analog.expr.OperatorAdd] </div>
- Addition <div style="float:right"> [![](https://img.shields.io/badge/Implementation-7C4DFF)][oqd_core.interface.analog.expr.OperatorExprAdd] </div>

- Subtraction <div style="float:right"> [![](https://img.shields.io/badge/Implementation-7C4DFF)][oqd_core.interface.analog.expr.OperatorSub] </div>
- Subtraction <div style="float:right"> [![](https://img.shields.io/badge/Implementation-7C4DFF)][oqd_core.interface.analog.expr.OperatorExprSub] </div>

- Multiplication <div style="float:right"> [![](https://img.shields.io/badge/Implementation-7C4DFF)][oqd_core.interface.analog.expr.OperatorMul] </div>
- Multiplication <div style="float:right"> [![](https://img.shields.io/badge/Implementation-7C4DFF)][oqd_core.interface.analog.expr.OperatorExprMul] </div>

- Tensor Product <div style="float:right"> [![](https://img.shields.io/badge/Implementation-7C4DFF)][oqd_core.interface.analog.expr.OperatorKron] </div>
- Tensor Product <div style="float:right"> [![](https://img.shields.io/badge/Implementation-7C4DFF)][oqd_core.interface.analog.expr.OperatorExprKron] </div>

## Math Expressions

Expand Down
5 changes: 3 additions & 2 deletions docs/interfaces/atomic_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ The [`AtomicCircuit`][oqd_core.interface.atomic.circuit.AtomicCircuit] is the to
type: example

```py
from oqd_core.interface.atomic import AtomicCircuit, Beam
from oqd_core.interface.atomic import AtomicCircuit, Beam, Access

circuit = AtomicCircuit()

Expand All @@ -96,7 +96,8 @@ mw = Beam(
wavevector=[0.0, 0.0, 1.0],
)

circuit.pulse(duration=10e-6, target=0, beam=mw, measured=False)
ions = Access(name="ions")
circuit.pulse(beam=mw, duration=10e-6, target=ions, measured=False)
```

///
6 changes: 3 additions & 3 deletions docs/reference/analog_compiler.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Analog Compiler

The analog compiler is implemented in `src/oqd_core/compiler/analog`. The entry point is [`compile_analog_circuit`][oqd_core.compiler.analog.passes.compile.compile_analog_circuit], which takes an [`AnalogCircuit`][oqd_core.interface.analog.circuit.AnalogCircuit], a `ControlFlowGraph`, and an `AnalogSymbolTable`.
The analog compiler is implemented in `src/oqd_core/compiler/analog`. The entry point is [`compile_analog_circuit`][oqd_core.compiler.analog.passes.compile.compile_analog_circuit], which takes an [`AnalogCircuit`][oqd_core.interface.analog.circuit.AnalogCircuit], a [`ControlFlowGraph`][oqd_core.analysis.utils.control_flow.ControlFlowGraph], and an `AnalogSymbolTable`[oqd_core.analysis.analog.symbol_table.AnalogSymbolTable].

The compile pipeline:
- Canonicalize operators over the CFG via [`canonicalize_operators_cfg`][oqd_core.compiler.analog.cfg_passes.walk.canonicalize_operators_cfg]
- Canonicalize math expressions over the CFG via [`canonicalize_math_cfg`][oqd_core.compiler.analog.cfg_passes.walk.canonicalize_math_cfg]
- Verify register access and Hamiltonian target dimensions
- Infer circuit Hilbert space dimensions from canonicalized `Evolve` statements
- Infer Hilbert space dimensions from canonicalized `Evolve` statements

## Compile Passes

Expand Down Expand Up @@ -122,5 +122,5 @@ circuit = parse_analog(source)
cfg = AnalogCFGBuilder().run(circuit)
type_checker = AnalogTypeChecker(cfg)
symbol_table = AnalogSymbolTableBuilder(cfg, type_checker.dataflow_result).symbol_table
circuit, (n_qreg, n_qmode) = compile_analog_circuit(circuit, cfg, symbol_table)
circuit, cfg, n_qreg, n_qmode = compile_analog_circuit(circuit, cfg, symbol_table)
```
3 changes: 3 additions & 0 deletions docs/reference/analog_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
options:
heading_level: 3
members: [
"OperatorExpr",
"OperatorBinaryOp",
"OperatorTerminal",
"AnalogExpr",
"AnalogExprSubtypes",
"CastAnalogExpr",
Expand Down
1 change: 0 additions & 1 deletion docs/reference/atomic_canonicalization.md

This file was deleted.

117 changes: 117 additions & 0 deletions docs/reference/atomic_compiler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Atomic Compiler

The atomic compiler is implemented in `src/oqd_core/compiler/atomic`. The entry point is [`compile_atomic_circuit`][oqd_core.compiler.atomic.passes.compile.compile_atomic_circuit], which takes an [`AtomicCircuit`][oqd_core.interface.atomic.circuit.AtomicCircuit], a [`ControlFlowGraph`][oqd_core.analysis.utils.control_flow.ControlFlowGraph] and an [`AtomicSymbolTable`][oqd_core.analysis.atomic.symbol_table.AtomicSymbolTable].

The compile pipeline:
- Canonicalize declaration values over the CFG via [`canonicalize_declarations_cfg`][oqd_core.compiler.atomic.cfg_passes.walk.canonicalize_declarations_cfg]
- Canonicalize nested protocols and relative time via [`canonicalize_protocol_cfg`][oqd_core.compiler.atomic.cfg_passes.protocol.canonicalize_protocol_cfg]
- Rebuild the CFG from the updated circuit via [`AtomicCFGBuilder`][oqd_core.analysis.atomic.cfg.AtomicCFGBuilder]
- Re-run the type checker and symbol table on the rebuilt CFG
- Verify pulse target dimensions via [`verify_pulse_target_dim`][oqd_core.compiler.atomic.verify.passes.verify_pulse_target_dim]

## Compile Passes

<!-- prettier-ignore -->
::: oqd_core.compiler.atomic.passes.compile
options:
heading_level: 3
members: [
"compile_atomic_circuit",
]

## CFG Passes

<!-- prettier-ignore -->
::: oqd_core.compiler.atomic.cfg_passes.walk
options:
heading_level: 3
members: [
"iter_stmt_blocks",
"canonicalize_declarations_cfg",
"canonicalize_beam",
"canonicalize_scalar_expr",
]
<!-- prettier-ignore -->
::: oqd_core.compiler.atomic.cfg_passes.protocol
options:
heading_level: 3
members: [
"apply_protocol_passes",
"canonicalize_protocol_tree",
"canonicalize_protocol_circuit",
]
<!-- prettier-ignore -->
::: oqd_core.compiler.atomic.cfg_passes.resolve
options:
heading_level: 3
members: [
"resolve_scalar_expr",
"resolve_beam_expr",
"resolve_beam_ref",
"resolve_pulse_expr",
"resolve_pulse_ref",
"resolve_protocol_pulses",
]

## Verification Passes

<!-- prettier-ignore -->
::: oqd_core.compiler.atomic.verify.passes
options:
heading_level: 3
members: [
"verify_pulse_target_dim",
]

## Atomic Math Passes

<!-- prettier-ignore -->
::: oqd_core.compiler.atomic.math.passes
options:
heading_level: 3
members: [
"canonicalize_math_expr",
"evaluate_math_expr",
"simplify_math_expr",
"print_math_expr",
]

## Atomic Math Rewrite Rules

<!-- prettier-ignore -->
::: oqd_core.compiler.atomic.math.rules
options:
heading_level: 3
members: [
"DistributeMathExpr",
"PartitionMathExpr",
"ProperOrderMathExpr",
"PruneMathExpr",
"EvaluateMathExpr",
"SimplifyMathExpr",
"PrintMathExpr",
]

## Usage


<!-- prettier-ignore -->
/// admonition | Example
type: example
```py
from oqd_core.frontend.atomic import parse_atomic
from oqd_core.analysis.atomic import AtomicCFGBuilder, AtomicTypeChecker, AtomicSymbolTableBuilder
from oqd_core.compiler.atomic.passes.compile import compile_atomic_circuit

source = """
ions = ionreg(1)
mw = beam(2.0, 1.0, 0.0, [1.0, 0.0, 0.0], [0.0, 0.0, 1.0])
pulse(mw, 1e-5, ions[0], true)
"""

circuit = parse_atomic(source)
cfg = AtomicCFGBuilder().run(circuit)
type_checker = AtomicTypeChecker(cfg)
symbol_table = AtomicSymbolTableBuilder(cfg, type_checker.dataflow_result).symbol_table
circuit, cfg = compile_atomic_circuit(circuit, cfg, symbol_table, type_checker.dataflow_result)
```
4 changes: 4 additions & 0 deletions docs/reference/atomic_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
"AtomicExpr",
"AtomicExprSubtypes",
"CastAtomicExpr",
"IonExpr",
"CollectionExpr",
"IndexingExpr",
"RegisterExpr",
"Terminal",
"Access",
"IonRegister",
Expand Down
Empty file removed docs/reference/math_interface.md
Empty file.
4 changes: 2 additions & 2 deletions examples/analog/test.analog
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ if (x > 0){
initialize(r)
}
if (x == 1) {
evolve(H_single, 1.0, r)
evolve(H_single, 1.0, q0)
}
else { evolve(H_pair, 0.5, r) }
n = 3
Expand Down Expand Up @@ -67,7 +67,7 @@ if (a > b) {
initialize(r)

// evolve(hamiltonian, duration, target)
evolve(H_single, 2.0, r)
evolve(H_single, 2.0, q1)
evolve(H_pair, 1.0, targets)
evolve(%X %* 0.5, pi, q0)

Expand Down
Loading
Loading