def _get_flipped_protoquil_program(program: Program) -> Program:
    """For symmetrization, generate a program where X gates are added before measurement.

    Forest 1.3 is really picky about where the measure instructions happen. It has to be
    at the end!
    """
    program = program.copy()
    to_measure = []
    while len(program) > 0:
        inst = program.instructions[-1]
        if isinstance(inst, Measurement):
            program.pop()
            to_measure.append((inst.qubit, inst.classical_reg))
        else:
            break

    program += Pragma('PRESERVE_BLOCK')
    for qu, addr in to_measure[::-1]:
        program += RX(pi, qu)
    program += Pragma('END_PRESERVE_BLOCK')

    for qu, addr in to_measure[::-1]:
        program += Measurement(qubit=qu, classical_reg=addr)

    return program
Exemple #2
0
def tk_to_pyquil(circ: Union[Circuit,PhysicalCircuit]) -> Program:
    """
       Convert a :math:`\\mathrm{t|ket}\\rangle` :py:class:`Circuit` to a :py:class:`pyquil.Program` .
    
    :param circ: A circuit to be converted

    :return: The converted circuit
    """
    p = Program()
    ro = p.declare('ro', 'BIT', circ.n_qubits)
    for command in circ:
        op = command.op
        optype = op.get_type()
        if optype == OpType.Input or optype == OpType.Output:
            continue
        elif optype == OpType.Measure:
            p += Measurement(Qubit(command.qubits[0]), ro[int(op.get_desc())])
            continue
        try:
            gatetype = _known_quil_gate_rev[optype]
        except KeyError as error:
            raise NotImplementedError("Cannot convert tket Op to pyquil gate: " + op.get_name()) from error
        params = []
        for par in op.get_params():
            try:
                params.append(par.evalf()*PI)
            except:
                params.append(par*PI)
        g = Gate(gatetype, params, [Qubit(q) for q in command.qubits])
        p += g
    return p
Exemple #3
0
 def exitMeasure(self, ctx):
     # type: (QuilParser.MeasureContext) -> None
     qubit = _qubit(ctx.qubit())
     classical = None
     if ctx.addr():
         classical = _addr(ctx.addr())
     self.result.append(Measurement(qubit, classical))
Exemple #4
0
def address_qubits(program, qubit_mapping=None):
    """
    Takes a program which contains placeholders and assigns them all defined values.

    Either all qubits must be defined or all undefined. If qubits are
    undefined, you may provide a qubit mapping to specify how placeholders get mapped
    to actual qubits. If a mapping is not provided, integers 0 through N are used.

    This function will also instantiate any label placeholders.

    :param program: The program.
    :param qubit_mapping: A dictionary-like object that maps from :py:class:`QubitPlaceholder`
        to :py:class:`Qubit` or ``int`` (but not both).
    :return: A new Program with all qubit and label placeholders assigned to real qubits and labels.
    """
    fake_qubits, real_qubits, qubits = _what_type_of_qubit_does_it_use(program)
    if real_qubits:
        if qubit_mapping is not None:
            warnings.warn(
                "A qubit mapping was provided but the program does not "
                "contain any placeholders to map!")
        return program

    if qubit_mapping is None:
        qubit_mapping = {qp: Qubit(i) for i, qp in enumerate(qubits)}
    else:
        if all(isinstance(v, Qubit) for v in qubit_mapping.values()):
            pass  # we good
        elif all(isinstance(v, int) for v in qubit_mapping.values()):
            qubit_mapping = {k: Qubit(v) for k, v in qubit_mapping.items()}
        else:
            raise ValueError(
                "Qubit mapping must map to type Qubit or int (but not both)")

    result = []
    for instr in program:
        # Remap qubits on Gate and Measurement instructions
        if isinstance(instr, Gate):
            remapped_qubits = [qubit_mapping[q] for q in instr.qubits]
            result.append(Gate(instr.name, instr.params, remapped_qubits))
        elif isinstance(instr, Measurement):
            result.append(
                Measurement(qubit_mapping[instr.qubit], instr.classical_reg))
        elif isinstance(instr, Pragma):
            new_args = []
            for arg in instr.args:
                # Pragmas can have arguments that represent things besides qubits, so here we
                # make sure to just look up the QubitPlaceholders.
                if isinstance(arg, QubitPlaceholder):
                    new_args.append(qubit_mapping[arg])
                else:
                    new_args.append(arg)
            result.append(
                Pragma(instr.command, new_args, instr.freeform_string))
        # Otherwise simply add it to the result
        else:
            result.append(instr)

    return Program(result)
Exemple #5
0
def MEASURE(qubit, classical_reg=None):
    """
    Produce a MEASURE instruction.

    :param qubit: The qubit to measure.
    :param classical_reg: The classical register to measure into, or None.
    :return: A Measurement instance.
    """
    qubit = unpack_qubit(qubit)
    address = None if classical_reg is None else unpack_classical_reg(classical_reg)
    return Measurement(qubit, address)
def get_flipped_program(program: Program) -> Program:
    """For symmetrization, generate a program where X gates are added before measurement."""
    flipped_prog = Program()
    for inst in program:
        if isinstance(inst, Measurement):
            flipped_prog += Pragma('PRESERVE_BLOCK')
            flipped_prog += RX(pi, inst.qubit)
            flipped_prog += Measurement(qubit=inst.qubit, classical_reg=inst.classical_reg)
            flipped_prog += Pragma('END_PRESERVE_BLOCK')
        else:
            flipped_prog.inst(inst)

    return flipped_prog
