def _decompose_CnU(cmd): # pylint: disable=invalid-name """ Decompose a multi-controlled gate U with n control qubits into a single- controlled U. It uses (n-1) work qubits and 2 * (n-1) Toffoli gates for general U and (n-2) work qubits and 2n - 3 Toffoli gates if U is an X-gate. """ eng = cmd.engine qubits = cmd.qubits ctrl_qureg = cmd.control_qubits gate = cmd.gate n_controls = get_control_count(cmd) # specialized for X-gate if gate == XGate() and n_controls > 2: n_controls -= 1 ancilla_qureg = eng.allocate_qureg(n_controls - 1) with Compute(eng): Toffoli | (ctrl_qureg[0], ctrl_qureg[1], ancilla_qureg[0]) for ctrl_index in range(2, n_controls): Toffoli | ( ctrl_qureg[ctrl_index], ancilla_qureg[ctrl_index - 2], ancilla_qureg[ctrl_index - 1], ) ctrls = [ancilla_qureg[-1]] # specialized for X-gate if gate == XGate() and get_control_count(cmd) > 2: ctrls += [ctrl_qureg[-1]] with Control(eng, ctrls): gate | qubits Uncompute(eng)
def _add_single_qubit_op_to_circuit(cmd: ProjectQCommand, circ: Circuit) -> bool: assert len(cmd.qubits) == 1 assert len(cmd.qubits[0]) == 1 qubit_no = cmd.qubits[0][0].id new_qubit = False if get_control_count(cmd) > 0: raise Exception("singleq gate " + str(cmd.gate) + " has " + str(get_control_count(cmd)) + " control qubits") else: if qubit_no >= circ.n_qubits: circ.add_blank_wires(1 + qubit_no - circ.n_qubits) new_qubit = True if type(cmd.gate) == pqo.MeasureGate: bit = Bit("c", qubit_no) if bit not in circ.bits: circ.add_bit(bit) circ.Measure(qubit_no, qubit_no) return new_qubit elif type(cmd.gate) in (pqo.Rx, pqo.Ry, pqo.Rz): op = Op.create(_pq_to_tk_singleqs[type(cmd.gate)], cmd.gate.angle / np.pi) else: op = Op.create(_pq_to_tk_singleqs[type(cmd.gate)]) circ.add_gate(Op=op, args=[qubit_no]) return new_qubit
def _recognize_CnU(cmd): # pylint: disable=invalid-name """Recognize an arbitrary gate which has n>=2 control qubits, except a Toffoli gate.""" if get_control_count(cmd) == 2: if not isinstance(cmd.gate, XGate): return True elif get_control_count(cmd) > 2: return True return False
def _store(self, cmd): if self._clear: self._clear = False self.qasm = "" self._allocated_qubits = set() gate = cmd.gate if gate == ops.Allocate: self._allocated_qubits.add(cmd.qubits[0][0].id) return if gate == ops.Deallocate: return if gate == ops.Measure: assert len(cmd.qubits) == 1 and len(cmd.qubits[0]) == 1 qb_id = cmd.qubits[0][0].id logical_id = None for t in cmd.tags: if isinstance(t, LogicalQubitIDTag): logical_id = t.logical_qubit_id break assert logical_id is not None self._measured_ids += [logical_id] elif gate == ops.NOT and get_control_count(cmd) == 1: ctrl_pos = cmd.control_qubits[0].id qb_pos = cmd.qubits[0][0].id self.qasm += "\ncx q[{}], q[{}];".format(ctrl_pos, qb_pos) elif gate == ops.Barrier: qb_pos = [qb.id for qr in cmd.qubits for qb in qr] self.qasm += "\nbarrier " qb_str = "" for pos in qb_pos: qb_str += "q[{}], ".format(pos) self.qasm += qb_str[:-2] + ";" elif isinstance(gate, (ops.Rx, ops.Ry, ops.Rz)): assert get_control_count(cmd) == 0 qb_pos = cmd.qubits[0][0].id u_strs = { 'Rx': 'u3({}, -pi/2, pi/2)', 'Ry': 'u3({}, 0, 0)', 'Rz': 'u1({})' } gate = u_strs[str(gate)[0:2]].format(gate.angle) self.qasm += "\n{} q[{}];".format(gate, qb_pos) else: assert get_control_count(cmd) == 0 if str(gate) in self._gate_names: gate_str = self._gate_names[str(gate)] else: gate_str = str(gate).lower() qb_pos = cmd.qubits[0][0].id self.qasm += "\n{} q[{}];".format(gate_str, qb_pos)
def is_available(self, cmd): g = cmd.gate if g == ops.NOT and get_control_count(cmd) <= 1: return True if get_control_count(cmd) == 0: if g in (ops.T, ops.Tdag, ops.S, ops.Sdag, ops.H, ops.Y, ops.Z): return True if isinstance(g, (ops.Rx, ops.Ry, ops.Rz)): return True if g in (ops.Measure, ops.Allocate, ops.Deallocate, ops.Barrier): return True return False
def is_available(self, cmd: Command) -> bool: """ Via this method the ProjectQ framework determines which commands (gates) are available in the backend. Args: cmd: Command with a gate for which to check availability. Returns: True when the gate in the command is available on the Quantum Inspire backend. """ count = get_control_count(cmd) g = cmd.gate if self._verbose >= 3: print('call to is_available with cmd %s (gate %s)' % (cmd, g)) if g == NOT and count <= 2: return True if g == Z and count <= 1: return True if g in (Measure, Allocate, Deallocate, Barrier): return True if count != 0: return False if g in (T, Tdag, S, Sdag, Swap, H, X, Y, Z): return True elif isinstance(g, (Rx, Ry, Rz)): return True elif isinstance(g, Ph): return False else: return False
def is_available(self, cmd: Command) -> bool: """ Return true if the command can be executed. Args: cmd: Command for which to check availability. """ count = get_control_count(cmd) g = cmd.gate if self._verbose: print('call to is_available with cmd %s (gate %s)' % (cmd, g)) if g == NOT and count <= 2: return True if g == Z and count <= 1: return True if g in (Measure, Allocate, Deallocate, Barrier): return True if count != 0: return False if g in (T, Tdag, S, Sdag, H, X, Y, Z): return True elif isinstance(g, (Rx, Ry, Rz)): return True elif isinstance(g, Ph): return False else: return False
def _recognize_CnU(cmd): """ Recognize an arbitrary gate which has n>=2 control qubits, except a Toffoli gate. """ if get_control_count(cmd) == 2: if not (isinstance(cmd.gate, XGate) and isinstance(cmd.gate, YGate) and isinstance(cmd.gate, ZGate) ): return True if not isinstance(cmd.gate, XGate): return True elif get_control_count(cmd) > 2: return True return False
def _rx_ry_rz(cmd, mapping, qubits): """ Translate a rotation gate into a Cirq roation (phase) gate. Global phase difference betwee proejctq rotation gate and cirq phase gate is dropped. Args: cmd (:class:`projectq.ops.Command`): a projectq command instance mapping (:class:`dict`): a dictionary of qubit mappings qubits (list of :class:cirq.QubitID`): cirq qubits Returns: :class:`cirq.Operation` """ gates = {pqo.Rx: cop.XPowGate, pqo.Ry: cop.YPowGate, pqo.Rz: cop.ZPowGate} qb_pos = [mapping[qb.id] for qr in cmd.qubits for qb in qr] assert len(qb_pos) == 1 cirqGate = gates[type(cmd.gate)](half_turns=cmd.gate.angle / cmath.pi) if get_control_count(cmd) > 0: ctrl_pos = [mapping[qb.id] for qb in cmd.control_qubits] return cop.ControlledGate(cirqGate)( *[qubits[c] for c in ctrl_pos + qb_pos]) else: return cirqGate(*[qubits[idx] for idx in qb_pos])
def _recognize_paulis(cmd): if isinstance( cmd.gate, (ops.XGate, ops.YGate, ops.ZGate)) and get_control_count(cmd) == 0: return True else: return False
def is_available(self, cmd): """ Test if this backend is available to process the provided command. Args: cmd (Command): A command to process. Returns: bool: If this backend can process the command. """ gate = cmd.gate # Metagates. if gate in (Measure, Allocate, Deallocate, Barrier): return True if has_negative_control(cmd): return False # CNOT gates. # NOTE: IonQ supports up to 7 control qubits num_ctrl_qubits = get_control_count(cmd) if 0 < num_ctrl_qubits <= 7: return isinstance(gate, (XGate, )) # Gates witout control bits. if num_ctrl_qubits == 0: supported = isinstance(gate, SUPPORTED_GATES) supported_transpose = gate in (Sdag, Tdag) return supported or supported_transpose return False
def filter_gates(eng, cmd): if isinstance(cmd.gate, ClassicalInstructionGate): return True if ((cmd.gate == X and get_control_count(cmd) == 1) or cmd.gate == H or isinstance(cmd.gate, Rz)): return False return True
def _hiq_add_cmd(resource_counter, cmd): """ Add a gate to the count. """ if isinstance(cmd.gate, AllocateQuregGate): for qureg in cmd.qubits: for qubit in qureg: resource_counter._active_qubits += 1 resource_counter._depth_of_qubit[qubit.id] = 0 # this is original ProjectQ's code copied here from _add_cmd() resource_counter.max_width = max(resource_counter.max_width, resource_counter._active_qubits) ctrl_cnt = get_control_count(cmd) gate_description = (cmd.gate, ctrl_cnt) gate_class_description = (cmd.gate.__class__, ctrl_cnt) try: resource_counter.gate_counts[gate_description] += 1 except KeyError: resource_counter.gate_counts[gate_description] = 1 try: resource_counter.gate_class_counts[gate_class_description] += 1 except KeyError: resource_counter.gate_class_counts[gate_class_description] = 1 else: resource_counter._old_add_cmd(cmd)
def _add_cmd(self, cmd): """ Add a gate to the count. """ if cmd.gate == Allocate: self._active_qubits += 1 elif cmd.gate == Deallocate: self._active_qubits -= 1 elif cmd.gate == Measure: for qureg in cmd.qubits: for qubit in qureg: self.main_engine.set_measurement_result(qubit, 0) self.max_width = max(self.max_width, self._active_qubits) ctrl_cnt = get_control_count(cmd) gate_description = (cmd.gate, ctrl_cnt) gate_class_description = (cmd.gate.__class__, ctrl_cnt) try: self.gate_counts[gate_description] += 1 except KeyError: self.gate_counts[gate_description] = 1 try: self.gate_class_counts[gate_class_description] += 1 except KeyError: self.gate_class_counts[gate_class_description] = 1
def _print_cmd(self, cmd): """ Print a command or, if the command is a measurement instruction and the CommandPrinter is the last engine in the engine pipeline: Query the user for the measurement result (if accept_input = True) / Set the result to 0 (if it's False). Args: cmd (Command): Command to print. """ if self.is_last_engine and cmd.gate == Measure: assert (get_control_count(cmd) == 0) print(cmd) for qureg in cmd.qubits: for qubit in qureg: if self._accept_input: m = None while m != '0' and m != '1' and m != 1 and m != 0: prompt = ("Input measurement result (0 or 1) for" " qubit " + str(qubit) + ": ") m = input(prompt) else: m = self._default_measure m = int(m) self.main_engine.set_measurement_result(qubit, m) else: if self._in_place: sys.stdout.write("\0\r\t\x1b[K" + str(cmd) + "\r") else: print(cmd)
def _add_single_qubit_op_to_circuit(cmd:ProjectQCommand,circ:Circuit): assert len(cmd.qubits)==1 assert len(cmd.qubits[0])==1 qubit_no = cmd.qubits[0][0].id new_qubit = False if get_control_count(cmd) > 0: raise Exception("singleq gate " + str(cmd.gate) + " has " + str(get_control_count(cmd)) + " control qubits") else: if type(cmd.gate) in (pqo.Rx,pqo.Ry,pqo.Rz): op = circ._get_op(OpType=_pq_to_tk_singleqs[type(cmd.gate)],param=cmd.gate.angle/np.pi) else: op = circ._get_op(OpType=_pq_to_tk_singleqs[type(cmd.gate)]) if (qubit_no >= circ.n_qubits): circ.add_blank_wires(1+qubit_no-circ.n_qubits) new_qubit = True circ._add_operation(Op=op,qubits=[qubit_no]) return new_qubit
def _is_swap(self, cmd): # pylint: disable=no-self-use """ Check if the command corresponds to a Swap gate. Args: cmd (Command): Command to check """ return get_control_count(cmd) == 0 and cmd.gate == Swap
def _is_swap(self, cmd): """ Check if the command corresponds to a Swap gate. Args: cmd (Command): Command to check """ return (get_control_count(cmd) == 0 and cmd.gate == Swap)
def _is_cnot(self, cmd): # pylint: disable=no-self-use """ Check if the command corresponds to a CNOT (controlled NOT gate). Args: cmd (Command): Command to check """ return isinstance(cmd.gate, NOT.__class__) and get_control_count(cmd) == 1
def _is_cnot(self, cmd): """ Check if the command corresponds to a CNOT (controlled NOT gate). Args: cmd (Command): Command to check whether it is a controlled NOT gate. """ return isinstance(cmd.gate, NOT.__class__) and get_control_count(cmd) == 1
def _handle(self, cmd): """ Handle all commands, i.e., call the member functions of the C++- simulator object corresponding to measurement, allocation/ deallocation, and (controlled) single-qubit gate. Args: cmd (Command): Command to handle. Raises: Exception: If a non-single-qubit gate needs to be processed (which should never happen due to is_available). """ #print(cmd) if cmd.gate == Measure: assert (get_control_count(cmd) == 0) ids = [qb.id for qr in cmd.qubits for qb in qr] out = self._simulator.measure_qubits(ids) i = 0 for qr in cmd.qubits: for qb in qr: self.main_engine.set_measurement_result(qb, out[i]) i += 1 elif cmd.gate == Allocate: ID = cmd.qubits[0][0].id self._simulator.allocate_qubit(ID) elif cmd.gate == Deallocate: ID = cmd.qubits[0][0].id self._simulator.deallocate_qubit(ID) elif isinstance(cmd.gate, BasicMathGate): qubitids = [] for qr in cmd.qubits: qubitids.append([]) for qb in qr: qubitids[-1].append(qb.id) math_fun = cmd.gate.get_math_function(cmd.qubits) self._simulator.emulate_math(math_fun, qubitids, [qb.id for qb in cmd.control_qubits]) elif isinstance(cmd.gate, TimeEvolution): op = [(list(term), coeff) for (term, coeff) in cmd.gate.hamiltonian.terms.items()] t = cmd.gate.time qubitids = [qb.id for qb in cmd.qubits[0]] ctrlids = [qb.id for qb in cmd.control_qubits] self._simulator.emulate_time_evolution(op, t, qubitids, ctrlids) elif len(cmd.gate.matrix) == 2: matrix = cmd.gate.matrix self._simulator.apply_controlled_gate( matrix.tolist(), [cmd.qubits[0][0].id], [qb.id for qb in cmd.control_qubits]) if not self._gate_fusion: self._simulator.run() else: raise Exception("This simulator only supports controlled single-" "qubit gates!\nPlease add an auto-replacer engine" " to your list of compiler engines.")
def is_available(self, cmd): """ Return true if the command can be executed. The IBM quantum chip can do X, Y, Z, T, Tdag, S, Sdag, and CX / CNOT. Args: cmd (Command): Command for which to check availability """ g = cmd.gate if g == NOT and get_control_count(cmd) <= 1: return True if get_control_count(cmd) == 0: if (g == T or g == Tdag or g == S or g == Sdag or g == H or g == Y or g == Z or g == I): return True if g == Measure or g == Allocate or g == Deallocate: return True return False
def _recognize_carb1qubit(cmd): """ Recognize single controlled one qubit gates with a matrix.""" if get_control_count(cmd) == 1: try: m = cmd.gate.matrix if len(m) == 2: return True except: return False return False
def _decompose_CRz(cmd): # pylint: disable=invalid-name """Decompose the controlled Rz gate (into CNOT and Rz).""" qubit = cmd.qubits[0] ctrl = cmd.control_qubits gate = cmd.gate n_controls = get_control_count(cmd) Rz(0.5 * gate.angle) | qubit C(NOT, n_controls) | (ctrl, qubit) Rz(-0.5 * gate.angle) | qubit C(NOT, n_controls) | (ctrl, qubit)
def _add_cmd(self, cmd): """ Add a gate to the count. """ if cmd.gate == Allocate: self._active_qubits += 1 self._depth_of_qubit[cmd.qubits[0][0].id] = 0 elif cmd.gate == Deallocate: self._active_qubits -= 1 depth = self._depth_of_qubit[cmd.qubits[0][0].id] self._previous_max_depth = max(self._previous_max_depth, depth) self._depth_of_qubit.pop(cmd.qubits[0][0].id) elif self.is_last_engine and cmd.gate == Measure: for qureg in cmd.qubits: for qubit in qureg: self._depth_of_qubit[qubit.id] += 1 # Check if a mapper assigned a different logical id logical_id_tag = None for tag in cmd.tags: if isinstance(tag, LogicalQubitIDTag): logical_id_tag = tag if logical_id_tag is not None: qubit = WeakQubitRef(qubit.engine, logical_id_tag.logical_qubit_id) self.main_engine.set_measurement_result(qubit, 0) else: qubit_ids = set() for qureg in cmd.all_qubits: for qubit in qureg: qubit_ids.add(qubit.id) if len(qubit_ids) == 1: self._depth_of_qubit[list(qubit_ids)[0]] += 1 else: max_depth = 0 for qubit_id in qubit_ids: max_depth = max(max_depth, self._depth_of_qubit[qubit_id]) for qubit_id in qubit_ids: self._depth_of_qubit[qubit_id] = max_depth + 1 self.max_width = max(self.max_width, self._active_qubits) ctrl_cnt = get_control_count(cmd) gate_description = (cmd.gate, ctrl_cnt) gate_class_description = (cmd.gate.__class__, ctrl_cnt) try: self.gate_counts[gate_description] += 1 except KeyError: self.gate_counts[gate_description] = 1 try: self.gate_class_counts[gate_class_description] += 1 except KeyError: self.gate_class_counts[gate_class_description] = 1
def _decompose_CRz(cmd): """ Decompose the controlled Rz gate (into CNOT and Rz). """ qubit = cmd.qubits[0] ctrl = cmd.control_qubits gate = cmd.gate n = get_control_count(cmd) Rz(0.5 * gate._angle) | qubit C(NOT, n) | (ctrl, qubit) Rz(-0.5 * gate._angle) | qubit C(NOT, n) | (ctrl, qubit)
def _recognize_arb1qubit(cmd): """ Recognize an arbitrary one qubit gate which has a matrix property. It does not allow gates which have control qubits as otherwise the AutoReplacer might go into an infinite loop. Use carb1qubit2cnotrzandry instead. """ try: return len(cmd.gate.matrix) == 2 and get_control_count(cmd) == 0 except AttributeError: return False
def is_available(self, cmd): """ Return true if the command can be executed. For supporting gate of QuTiP, pleaser refer to http://qutip.org/docs/latest/guide/guide-qip.html. Args: cmd (Command): Command for which to check availability """ g = cmd.gate if g == NOT and get_control_count(cmd) <= 1: return True if get_control_count(cmd) == 0: if g in (H, X, Y, Z): return True if isinstance(g, (Rx, Ry, Rz)): return True if g in (Measure, Allocate, Deallocate, Barrier): return True return False
def is_available(self, cmd): """ Return true if the command can be executed. The IBM quantum chip can do X, Y, Z, T, Tdag, S, Sdag, rotation gates, barriers, and CX / CNOT. Args: cmd (Command): Command for which to check availability """ g = cmd.gate if g == NOT and get_control_count(cmd) <= 1: return True if get_control_count(cmd) == 0: if g in (T, Tdag, S, Sdag, H, Y, Z): return True if isinstance(g, (Rx, Ry, Rz)): return True if g in (Measure, Allocate, Deallocate, Barrier): return True return False
def _store(self, cmd): """ Temporarily store the command cmd. Translates the command and stores it in a local variable (self._cmds). Args: cmd: Command to store """ if self._clear: self._mapping = dict() self._inverse_mapping = dict() self._probabilities = dict() self._clear = False self.qasm = "" gate = cmd.gate if gate == Allocate: qb_id = cmd.qubits[0][0].id for tag in cmd.tags: if isinstance(tag, QubitPlacementTag): self._mapping[qb_id] = tag.position self._inverse_mapping[tag.position] = qb_id break if not qb_id in self._mapping: raise Exception("No qubit placement info found in Allocate.\n" "Please make sure you are using the IBM CNOT " "Mapper.") return if gate == Deallocate: return if gate == Measure: for qr in cmd.qubits: for qb in qr: qb_pos = self._mapping[qb.id] self.qasm += "\nmeasure q[{}] -> c[{}];".format(qb_pos, qb_pos) elif not (gate == NOT and get_control_count(cmd) == 1): if str(gate) in self._gate_names: gate_str = self._gate_names[str(gate)] else: gate_str = str(gate).lower() qb_pos = self._mapping[cmd.qubits[0][0].id] self.qasm += "\n{} q[{}];".format(gate_str, qb_pos) else: ctrl_pos = self._mapping[cmd.control_qubits[0].id] qb_pos = self._mapping[cmd.qubits[0][0].id] self.qasm += "\ncx q[{}], q[{}];".format(ctrl_pos, qb_pos)