def test_copy_to_tikz(): x, y = map(Ty, ("$x$", "$y$")) copy_x, copy_y = Box('COPY', x, x @ x), Box('COPY', y, y @ y) copy_x.draw_as_spider, copy_y.draw_as_spider = True, True copy_x.drawing_name, copy_y.drawing_name = "", "" copy_x.color, copy_y.color = "black", "black" return copy_x @ copy_y >> Id(x) @ Swap(x, y) @ Id(y)
def test_draw_who(): n, s = Ty('n'), Ty('s') copy, update = Box('copy', n, n @ n), Box('update', n @ s, s) return Cap(n.r, n)\ >> Id(n.r) @ copy\ >> Id(n.r @ n) @ Cap(s, s.l) @ Id(n)\ >> Id(n.r) @ update @ Id(s.l @ n)
def test_cross_composition_draw(): s, n = Ty('s'), Ty('n') gave, up = Word('gave', n.r @ s @ n.l), Word('up', s.r @ n.r.r @ n.r @ s) swap, cups = Diagram.swap, Diagram.cups diagram = gave @ up >> Id(n.r @ s) @ swap(n.l, s.r @ n.r.r) @ Id(n.r @ s)\ >> cups(n.r @ s, s.r @ n.r.r) @ swap(n.l, n.r @ s) grammar.draw(diagram, path='.') return diagram
def test_who_ansatz_to_tikz(): s, n = Ty('s'), Ty('n') who = Word('who', n.r @ n @ s.l @ n) who_ansatz = Cap(n.r, n)\ >> Id(n.r) @ Box('copy', n, n @ n)\ >> Id(n.r @ n) @ Cap(s, s.l) @ Id(n)\ >> Id(n.r) @ Box('update', n @ s, n) @ Id(s.l @ n) return who, who_ansatz
def test_draw_eggs(): def merge(x): return Box('merge', x @ x, x) egg, white, yolk = Ty('egg'), Ty('white'), Ty('yolk') crack = Box('crack', egg, white @ yolk) return crack @ crack\ >> Id(white) @ Swap(yolk, white) @ Id(yolk)\ >> merge(white) @ merge(yolk)
def test_tikz_eggs(): def merge(x): box = Box('merge', x @ x, x, draw_as_spider=True) return box egg, white, yolk = Ty('egg'), Ty('white'), Ty('yolk') crack = Box('crack', egg, white @ yolk) return crack @ crack\ >> Id(white) @ Swap(yolk, white) @ Id(yolk)\ >> merge(white) @ merge(yolk)
def make_units_adjacent(tk_gate): offset = tk_gate.qubits[0].index[0] swaps = Id(qubit**n_qubits @ bit**n_bits) for i, tk_qubit in enumerate(tk_gate.qubits[1:]): source, target = tk_qubit.index[0], offset + i + 1 if source < target: left, right = swaps.cod[:source], swaps.cod[target:] swap = Id.swap(swaps.cod[source:source + 1], swaps.cod[source + 1:target]) if source <= offset: offset -= 1 elif source > target: left, right = swaps.cod[:target], swaps.cod[source + 1:] swap = Id.swap(swaps.cod[target:target + 1], swaps.cod[target + 1:source + 1]) else: # pragma: no cover continue # units are adjacent already swaps = swaps >> Id(left) @ swap @ Id(right) return offset, swaps
def spiral(n_cups): """ Implements the asymptotic worst-case for normal_form, see arXiv:1804.07832. """ x = Ty('x') unit, counit = Box('unit', Ty(), x), Box('counit', x, Ty()) cup, cap = Box('cup', x @ x, Ty()), Box('cap', Ty(), x @ x) for box in [unit, counit, cup, cap]: box.draw_as_spider, box.color, box.drawing_name = True, "black", "" result = unit for i in range(n_cups): result = result >> Id(x**i) @ cap @ Id(x**(i + 1)) result = result >> Id(x**n_cups) @ counit @ Id(x**n_cups) for i in range(n_cups): result = result >>\ Id(x ** (n_cups - i - 1)) @ cup @ Id(x ** (n_cups - i - 1)) return result
def from_tk(tk_circuit): """ Translates from tket to discopy. """ if not isinstance(tk_circuit, tk.Circuit): raise TypeError(messages.type_err(tk.Circuit, tk_circuit)) if not isinstance(tk_circuit, Circuit): tk_circuit = Circuit.upgrade(tk_circuit) n_bits = tk_circuit.n_bits - len(tk_circuit.post_selection) n_qubits = tk_circuit.n_qubits def box_from_tk(tk_gate): name = tk_gate.op.type.name if name == 'Rx': return Rx(tk_gate.op.params[0] / 2) if name == 'Rz': return Rz(tk_gate.op.params[0] / 2) if name == 'CRz': return CRz(tk_gate.op.params[0] / 2) for gate in GATES: if name == gate.name: return gate raise NotImplementedError def make_units_adjacent(tk_gate): offset = tk_gate.qubits[0].index[0] swaps = Id(qubit**n_qubits @ bit**n_bits) for i, tk_qubit in enumerate(tk_gate.qubits[1:]): source, target = tk_qubit.index[0], offset + i + 1 if source < target: left, right = swaps.cod[:source], swaps.cod[target:] swap = Id.swap(swaps.cod[source:source + 1], swaps.cod[source + 1:target]) if source <= offset: offset -= 1 elif source > target: left, right = swaps.cod[:target], swaps.cod[source + 1:] swap = Id.swap(swaps.cod[target:target + 1], swaps.cod[target + 1:source + 1]) else: # pragma: no cover continue # units are adjacent already swaps = swaps >> Id(left) @ swap @ Id(right) return offset, swaps circuit, bras = Id(qubit**n_qubits @ bit**n_bits), {} for tk_gate in tk_circuit.get_commands(): if tk_gate.op.type.name == "Measure": offset = tk_gate.qubits[0].index[0] bit_index = tk_gate.bits[0].index[0] if bit_index in tk_circuit.post_selection: bras[offset] = tk_circuit.post_selection[bit_index] continue # post selection happens at the end box = Measure(destructive=False, override_bits=True) swaps = Id(circuit.cod[:offset + 1]) @ Id.swap( circuit.cod[offset + 1:n_qubits + bit_index], circuit.cod[n_qubits:][bit_index: bit_index + 1])\ @ Id(circuit.cod[n_qubits + bit_index + 1:]) else: box = box_from_tk(tk_gate) offset, swaps = make_units_adjacent(tk_gate) left, right = swaps.cod[:offset], swaps.cod[offset + len(box.dom):] circuit = circuit >> swaps >> Id(left) @ box @ Id(right) >> swaps[::-1] circuit = circuit >> Id(0).tensor( *(Bra(bras[i]) if i in bras else Id(circuit.cod[i:i + 1]) for i, _ in enumerate(circuit.cod))) if tk_circuit.scalar != 1: circuit = circuit @ scalar_box(tk_circuit.scalar) return circuit
def test_tikz_bell_state(): from discopy.quantum import H, sqrt, Bra, Ket, Id, CX H.draw_as_spider, H.color, H.drawing_name = True, "yellow", "" return sqrt(2) >> Ket(0, 0) >> H @ Id(1) >> CX >> Bra(0) @ Id(1)
def test_snake_equation_to_tikz(): x = Ty('x') return Id(x.r).transpose(left=True), Id(x), Id(x.l).transpose()
def test_sentence_to_tikz(): s, n = Ty('s'), Ty('n') Alice, Bob = Word('Alice', n), Word('Bob', n) loves = Word('loves', n.r @ s @ n.l) return Alice @ loves @ Bob >> Cup(n, n.r) @ Id(s) @ Cup(n.l, n)
def test_draw_typed_snake(): x = Ty('x') return Id(x.r).transpose(left=True), Id(x), Id(x.l).transpose()
def test_draw_bialgebra(): from discopy.quantum.zx import Z, X, Id, SWAP bialgebra = Z(1, 2) @ Z(1, 2) >> Id(1) @ SWAP @ Id(1) >> X(2, 1) @ X(2, 1) return bialgebra + bialgebra
def test_draw_bell_state(): from discopy.quantum import H, sqrt, Bra, Ket, Id, CX return sqrt(2) >> Ket(0, 0) >> H @ Id(1) >> CX >> Bra(0) @ Id(1)
def test_tikz_bialgebra_law(): from discopy.quantum.zx import Z, X, Id, SWAP source = X(2, 1) >> Z(1, 2) target = Z(1, 2) @ Z(1, 2) >> Id(1) @ SWAP @ Id(1) >> X(2, 1) @ X(2, 1) return source, target
def remove_ket1(box): if not isinstance(box, Ket): return box x_gates = Id(0).tensor(*(X if x else Id(1) for x in box.bitstring)) return Ket(*(len(box.bitstring) * (0, ))) >> x_gates
def test_pregroup_draw(): s, n = Ty('s'), Ty('n') Alice, Bob = Word('Alice', n), Word('Bob', n) loves = Word('loves', n.r @ s @ n.l) return Alice @ loves @ Bob >> Cup(n, n.r) @ Id(s) @ Cup(n.l, n)