Exemple #7
0
def MEASURE(qubit: QubitDesignator, classical_reg: Optional[MemoryReferenceDesignator]) -> Measurement:
    """
    Produce a MEASURE instruction.

    :param qubit: The qubit to measure.
    :param classical_reg: The classical register to measure into, or None.
    :return: A Measurement instance.
    """
    qubit = unpack_qubit(qubit)
    if classical_reg is None:
        address = None
    else:
        address = unpack_classical_reg(classical_reg)
    return Measurement(qubit, address)
Exemple #8
0
def tk_to_pyquil(tkcirc: Union[Circuit, PhysicalCircuit],
                 active_reset: bool = False) -> Program:
    """
       Convert a :math:`\\mathrm{t|ket}\\rangle` :py:class:`Circuit` to a :py:class:`pyquil.Program` .
    
    :param tkcirc: A circuit to be converted

    :return: The converted circuit
    """
    circ = tkcirc
    if isinstance(tkcirc, PhysicalCircuit):
        circ = tkcirc._get_circuit()
    p = Program()
    if len(circ.q_regs) != 1:
        raise NotImplementedError(
            "Cannot convert circuit with multiple quantum registers to PyQuil")
    cregmap = {}
    for _, reg in circ.c_regs.items():
        if reg.size() == 0:
            continue
        name = reg.name
        if name == 'c':
            name = 'ro'
        quil_reg = p.declare(name, 'BIT', reg.size())
        cregmap.update({reg: quil_reg})
    if active_reset:
        p.reset()
    for command in circ:
        op = command.op
        qubits = [Qubit(qb.index) for qb in command.qubits]
        optype = op.get_type()
        if optype == OpType.Measure:
            bits = [cregmap[b.reg][b.index] for b in command.bits]
            p += Measurement(*qubits, *bits)
            continue
        try:
            gatetype = _known_quil_gate_rev[optype]
        except KeyError as error:
            raise NotImplementedError(
                "Cannot convert tket Op to pyquil gate: " +
                op.get_name()) from error
        if len(command.controls) != 0:
            raise NotImplementedError(
                "Cannot convert conditional gates from tket to PyQuil")
        params = [float((p * pi).evalf()) for p in op.get_params()]
        g = Gate(gatetype, params, qubits)
        p += g
    return p
Exemple #9
0
def MEASURE(qubit, classical_reg=None):
    """
    Produce a MEASURE instruction.

    :param qubit: The qubit to measure.
    :param classical_reg: The classical register to measure into, or None.
    :return: A Measurement instance.
    """
    qubit = unpack_qubit(qubit)
    if classical_reg is None:
        address = None
    elif isinstance(classical_reg, int):
        warn("Indexing measurement addresses by integers is deprecated. " +
             "Replacing this with the MemoryReference ro[i] instead.")
        address = MemoryReference("ro", classical_reg)
    else:
        address = unpack_classical_reg(classical_reg)
    return Measurement(qubit, address)
def tk_to_pyquil(
    tkcirc: Circuit,
    active_reset: bool = False,
    return_used_bits: bool = False
) -> Union[Program, Tuple[Program, List[Bit]]]:
    """
       Convert a tket :py:class:`Circuit` to a :py:class:`pyquil.Program` .

    :param tkcirc: A circuit to be converted

    :return: The converted circuit
    """
    p = Program()
    qregs = set()
    for qb in tkcirc.qubits:
        if len(qb.index) != 1:
            raise NotImplementedError(
                "PyQuil registers must use a single index")
        qregs.add(qb.reg_name)
    if len(qregs) > 1:
        raise NotImplementedError(
            "Cannot convert circuit with multiple quantum registers to pyQuil")
    creg_sizes: Dict = {}
    for b in tkcirc.bits:
        if len(b.index) != 1:
            raise NotImplementedError(
                "PyQuil registers must use a single index")
        if (b.reg_name
                not in creg_sizes) or (b.index[0] >= creg_sizes[b.reg_name]):
            creg_sizes.update({b.reg_name: b.index[0] + 1})
    cregmap = {}
    for reg_name, size in creg_sizes.items():
        name = reg_name
        if name == "c":
            name = "ro"
        quil_reg = p.declare(name, "BIT", size)
        cregmap.update({reg_name: quil_reg})
    for sym in tkcirc.free_symbols():
        p.declare(str(sym), "REAL")
    if active_reset:
        p.reset()
    measures = []
    measured_qubits: List[Qubit] = []
    used_bits: List[Bit] = []
    for command in tkcirc:
        op = command.op
        optype = op.type
        if optype == OpType.Measure:
            qb = Qubit_(command.args[0].index[0])
            if qb in measured_qubits:
                raise NotImplementedError("Cannot apply gate on qubit " +
                                          qb.__repr__() + " after measurement")
            bit = command.args[1]
            b = cregmap[bit.reg_name][bit.index[0]]
            measures.append(Measurement(qb, b))
            measured_qubits.append(qb)
            used_bits.append(bit)
            continue
        elif optype == OpType.Barrier:
            continue  # pyQuil cannot handle barriers
        qubits = [Qubit_(qb.index[0]) for qb in command.args]
        for qb in qubits:
            if qb in measured_qubits:
                raise NotImplementedError("Cannot apply gate on qubit " +
                                          qb.__repr__() + " after measurement")
        try:
            gatetype = _known_quil_gate_rev[optype]
        except KeyError as error:
            raise NotImplementedError(
                "Cannot convert tket Op to pyQuil gate: " +
                op.get_name()) from error
        params = [param_to_pyquil(p) for p in op.params]
        g = Gate(gatetype, params, qubits)
        p += g
    for m in measures:
        p += m
    if return_used_bits:
        return p, used_bits
    return p