Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Ways to Use XQuad

Six separate surfaces get a problem into XQuad and a result back out. Pick the wrong one and you find out several pages later. This page is the map.

SurfaceWhat it isWho it is for
xqcp DSLPython constraint-programming layer; compiles a problem to XQVM assemblyModelling a new combinatorial problem without hand-writing assembly
xquad Program/Session APIProgram / Session / RunResult: load a program once, run it repeatedly with fresh calldataDriving an existing compiled program from Python – a REPL, a notebook, a script
xqffi.vm FFIVm: a thin wrapper over the Rust interpreterPython code building its own convenience layer on top of the raw Rust VM
xquad.vm VM wrapperVM / VMBackend: runs .xqasm source text directly against either the Rust interpreter or the pure-Python reference VM, with xquad.types.XQMX at the boundaryBackend-parity checking, or working in xquad.types terms; the surface every example runner under examples/ actually uses
xquad CLIxquad asm / run / dism / verifyAssembling, running, inspecting, or verifying one .xqasm/.xqb file, no Python involved
Rust embeddingxqvm::InstructionBuilder, building a Program directly, no text assembly stepEmbedding XQVM in a Rust host: no_std target, WASM runtime, on-chain pallet

xqcp – The DSL

You write a Problem in Python: declare inputs, define the model, add objective terms and constraints, declare outputs. problem.compile() returns CompiledPrograms(encoder, verifier, decoder) – three .xqasm programs, ready to run. See Three Programs for what those three are and why there are three. Every example under examples/ is built this way; examples/maxcut/runner.py is a complete pipeline you can read start to finish.

Stop here if you have a combinatorial problem to model and no existing .xqasm source. Keep reading if you already have compiled bytecode and need to run or inspect it. Full coverage: Modelling.

xquad.program – Program and Session

Program.from_source(src) or Program.load(bytecode) loads a program once; program.session(output_slots=n) gives you a Session you call .run() on repeatedly, each time with fresh calldata via session.set_calldata(...). Each run returns a RunResult with dict-keyed outputs (an unset slot reads as None), the residual stack, and the step count. Program.from_source plus Session.run() round-trips 40 + 2 through calldata and an output slot to {0: 42}, and running the same session again returns {0: 42} again: each run() starts clean.

Stop here if you are driving an already-compiled program from Python and want calldata handling and output decoding done for you. Keep reading if you are choosing between this and the raw FFI below. Full coverage: Running Programs.

xqffi.vm – The Raw FFI

xqffi.vm.Vm is a thin wrapper over the Rust interpreter: construct a Vm, call set_calldata/set_output_slots, call .run(bytecode), read .outputs(). No Program/Session layer on top, and unlike Session, a Vm holds its stack and registers across runs: call .run() twice on the same Vm without an intervening .reset() and the second run’s results sit on top of the first’s. reset() clears the stack, registers, and loop state; calldata and outputs both survive a reset() untouched, and only a fresh set_output_slots(n) call replaces the output slots. Session sidesteps the question entirely: Session.run() builds a fresh Vm per call, so no state survives between runs. That is the real reason to prefer it for anything but a single one-off program.

Reach for Vm directly only if you are building your own convenience layer on top, or the Program/Session assumptions do not fit – most Python users want xquad.program or xquad.vm instead. Full coverage: Running Programs.

xquad.vm – Backend Dispatch

xquad.vm.VM selects between the Rust interpreter and the pure-Python reference VM via VMBackend, converting FFI objects to and from the canonical xquad.types.XQMX at the boundary, and runs .xqasm source text directly rather than pre-assembled bytecode. VMBackend.RUST is the default and reaches the Rust interpreter through xqffi.vm.Vm internally. Every example runner under examples/ imports VM and VMBackend from here, not xqffi.vm directly.

Stop here if you want backend-parity checking or your calldata and outputs are already in xquad.types terms. Keep reading if you need the raw FFI underneath instead. Full coverage: Running Programs.

xquad CLI

xquad asm, xquad run, xquad dism, xquad verify – four subcommands, entirely in the shell. Assemble a .xqasm file to bytecode, run a .xqb file (or a .xqasm file with --text) against calldata, disassemble bytecode back to a readable listing, or verify a compiled program before running it. xquad asm add.xqasm -o add.xqb followed by xquad run add.xqb, xquad dism add.xqb, and xquad verify add.xqb assembles, runs, disassembles, and verifies the four-instruction add.xqasm from Toolchain Map.

Stop here if you are working from a shell or from CI. Keep reading if you need to drive many runs programmatically rather than one at a time. Full coverage: CLI.

Rust Embedding

xqvm::InstructionBuilder builds a Program directly from Rust, with no .xqasm text step at all:

#![allow(unused)]
fn main() {
use xqvm::{InstructionBuilder, Vm};

let mut builder = InstructionBuilder::new();
builder.emit_push(10).emit_push(32).emit_add().emit_halt();
let program = builder.build().unwrap();

let mut vm = Vm::new();
vm.run(&program).unwrap();
assert_eq!(vm.stack(), &[42]);
}

The xqvm crate is no_std + alloc-compatible, so this is the surface for embedding XQVM where Python, or even a filesystem, is not available.

Stop here if you are embedding the VM inside another Rust program. Everyone else wants one of the five surfaces above. Full coverage: Builder API.

The Orthogonal Choice: Where It Solves

Whichever surface builds your model, you still choose separately where that model gets solved: local CPU or GPU simulated annealing, a D-Wave QPU, or the Quip network. xqsa.build_solver(name, seed=...) selects a backend by name regardless of which surface above produced the model, and every example runner exposes this as a --solver flag. See Backends.