예제 #1
0
def test_compilation_pass() -> None:
    b = MyBackend()
    for opt_level in range(3):
        c = Circuit(2)
        c.CX(0, 1)
        u = np.asarray([[0, 1], [-1j, 0]])
        c.add_unitary1qbox(Unitary1qBox(u), 1)
        c.CX(0, 1)
        c.add_gate(OpType.CRz, 0.35, [1, 0])
        assert not (b.valid_circuit(c))
        b.compile_circuit(c, optimisation_level=opt_level)
        assert b.valid_circuit(c)
예제 #2
0
def default_compilation_pass(self, optimisation_level: int = 1) -> BasePass:
    """
    A suggested compilation pass that will guarantee the resulting circuit
    will be suitable to run on this backend with as few preconditions as
    possible.

    :param optimisation_level: The level of optimisation to perform during
        compilation. Level 0 just solves the device constraints without
        optimising. Level 1 additionally performs some light optimisations.
        Level 2 adds more intensive optimisations that can increase compilation
        time for large circuits. Defaults to 1.
    :type optimisation_level: int, optional
    :return: Compilation pass guaranteeing required predicates.
    :rtype: BasePass
    """
    assert optimisation_level in range(3)
    cx_circ = Circuit(2)
    cx_circ.Sdg(0)
    cx_circ.V(1)
    cx_circ.Sdg(1)
    cx_circ.Vdg(1)
    cx_circ.add_gate(OpType.ZZMax, [0, 1])
    cx_circ.Vdg(1)
    cx_circ.Sdg(1)
    cx_circ.add_phase(0.5)

    def sq(a, b, c):
        circ = Circuit(1)
        if c != 0:
            circ.Rz(c, 0)
        if b != 0:
            circ.Rx(b, 0)
        if a != 0:
            circ.Rz(a, 0)
        return circ

    rebase = RebaseCustom({OpType.ZZMax}, cx_circ,
                          {OpType.Rx, OpType.Ry, OpType.Rz}, sq)
    squash = SquashCustom({OpType.Rz, OpType.Rx, OpType.Ry}, sq)
    seq = [DecomposeBoxes()]  # Decompose boxes into basic gates
    if optimisation_level == 1:
        seq.append(SynthesiseIBM())  # Optional fast optimisation
    elif optimisation_level == 2:
        seq.append(FullPeepholeOptimise())  # Optional heavy optimisation
    seq.append(rebase)  # Map to target gate set
    if optimisation_level != 0:
        seq.append(
            squash)  # Optionally simplify 1qb gate chains within this gate set
    return SequencePass(seq)
예제 #3
0
def iterated_entanglement_swap(n_iter):
    # Iterate the entanglement swapping protocol n_iter times
    it_es = Circuit()
    ava = it_es.add_q_register("a", 1)
    bella = it_es.add_q_register("b", 2)
    charlie = it_es.add_q_register("c", 1)
    data = it_es.add_c_register("d", 2)

    # Start with an initial Bell state
    it_es.H(ava[0])
    it_es.CX(ava[0], bella[0])

    for i in range(n_iter):
        if i % 2 == 0:
            # Teleport bella[0] to charlie[0] to give a Bell pair between ava[0] and charlier[0]
            tel_to_c = qtel.copy()
            tel_to_c.rename_units(
                {alice[0]: bella[0], alice[1]: bella[1], bob[0]: charlie[0]}
            )
            it_es.append(tel_to_c)
            it_es.add_gate(OpType.Reset, [bella[0]])
            it_es.add_gate(OpType.Reset, [bella[1]])
        else:
            # Teleport charlie[0] to bella[0] to give a Bell pair between ava[0] and bella[0]
            tel_to_b = qtel.copy()
            tel_to_b.rename_units(
                {alice[0]: charlie[0], alice[1]: bella[1], bob[0]: bella[0]}
            )
            it_es.append(tel_to_b)
            it_es.add_gate(OpType.Reset, [bella[1]])
            it_es.add_gate(OpType.Reset, [charlie[0]])
    # Return the circuit and the qubits expected to share a Bell pair
    if n_iter % 2 == 0:
        return it_es, [ava[0], bella[0]]
    else:
        return it_es, [ava[0], charlie[0]]
