Skip to main content
The demos/ directory contains complete, runnable examples that show how b01t programs are structured in practice. Each demo pairs a @coherent or @adaptive circuit with its classical driver, covering algorithms from introductory textbook problems through to multi-layer coherent pipelines. Reading these alongside the source code in b01t/zoo/ is the fastest way to understand how the DSL components fit together.
Determines whether a 1-bit Boolean function f: {0,1} → {0,1} is constant or balanced using a single quantum query. Classically you need two evaluations; Deutsch’s algorithm needs one.What it demonstrates: @coherent oracle construction, @adaptive algorithm, phase kickback with |−⟩ target, measure on a single qubit.The oracle make_deutsch_oracle(f0, f1) implements U_f|x,y⟩ = |x, y ⊕ f(x)⟩ using only permutation gates (X, CX):
from b01t import QReg, coherent, cx, x

def make_deutsch_oracle(f0: int, f1: int):
    @coherent
    def oracle(inp: QReg, tgt: QReg):
        if f0 == 1:
            x(tgt[0])
        if f0 != f1:
            cx(inp[0], tgt[0])
    return oracle
The algorithm prepares |+⟩ on the input and |−⟩ on the target, queries once, then measures. The result is 0 for constant functions and 1 for balanced functions:
from b01t import QReg, adaptive, h, x, cx, measure

def make_deutsch_algorithm(f0: int, f1: int):
    @adaptive
    def algorithm(inp: QReg, tgt: QReg):
        h(inp[0])
        x(tgt[0]); h(tgt[0])          # prepare |->
        if f0 == 1:
            x(tgt[0])
        if f0 != f1:
            cx(inp[0], tgt[0])
        h(inp[0])
        return measure(inp[0])         # 0=constant, 1=balanced
    return algorithm
Run it:
uv run pytest demos/deutsch/
Recovers a hidden binary string s from the function f(x) = s·x (mod 2) using a single quantum query, where a classical algorithm needs n queries.What it demonstrates: @coherent oracle with a secret parameter, @adaptive algorithm, measure_all, for_each-style Hadamard layers.The oracle implements U_f|x,y⟩ = |x, y ⊕ (s·x)⟩ by applying CX(x_i, target) for each i where s_i = 1:
from typing import Sequence
from b01t import QReg, coherent, cx

def make_bv_oracle(secret: Sequence[int]):
    s = tuple(secret)
    @coherent
    def oracle(inp: QReg, tgt: QReg):
        for i in range(len(s)):
            if s[i] == 1:
                cx(inp[i], tgt[0])
    return oracle
The algorithm applies Hadamard on all inputs, queries the oracle, applies Hadamard again, and measures — the output is the hidden string s directly:
from b01t import QReg, adaptive, h, x, cx, measure_all

def make_bv_algorithm(secret: Sequence[int]):
    s = tuple(secret)
    @adaptive
    def algorithm(inp: QReg, tgt: QReg):
        for i in range(len(s)):
            h(inp[i])
        x(tgt[0]); h(tgt[0])          # prepare |->
        for i in range(len(s)):
            if s[i] == 1:
                cx(inp[i], tgt[0])
        for i in range(len(s)):
            h(inp[i])
        return measure_all(inp)        # outcome = s
    return algorithm
Run it:
uv run pytest demos/bernstein_vazirani/
Finds a hidden XOR-mask s satisfying f(x) = f(x ⊕ s) for all x, using O(n) quantum rounds followed by classical Gaussian elimination. Classically the problem requires exponentially many queries.What it demonstrates: multi-register @coherent oracle, repeated @adaptive rounds, classical post-processing to recover a hidden period.Each quantum round produces a random string y satisfying y·s = 0 (mod 2). After n − 1 linearly independent samples, s is recovered classically:
from typing import Sequence
from b01t import QReg, adaptive, h, cx, measure_all

def make_simon_algorithm(secret: Sequence[int]):
    s = tuple(secret)
    n = len(s)
    pivot = next((i for i in range(n) if s[i] == 1), None)

    @adaptive
    def algorithm(inp: QReg, out: QReg):
        for i in range(n):
            h(inp[i])
        # Oracle: copy input, then conditionally XOR s into output
        for i in range(n):
            cx(inp[i], out[i])
        if pivot is not None:
            for i in range(n):
                if s[i] == 1 and i != pivot:
                    cx(inp[pivot], out[i])
            cx(inp[pivot], out[pivot])
        for i in range(n):
            h(inp[i])
        return measure_all(inp)   # y such that y·s = 0 mod 2

    return algorithm
