def test_classical() -> None:
    # circuit to cover capabilities covered in HQS example notebook
    c = Circuit(1)
    a = c.add_c_register("a", 8)
    b = c.add_c_register("b", 10)
    c.add_c_register("c", 10)

    c.add_c_setbits([True], [a[0]])
    c.add_c_setbits([False, True] + [False] * 6, list(a))
    c.add_c_setbits([True, True] + [False] * 8, list(b))

    c.X(0, condition=reg_eq(a ^ b, 1))
    c.X(0, condition=(a[0] ^ b[0]))
    c.X(0, condition=reg_eq(a & b, 1))
    c.X(0, condition=reg_eq(a | b, 1))

    c.X(0, condition=a[0])
    c.X(0, condition=reg_neq(a, 1))
    c.X(0, condition=if_not_bit(a[0]))
    c.X(0, condition=reg_gt(a, 1))
    c.X(0, condition=reg_lt(a, 1))
    c.X(0, condition=reg_geq(a, 1))
    c.X(0, condition=reg_leq(a, 1))

    b = HoneywellBackend("HQS-LT-S1-APIVAL")

    b.compile_circuit(c)
    assert b.get_counts(c, 10)
def test_conditions() -> None:
    box_c = Circuit(2, 2)
    box_c.Z(0)
    box_c.Y(1, condition_bits=[0, 1], condition_value=1)
    box_c.Measure(0, 0, condition_bits=[0, 1], condition_value=0)
    box = CircBox(box_c)

    u = np.asarray([[0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1], [1, 0, 0, 0]])
    ubox = Unitary2qBox(u)

    c = Circuit(2, 2, name="c")
    b = c.add_c_register("b", 1)
    c.add_circbox(
        box,
        [Qubit(0), Qubit(1), Bit(0), Bit(1)],
        condition_bits=[b[0]],
        condition_value=1,
    )
    c.add_unitary2qbox(ubox,
                       Qubit(0),
                       Qubit(1),
                       condition_bits=[b[0]],
                       condition_value=0)
    c2 = c.copy()
    qc = tk_to_qiskit(c)
    c1 = qiskit_to_tk(qc)
    assert len(c1.get_commands()) == 2
    DecomposeBoxes().apply(c)
    DecomposeBoxes().apply(c1)
    assert c == c1

    c2.Z(1, condition=reg_eq(b, 1))
    qc = tk_to_qiskit(c2)
    c1 = qiskit_to_tk(qc)
    assert len(c1.get_commands()) == 3
def test_mixed_circuit() -> None:
    c = Circuit()
    qr = c.add_q_register("q", 2)
    ar = c.add_c_register("a", 1)
    br = c.add_c_register("b", 1)
    c.H(qr[0])
    c.Measure(qr[0], ar[0])
    c.X(qr[1], condition=reg_eq(ar, 0))
    c.Measure(qr[1], br[0])
    backend = AerBackend()
    backend.compile_circuit(c)
    counts = backend.get_counts(c, 1024)
    for key in counts.keys():
        assert key in {(0, 1), (1, 0)}
def pyquil_to_tk(prog: Program) -> Circuit:
    """
    Convert a :py:class:`pyquil.Program` to a tket :py:class:`Circuit` .
    Note that not all pyQuil operations are currently supported by pytket.

    :param prog: A circuit to be converted

    :return: The converted circuit
    """
    tkc = Circuit()
    qmap = {}
    for q in prog.get_qubits():
        uid = Qubit("q", q)
        tkc.add_qubit(uid)
        qmap.update({q: uid})
    cregmap: Dict = {}
    for i in prog.instructions:
        if isinstance(i, Gate):
            try:
                optype = _known_quil_gate[i.name]
            except KeyError as error:
                raise NotImplementedError("Operation not supported by tket: " +
                                          str(i)) from error
            qubits = [qmap[q.index] for q in i.qubits]
            params = [param_from_pyquil(p) for p in i.params]  # type: ignore
            tkc.add_gate(optype, params, qubits)
        elif isinstance(i, Measurement):
            qubit = qmap[i.qubit.index]
            reg = cregmap[i.classical_reg.name]  # type: ignore
            bit = reg[i.classical_reg.offset]  # type: ignore
            tkc.Measure(qubit, bit)
        elif isinstance(i, Declare):
            if i.memory_type == "BIT":
                new_reg = tkc.add_c_register(i.name, i.memory_size)
                cregmap.update({i.name: new_reg})
            elif i.memory_type == "REAL":
                continue
            else:
                raise NotImplementedError("Cannot handle memory of type " +
                                          i.memory_type)
        elif isinstance(i, Pragma):
            continue
        elif isinstance(i, Halt):
            return tkc
        else:
            raise NotImplementedError("PyQuil instruction is not a gate: " +
                                      str(i))
    return tkc
Example #5
0
def test_nondefault_registers() -> None:
    c = Circuit()

    qreg = c.add_q_register("g", 3)
    creg1 = c.add_c_register("a", 3)
    creg2 = c.add_c_register("b", 3)

    c.X(qreg[1])
    c.X(qreg[0])
    c.Measure(qreg[1], creg1[1])
    c.Measure(qreg[0], creg2[0])

    b = QsharpSimulatorBackend()
    b.compile_circuit(c)
    counts = b.get_result(b.process_circuit(c, 10)).get_counts()

    assert counts == {(0, 1, 0, 1, 0, 0): 10}
