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
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
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))
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)
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
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)
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
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