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.
| Surface | What it is | Who it is for |
|---|---|---|
xqcp DSL | Python constraint-programming layer; compiles a problem to XQVM assembly | Modelling a new combinatorial problem without hand-writing assembly |
xquad Program/Session API | Program / Session / RunResult: load a program once, run it repeatedly with fresh calldata | Driving an existing compiled program from Python – a REPL, a notebook, a script |
xqffi.vm FFI | Vm: a thin wrapper over the Rust interpreter | Python code building its own convenience layer on top of the raw Rust VM |
xquad.vm VM wrapper | VM: runs .xqasm source text or bytecode on the Rust interpreter, keeping calldata, output slots and limits across runs | Scripts that run several programs in a row with the same settings; the surface every example runner under examples/ uses |
xquad CLI | xquad vm asm / run / dis / check | Assembling, running, inspecting, or verifying one .xqasm/.xqb file, no Python involved |
| Rust embedding | xqvm::InstructionBuilder, building a Program directly, no text assembly step | Embedding 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 – The Source-Level VM
xquad.vm.VM wraps xqffi.vm.Vm. run(source) assembles .xqasm text
and runs it; run_bytecode(bytecode) runs pre-assembled bytes. Calldata,
output slots, and the step and memory limits persist across runs until
reset(), while every run starts from a fresh stack and register file.
Outputs come back as the xqffi types unchanged: int, list[int],
XqmxModel, XqmxSample, or None. Every example runner under
examples/ imports VM from here, not xqffi.vm directly.
Stop here if you run .xqasm source from a script and want the settings
to carry from one run to the next. Keep reading if you need the raw FFI
underneath instead. Full coverage: Running
Programs.
xquad CLI
xquad vm asm, xquad vm run, xquad vm dis, xquad vm check – 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 vm asm add.xqasm -o add.xqb followed by xquad vm run add.xqb,
xquad vm dis add.xqb, and xquad vm check 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.