예제 #4
0
파일: qasm.py 프로젝트: tbcdebug/pytket
class QASMParser(object):
    """Class for parsing OpenQASM files into CQC t|ket> Circuits."""
    def __init__(self):
        self.circuit = Circuit()
        self.register_dict = dict()

    def parse_qasm(self, qasm):
        lines = qasm.splitlines()
        rows = []

        #first, get rid of comments and whitespace lines
        for l in lines:
            i = l.find("//")
            if i != -1:
                s = l[0:i].strip()
            else:
                s = l.strip()
            if s: rows.append(s)

        #now, throw away OPENQASM descriptor etc.
        if not (rows[0].startswith("OPENQASM 2.0")
                and rows[1].startswith('include "qelib1.inc";')):
            raise TypeError(
                "File must declare OPENQASM version and its includes.")
        data = "\n".join(rows[2:])

        #now, separate out the custom gates to deal with elsewhere
        while True:
            i = data.find("gate ")
            if i == -1: break
            j = data.find("}", i)
            if j == -1: raise TypeError("Custom gate definition is invalid.")
            self.parse_custom_gate(data[i:j + 1])  #TODO: deal with custom gate
            data = data[:i] + data[j + 1:]

        #now, parse the regular instructions
        instructions = [s.strip() for s in data.split(";") if s.strip()]
        for i in instructions:
            self.parse_instruction(i)
        return self.circuit

    def parse_custom_gate(self, data):
        raise TypeError("Cannot currently parse custom gates")

    def parse_instruction(self, instruction):
        if instruction.find("->") != -1:
            ###handle measure gates
            ###currently assumes that there is just 1 qb being read to 1 bit
            name_and_qbs, bits = instruction.split("->", 1)
            if (name_and_qbs.find("measure") == -1):
                raise Exception(
                    "Error in parsing: cannot accept a non-Measure gate writing to classical register"
                )
            name_and_qbs = name_and_qbs.replace("measure", "")
            name_and_qbs = name_and_qbs.replace(" ", "")

            name_and_qbs.strip()
            qregname, qbindex = name_and_qbs.split("[")
            qbindex = int(qbindex[0])
            qubit = self.circuit.q_regs[qregname][qbindex]

            bits = bits.replace(" ", "")
            bitreg, bitindex = bits.split("[")
            bitindex = int(bitindex[0])
            bit = self.circuit.c_regs[bitreg][bitindex]

            self.circuit.add_measure(qubit, bit)
            return

        if instruction.find("(") != -1:
            name, rest = instruction.split(") ", 1)
            name = name.replace(" ", "")
        else:
            name, rest = instruction.split(" ", 1)
        args = [s.strip() for s in rest.split(",") if s.strip()]

        #deal with qubit register declarations
        if name == "qreg" or name == "creg":
            regname, size = args[0].split("[", 1)
            regname.strip()
            size = int(size[:-1])
            if name == "qreg":
                self.circuit.add_q_register(regname, size)
            else:
                self.circuit.add_c_register(regname, size)
            return

        #get qubits to append operation to
        qubits = []
        for a in args:
            if "[" in a:
                regname, val = a.split("[", 1)
                val = int(val[:-1])
                qubits.append(self.circuit.q_regs[regname][val])
            else:
                raise Exception(
                    "Unknown error in parsing: Cannot parse argument {}".
                    format(a))

        #if the gate is parameterised, get these parameters
        if name.find("(") != -1:
            name, params = name.split("(", 1)
            if name in PARAM_COMMANDS:
                angles = [s.strip() for s in params.split(",") if s.strip()]
                halfturn_angles = []
                for ang in angles:
                    ang = ang.replace("pi", str(math.pi))
                    try:
                        halfturns = sympify(ang) / math.pi
                        halfturn_angles.append(halfturns)
                    except:
                        raise TypeError("Cannot parse angle: {}".format(ang))
                self.circuit.add_gate(PARAM_COMMANDS[name], halfturn_angles,
                                      qubits, [])

            else:
                raise TypeError("Cannot parse gate of type: {}".format(name))

        else:
            if name in NOPARAM_COMMANDS:
                self.circuit.add_gate(NOPARAM_COMMANDS[name], [], qubits, [])
            else:
                raise TypeError("Cannot parse gate of type: {}".format(name))