From 209ab4af8dfb19bf33be4b5df0b2646e7d51a3ef Mon Sep 17 00:00:00 2001 From: Mc-Zen <52877387+Mc-Zen@users.noreply.github.com> Date: Tue, 15 Oct 2024 12:10:56 +0200 Subject: [PATCH] [add] tequila support for multi-controlled gates (#14) --- src/tequila-impl.typ | 65 ++++++++++++++++++++++++++++++---- src/tequila.typ | 2 +- tests/tequila/basic/ref/9.png | Bin 0 -> 5281 bytes tests/tequila/basic/test.typ | 15 ++++++++ 4 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 tests/tequila/basic/ref/9.png diff --git a/src/tequila-impl.typ b/src/tequila-impl.typ index 2fe23f4..bfbb595 100644 --- a/src/tequila-impl.typ +++ b/src/tequila-impl.typ @@ -1,9 +1,9 @@ #import "gates.typ" -#let bgate(qubit, constructor, nq: 1, end: none, ..args) = (( +#let bgate(qubit, constructor, nq: 1, supplements: (), ..args) = (( qubit: qubit, n: nq, - end: end, + supplements: supplements, constructor: constructor, args: args ),) @@ -20,7 +20,14 @@ #let generate-two-qubit-gate(control, target, start, end) = { if type(control) == int and type(target) == int { - return bgate(control, start, nq: target - control + 1, end: end, target - control) + assert.ne(target, control, message: "Target and control qubit cannot be the same") + return bgate( + control, + start, + target - control, + nq: target - control + 1, + supplements: ((target, end),) + ) } let gates = () if type(control) == int { control = (control,) } @@ -30,8 +37,34 @@ let c = control.at(i, default: control.last()) let t = target.at(i, default: target.last()) assert.ne(t, c, message: "Target and control qubit cannot be the same") - gates.push(bgate(c, start, nq: t - c + 1, end: end, t - c) ) + gates.push(bgate(c, start, nq: t - c + 1, t - c, supplements: ((t, end),))) + } + gates +} + +#let generate-multi-controlled-gate(controls, qubit, target) = { + let sort-ops(cs, q) = { + let k = cs.map(c => (c, gates.ctrl.with(0))) + ((q, target),) + k = k.sorted(key: x => x.first()) + let n = k.last().at(0) - k.first().at(0) + if k.first().at(1) == gates.ctrl.with(0) { k.first().at(1) = gates.ctrl.with(n) } + else if k.last().at(1) == gates.ctrl.with(0) { k.at(2).at(1) = gates.ctrl.with(-n) } + return k + } + let gates = () + controls = controls.map(c => if type(c) == int { (c,)} else { c }) + if type(qubit) == int { qubit = (qubit,) } + for i in range(calc.max(qubit.len(), ..controls.map(array.len))) { + let q = qubit.at(i, default: qubit.last()) + let cs = controls.map(c => c.at(i, default: c.last())) + assert((cs + (q,)).dedup().len() == cs.len() + 1, message: "Target and control qubits need to be all different (were " + str(q) + " and " + repr(cs) + ")") + let ops = sort-ops(cs, q) + gates.push(bgate( + ops.first().at(0), ops.first().at(1), + nq: ops.last().at(0) - ops.first().at(0) + 1, + supplements: ops.slice(1) + )) } gates } @@ -78,12 +111,28 @@ #let swap(control, target) = generate-two-qubit-gate( control, target, gates.swap, gates.swap.with(0) ) +#let ccx(control1, control2, target) = generate-multi-controlled-gate( + (control1, control2), target, gates.targ +) +#let cccx(control1, control2, control3, target) = generate-multi-controlled-gate( + (control1, control2, control3), target, gates.targ +) +#let ccz(control1, control2, target) = generate-multi-controlled-gate( + (control1, control2), target, gates.ctrl.with(0) +) +#let cca(control1, control2, target, content) = generate-multi-controlled-gate( + (control1, control2), target, gates.gate.with(content) +) #let ca(control, target, content) = generate-two-qubit-gate( control, target, gates.ctrl, gates.gate.with(content) ) +#let multi-controlled-gate(controls, qubit, target) = generate-multi-controlled-gate( + controls, qubit, target +) + /// Constructs a circuit from operation instructions. /// @@ -117,17 +166,19 @@ (q1, q2) = (0, num-qubits - 1) } let max-track-len = calc.max(..tracks.slice(q1, q2 + 1).map(array.len)) + let h = (q1, q2) + let h = (start,) + op.supplements.map(x => x.first()) for q in range(q1, q2 + 1) { let dif = max-track-len - tracks.at(q).len() - if op.constructor != barrier and q not in (q1, q2) { + if op.constructor != barrier and q not in h { dif += 1 } tracks.at(q) += (1,) * dif } if op.constructor != barrier { tracks.at(start).push((op.constructor)(..op.args, x: x + tracks.at(start).len(), y: y + start)) - if op.end != none { - tracks.at(end).push((op.end)(x: x + tracks.at(end).len(), y: y + end)) + for (qubit, supplement) in op.supplements { + tracks.at(qubit).push((supplement)(x: x + tracks.at(end).len(), y: y + qubit)) } } } diff --git a/src/tequila.typ b/src/tequila.typ index 40d5777..86cf4bb 100644 --- a/src/tequila.typ +++ b/src/tequila.typ @@ -1 +1 @@ -#import "tequila-impl.typ": build, h, gate, mqgate, x, y, z, cx, cz, s, sdg, sx, sxdg, t, tdg, p, rx, ry, rz, u, barrier, swap, meter, graph-state, qft \ No newline at end of file +#import "tequila-impl.typ": build, h, gate, mqgate, x, y, z, cx, cz, s, sdg, sx, sxdg, t, tdg, p, rx, ry, rz, u, barrier, swap, meter, graph-state, qft, ccx, ccz, cca, cccx, multi-controlled-gate \ No newline at end of file diff --git a/tests/tequila/basic/ref/9.png b/tests/tequila/basic/ref/9.png new file mode 100644 index 0000000000000000000000000000000000000000..2b97122180682c1d829a99d1112d44e5298f5566 GIT binary patch literal 5281 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 YV)c2+qB|JaAGJpvI8viR?U#tZ11>MPE&u=k literal 0 HcmV?d00001 diff --git a/tests/tequila/basic/test.typ b/tests/tequila/basic/test.typ index dfd7686..6eb5323 100644 --- a/tests/tequila/basic/test.typ +++ b/tests/tequila/basic/test.typ @@ -81,3 +81,18 @@ tq.meter(range(1,3)), )) + + +#pagebreak() + +#quill.quantum-circuit(..tq.build( + tq.ccx((0, 1, 2, 1, 0, 2), (1, 0, 1, 2, 2, 0), (2, 2, 0, 0, 1, 1)), + tq.ccx(2, 4, 1), + tq.ccz(2, 3, 1), + tq.y(1), + tq.cca(1, 4, 2, $X$), + tq.h(range(5)), + tq.cccx(0, 1, 3, 2), + tq.multi-controlled-gate((0,1,4), 2, quill.mqgate.with(n:2, $K$)) +)) +