Skip to content

Commit

Permalink
[add] tequila support for multi-controlled gates (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mc-Zen authored Oct 15, 2024
1 parent f8368c1 commit 209ab4a
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 8 deletions.
65 changes: 58 additions & 7 deletions src/tequila-impl.typ
Original file line number Diff line number Diff line change
@@ -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
),)
Expand All @@ -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,) }
Expand All @@ -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
}
Expand Down Expand Up @@ -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.
///
Expand Down Expand Up @@ -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))
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/tequila.typ
Original file line number Diff line number Diff line change
@@ -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
#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
Binary file added tests/tequila/basic/ref/9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions tests/tequila/basic/test.typ
Original file line number Diff line number Diff line change
Expand Up @@ -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$))
))

0 comments on commit 209ab4a

Please sign in to comment.