Run it:
uv run pytest demos/simon/
Factors an integer N by finding the period of a^x mod N using Quantum Phase Estimation with a modular exponentiation oracle.What it demonstrates: @adaptive top-level circuit, @parametric modular exponentiation inlined for broad-IR, inverse_qft from zoo.qft, and classical continued-fraction post-processing.make_shor_circuit(a_val, N, num_counting_bits) returns an @adaptive function that:
  1. Initialises the work register to |1⟩.
  2. Applies Hadamard to the counting register.
  3. Runs the modular exponentiation oracle.
  4. Applies inverse_qft on the counting register.
  5. Measures the counting register.
from b01t import QReg, adaptive, x, h, measure_all
from b01t.zoo.qft import inverse_qft

def make_shor_circuit(a_val: int, N: int, num_counting_bits: int):
    oracle = _make_parametric_modular_exp(a_val, N, num_counting_bits)

    @adaptive
    def shor_circuit(counting: QReg, y_reg: QReg, acc: QReg, scratch: QReg):
        x(y_reg[0])                       # initialise work to |1>
        for i in range(len(counting)):
            h(counting[i])
        oracle(counting, y_reg, acc, scratch)
        inverse_qft(counting)
        return measure_all(counting)

    return shor_circuit
The measurement is then decoded classically using continued fractions. The demo includes helper utilities for this post-processing step:
# Classical post-processing: decode QPE measurement to period, then factor
# measurement is the integer read from the counting register
# r = period of a^x mod N recovered via continued fractions
# factors = gcd(a^(r/2) ± 1, N)
measurement = 42        # example QPE output
# See demos/shor/ for the classical continued-fraction utilities
Run it:
uv run pytest demos/shor/
Implements coherent rollout oracles for sequential decision problems, where a quantum circuit simulates multiple rounds of a stochastic environment in superposition.What it demonstrates: multi-register @coherent state-preparation, rank_select_binary from zoo.rank_select, complex ancilla discipline across many sub-circuits.Two environments are provided:
  • sway/ — a two-player stochastic board game where black and white alternate placing stones on a grid, with stochastic rule transitions.
  • epidemic/ — an SIR epidemic intervention model where a policy selects interventions over time.
The rollout oracle structure for the Sway game prepares a superposition over all outcomes by:
  1. Placing selector registers in uniform superposition (H on each bit).
  2. Using rank_select_binary to coherently map a selector index to the corresponding legal move.
  3. Applying the transition and terminal evaluation circuits.
from b01t import QReg, coherent, h
from b01t.zoo.rank_select import rank_select_binary
from demos.rollout.sway.sway_spec import SwaySpec

spec = SwaySpec(rows=2, cols=2, horizon=1)
# register_specs() returns (name, size) pairs for every qubit register
reg_specs = spec.register_specs()
Run it:
uv run pytest tests/test_rollout_sway.py
uv run pytest tests/test_rollout_epidemic.py
A full coherent pipeline that identifies the highest-payoff action in a decision problem using quantum maximum finding. It composes three layers: a rollout oracle, coherent amplitude estimation, and Dürr–Høyer maximum finding.What it demonstrates: end-to-end composition of zoo.qae.make_coherent_ae, zoo.max_finding.make_comparison_oracle, and zoo.max_finding.DurrHoyerRunner. This is the most complex demo and shows how the zoo modules stack together.The pipeline is:
DurrHoyerRunner (O(√k) comparisons)
  └─ comparison oracle
       ├─ coherent AE (QPE on Grover iterate, O(1/ε) depth)
       │    └─ Grover iterate G = mark · A† · S₀ · A
       │         └─ A = arm-specific rollout oracle
       ├─ less_than comparison to threshold
       └─ uncompute
Each “arm” is a different first action for the player. The arm oracle fixes the first-round selector to a specific action index while leaving the rest of the game randomness in superposition:
from b01t.zoo.qae import make_coherent_ae
from b01t.zoo.max_finding import make_comparison_oracle, DurrHoyerRunner
from demos.best_arm.arm_oracle import make_arm_state_prep, make_arm_mark_oracle
from demos.rollout.sway.sway_spec import SwaySpec

spec = SwaySpec(rows=2, cols=2, horizon=1)
mark_oracle = make_arm_mark_oracle(spec)

# Build per-arm state-prep oracles
arm_preps = [make_arm_state_prep(spec, action_index=i)
             for i in range(spec.black_choices(1))]

# Coherent AE for each arm
ae_circuits = [make_coherent_ae(prep, mark_oracle) for prep in arm_preps]

# Comparison oracle: does arm i beat the current threshold?
ae_arm0 = ae_circuits[0]
comp = make_comparison_oracle(ae_arm0, threshold_value=1, precision=2)
Run it:
uv run python -m demos.best_arm.demo
uv run pytest tests/test_best_arm_correctness.py

Running all demos

You can run every demo’s test suite from the repository root:
uv run pytest demos/
Or run the full best-arm pipeline demo to see the circuit qubit counts and gate counts printed to the console:
uv run python -m demos.best_arm.demo