Custom Functions
You can extend the DSL with your own reusable, chainable routines using addFunction(). This lets you define named sub-algorithms that integrate naturally into the fluent API.
Defining a Custom Function
circuit({ qubits: 3 }, Q => {
Q.addFunction('bellState', (q, control, target) => {
q.bit(control).h().cx(q.bit(target));
});
// Call it through the fnc proxy
Q.fnc.bellState(0, 1);
Q.fnc.bellState(1, 2);
Q.all().measure();
});
The first argument to the function body is always the circuit (q). Any subsequent arguments are what you pass when calling it.
Reusing Across Circuits
Define your routines as plain functions and call addFunction in any circuit:
function registerRoutines(Q) {
Q.addFunction('qft2', (q) => {
q.bit(0).h();
q.bit(0).cp(q.bit(1), q.π.div(2));
q.bit(1).h();
});
Q.addFunction('bellState', (q, ctrl, tgt) => {
q.bit(ctrl).h().cx(q.bit(tgt));
});
}
const c1 = circuit({ qubits: 2 }, Q => {
registerRoutines(Q);
Q.fnc.qft2();
Q.all().measure();
});
const c2 = circuit({ qubits: 4 }, Q => {
registerRoutines(Q);
Q.fnc.bellState(0, 1);
Q.fnc.bellState(2, 3);
Q.all().measure();
});
Notes
- Functions are registered on the circuit instance via
addFunctionand accessed throughQ.fnc. Q.fncis a proxy that simply returns the circuit itself, soQ.fnc.myFunc(...)is equivalent toQ.myFunc(...)after registration.- The function body receives the circuit as its first argument, followed by any arguments you pass at the call site.