def test_condition_errors() -> None:
    with pytest.raises(Exception) as errorinfo:
        c = Circuit(2, 2)
        c.X(0, condition_bits=[0], condition_value=1)
        tk_to_qiskit(c)
    assert "OpenQASM conditions must be an entire register" in str(
        errorinfo.value)
    with pytest.raises(Exception) as errorinfo:
        c = Circuit(2, 2)
        b = c.add_c_register("b", 2)
        c.X(Qubit(0), condition_bits=[b[0], Bit(0)], condition_value=1)
        tk_to_qiskit(c)
    assert "OpenQASM conditions can only use a single register" in str(
        errorinfo.value)
    with pytest.raises(Exception) as errorinfo:
        c = Circuit(2, 2)
        c.X(0, condition_bits=[1, 0], condition_value=1)
        tk_to_qiskit(c)
    assert "OpenQASM conditions must be an entire register in order" in str(
        errorinfo.value)
Example #7
0
Transform.DecomposeBoxes().apply(c)
print(c.get_commands())

# Note that the unitaries have been decomposed into elementary gates.

# ## Classical controls

# Most of the examples above involve only pure quantum gates. However, `pytket` can also represent gates whose operation is conditional on one or more classical inputs.
#
# For example, suppose we want to run the complex circuit `c` we've just constructed, then measure qubits 0 and 1, and finally apply an $\mathrm{Rz}(\frac{1}{2})$ rotation to qubit 2 if and only if the measurements were 0 and 1 respectively.
#
# First, we'll add two classical wires to the circuit to store the measurement results:

from pytket.circuit import Bit

c.add_c_register("m", 2)
m = [Bit("m", i) for i in range(2)]

# Classically conditioned operations depend on all their inputs being 1. Since we want to condition on `m[0]` being 0, we must first apply an X gate to its qubit, and then measure:

q = [Qubit("q", i) for i in range(3)]
c.X(q[0])
c.Measure(q[0], m[0])
c.Measure(q[1], m[1])

# Finally we add the classically conditioned Rz operation, using the `add_gate()` method:

from pytket.circuit import OpType

c.add_gate(OpType.Rz, [0.5], [q[2]],
           condition_bits=[m[0], m[1]],
Example #8
0
class CircuitBuilder:
    def __init__(
        self,
        qregs: List[QuantumRegister],
        cregs: Optional[List[ClassicalRegister]] = None,
        name: Optional[str] = None,
        phase: Optional[float] = 0.0,
    ):
        self.qregs = qregs
        self.cregs = [] if cregs is None else cregs
        self.tkc = Circuit(name=name)
        self.tkc.add_phase(phase)
        self.qregmap = {}
        for reg in qregs:
            tk_reg = self.tkc.add_q_register(reg.name, len(reg))
            self.qregmap.update({reg: tk_reg})
        self.cregmap = {}
        for reg in self.cregs:
            tk_reg = self.tkc.add_c_register(reg.name, len(reg))
            self.cregmap.update({reg: tk_reg})

    def circuit(self) -> Circuit:
        return self.tkc

    def add_qiskit_data(self, data: "QuantumCircuitData") -> None:
        for i, qargs, cargs in data:
            condition_kwargs = {}
            if i.condition is not None:
                cond_reg = self.cregmap[i.condition[0]]
                condition_kwargs = {
                    "condition_bits":
                    [cond_reg[k] for k in range(len(cond_reg))],
                    "condition_value": i.condition[1],
                }
            if type(i) == ControlledGate:
                if type(i.base_gate) == qiskit_gates.RYGate:
                    optype = OpType.CnRy
                else:
                    # Maybe handle multicontrolled gates in a more general way,
                    # but for now just do CnRy
                    raise NotImplementedError(
                        "qiskit ControlledGate with " +
                        "base gate {} not implemented".format(i.base_gate))
            else:
                optype = _known_qiskit_gate[type(i)]

            qubits = [
                self.qregmap[qbit.register][qbit.index] for qbit in qargs
            ]
            bits = [self.cregmap[bit.register][bit.index] for bit in cargs]

            if optype == OpType.Unitary2qBox:
                u = i.to_matrix()
                ubox = Unitary2qBox(u)
                self.tkc.add_unitary2qbox(ubox, qubits[0], qubits[1],
                                          **condition_kwargs)
            elif optype == OpType.Barrier:
                self.tkc.add_barrier(qubits)
            elif optype in (OpType.CircBox, OpType.Custom):
                qregs = [QuantumRegister(i.num_qubits, "q")
                         ] if i.num_qubits > 0 else []
                cregs = ([ClassicalRegister(i.num_clbits, "c")]
                         if i.num_clbits > 0 else [])
                builder = CircuitBuilder(qregs, cregs)
                builder.add_qiskit_data(i.definition)
                subc = builder.circuit()
                if optype == OpType.CircBox:
                    cbox = CircBox(subc)
                    self.tkc.add_circbox(cbox, qubits + bits,
                                         **condition_kwargs)
                else:
                    # warning, this will catch all `Gate` instances
                    # that were not picked up as a subclass in _known_qiskit_gate
                    params = [param_to_tk(p) for p in i.params]
                    gate_def = CustomGateDef.define(i.name, subc,
                                                    list(subc.free_symbols()))
                    self.tkc.add_custom_gate(gate_def, params, qubits + bits)
            else:
                params = [param_to_tk(p) for p in i.params]
                self.tkc.add_gate(optype, params, qubits + bits,
                                  **condition_kwargs)