def cnot_rxx_decompose(plus_ry=True, plus_rxx=True): """Decomposition of CNOT gate. NOTE: this differs to CNOT by a global phase. The matrix returned is given by exp(1j * pi/4) * CNOT Args: plus_ry (bool): positive initial RY rotation plus_rxx (bool): positive RXX rotation. Returns: QuantumCircuit: The decomposed circuit for CNOT gate (up to global phase). """ # Convert boolean args to +/- 1 signs if plus_ry: sgn_ry = 1 else: sgn_ry = -1 if plus_rxx: sgn_rxx = 1 else: sgn_rxx = -1 circuit = QuantumCircuit(2, global_phase=-sgn_ry * sgn_rxx * np.pi / 4) circuit.append(RYGate(sgn_ry * np.pi / 2), [0]) circuit.append(RXXGate(sgn_rxx * np.pi / 2), [0, 1]) circuit.append(RXGate(-sgn_rxx * np.pi / 2), [0]) circuit.append(RXGate(-sgn_rxx * sgn_ry * np.pi / 2), [1]) circuit.append(RYGate(-sgn_ry * np.pi / 2), [0]) return circuit
def _get_rule(self, node): q = QuantumRegister(node.op.num_qubits, "q") if node.name == "u1": rule = [(RZGate(node.op.params[0]), [q[0]], [])] elif node.name == "u2": rule = [ (RZGate(node.op.params[1]), [q[0]], []), (SYGate(), [q[0]], []), (RZGate(node.op.params[0]), [q[0]], []), ] elif node.name == "u3": rule = [ (RZGate(node.op.params[2]), [q[0]], []), (RYGate(node.op.params[0]), [q[0]], []), (RZGate(node.op.params[1]), [q[0]], []), ] elif node.name == "cx": # // controlled-NOT as per Maslov (2017); this implementation takes s = v = +1 # gate cx a,b # { # ry(pi/2) a; # ms(pi/2, 0) a,b; # rx(-pi/2) a; # rx(-pi/2) b; # ry(-pi/2) a; # } rule = [ (SYGate(), [q[0]], []), (MSGate(pi / 2, 0), [q[0], q[1]], []), (RXGate(-pi / 2), [q[0]], []), (RXGate(-pi / 2), [q[1]], []), (RYGate(-pi / 2), [q[0]], []), ] elif node.name == "rx": if node.op.params[0] == pi: rule = [(XGate(), [q[0]], [])] elif node.op.params[0] == pi / 2: rule = [(SXGate(), [q[0]], [])] else: rule = [(RGate(0, node.op.params[0]), [q[0]], [])] elif node.name == "h": rule = [ (ZGate(), [q[0]], []), (SYGate(), [q[0]], []), ] elif node.name == "ry": if node.op.params[0] == pi: rule = [(YGate(), [q[0]], [])] elif node.op.params[0] == pi / 2: rule = [(SYGate(), [q[0]], [])] else: rule = [(RGate(pi / 2, node.op.params[0]), [q[0]], [])] else: rule = node.op.definition return rule
def _define(self): """ Gate H to Rx(pi/2)·Rz(pi/2) """ definition = [] q = QuantumRegister(1, 'q') rule = [(RXGate(-pi / 2), [q[0]], []), (RZGate(-pi / 2), [q[0]], []), (RXGate(-pi / 2), [q[0]], [])] for inst in rule: definition.append(inst) self.definition = definition
def _define(self): """ Gate Rx(theta) to Rx(theta) """ definition = [] q = QuantumRegister(1, 'q') rule = [(RXGate(self.params[0]), [q[0]], [])] for inst in rule: definition.append(inst) self.definition = definition
def test_get_parameters(self): """Test instantiating gate with variable parameters""" from qiskit.circuit.library.standard_gates.rx import RXGate theta = Parameter('θ') qr = QuantumRegister(1) qc = QuantumCircuit(qr) rxg = RXGate(theta) qc.append(rxg, [qr[0]], []) vparams = qc._parameter_table self.assertEqual(len(vparams), 1) self.assertIs(theta, next(iter(vparams))) self.assertIs(rxg, vparams[theta][0][0])
def decompose_gate(gate): """ decompose gate in the list_gate to composition of Rx, Rz, Cz input: gate (string type) output: quantum gate """ if gate == 'id': return (RXGate(0), ) if gate == 'h': return (RZGate(pi / 2), RXGate(pi / 2), RZGate(pi / 2)) if gate == 'x': return (RXGate(pi), ) if gate == 'y': return (RZGate(pi), RXGate(pi)) if gate == 'z': return (RZGate(pi), ) if gate == 'cx': return RZGate(pi / 2), RXGate(pi / 2), RZGate( pi / 2), CZGate(), RZGate(pi / 2), RXGate(pi / 2), RZGate(pi / 2) if gate == 'cz': return (CZGate(), ) if 'rx' in gate: start = gate.find('(') # find the angle end = gate.find(')') if 'pi' in gate: angle = convert_angle_to_float(gate[start + 1:end]) else: angle = float(gate[start + 1:end]) return (RXGate(angle), ) if 'ry' in gate: start = gate.find('(') # find the angle end = gate.find(')') if 'pi' in gate: angle = convert_angle_to_float(gate[start + 1:end]) else: angle = float(gate[start + 1:end]) return RZGate(-pi / 2), RXGate(angle), RZGate(pi / 2) if 'rz' in gate: start = gate.find('(') # find the angle end = gate.find(')') if 'pi' in gate: angle = convert_angle_to_float(gate[start + 1:end]) else: angle = float(gate[start + 1:end]) return (RZGate(angle), ) if 'measure' in gate: return (Measure(), )
def _define(self): """ gate sx a { rx(pi/2) a; } """ definition = [] q = QuantumRegister(1, "q") rule = [ (RXGate(pi / 2), [q[0]], []), ] for inst in rule: definition.append(inst) self.definition = definition
def _define(self): """ Gate Ry(theta) to Rz(-pi/2)·Rx(theta)·Rz(pi/2) """ definition = [] q = QuantumRegister(1, 'q') if self.params[0] == 0: rule = [(RZGate(0), [q[0]], [])] elif self.params[0] % (2 * pi) == 0: rule = [(RZGate(0), [q[0]], [])] else: rule = [(RZGate(-pi / 2), [q[0]], []), (RXGate(self.params[0]), [q[0]], []), (RZGate(pi / 2), [q[0]], [])] for inst in rule: definition.append(inst) self.definition = definition
def test_is_parameterized(self): """Test checking if a gate is parameterized (bound/unbound)""" from qiskit.circuit.library.standard_gates.h import HGate from qiskit.circuit.library.standard_gates.rx import RXGate theta = Parameter('θ') rxg = RXGate(theta) self.assertTrue(rxg.is_parameterized()) theta_bound = theta.bind({theta: 3.14}) rxg = RXGate(theta_bound) self.assertFalse(rxg.is_parameterized()) h_gate = HGate() self.assertFalse(h_gate.is_parameterized())
def _define(self): """ gate r(theta, phi) a { rz(-theta) a; rx(phi) a; rz(theta) a; } """ definition = [] q = QuantumRegister(1, "q") theta, phi = tuple(self.params) rule = [ (RZGate(-theta), [q[0]], []), (RXGate(phi), [q[0]], []), (RZGate(theta), [q[0]], []), ] for inst in rule: definition.append(inst) self.definition = definition
def run(self, dag): """Run the CommutativeCancellation pass on `dag`. Args: dag (DAGCircuit): the DAG to be optimized. Returns: DAGCircuit: the optimized DAG. Raises: TranspilerError: when the 1-qubit rotation gates are not found """ # Now the gates supported are hard-coded q_gate_list = ['cx', 'cy', 'cz', 'h', 'y'] # Gate sets to be cancelled cancellation_sets = defaultdict(lambda: []) # Traverse each qubit to generate the cancel dictionaries # Cancel dictionaries: # - For 1-qubit gates the key is (gate_type, qubit_id, commutation_set_id), # the value is the list of gates that share the same gate type, qubit, commutation set. # - For 2qbit gates the key: (gate_type, first_qbit, sec_qbit, first commutation_set_id, # sec_commutation_set_id), the value is the list gates that share the same gate type, # qubits and commutation sets. for wire in dag.wires: wire_name = "{0}[{1}]".format(str(wire.register.name), str(wire.index)) wire_commutation_set = self.property_set['commutation_set'][ wire_name] for com_set_idx, com_set in enumerate(wire_commutation_set): if com_set[0].type in ['in', 'out']: continue for node in com_set: num_qargs = len(node.qargs) if num_qargs == 1 and node.name in q_gate_list: cancellation_sets[(node.name, wire_name, com_set_idx)].append(node) if num_qargs == 1 and node.name in [ 'z', 'u1', 'rz', 't', 's' ]: cancellation_sets[('z_rotation', wire_name, com_set_idx)].append(node) if num_qargs == 1 and node.name in ['rx', 'x']: cancellation_sets[('x_rotation', wire_name, com_set_idx)].append(node) # Don't deal with Y rotation, because Y rotation doesn't commute with CNOT, so # it should be dealt with by optimized1qgate pass elif num_qargs == 2 and node.qargs[0] == wire: second_op_name = "{0}[{1}]".format( str(node.qargs[1].register.name), str(node.qargs[1].index)) q2_key = (node.name, wire_name, second_op_name, com_set_idx, self.property_set['commutation_set'][( node, second_op_name)]) cancellation_sets[q2_key].append(node) for cancel_set_key in cancellation_sets: set_len = len(cancellation_sets[cancel_set_key]) if set_len > 1 and cancel_set_key[0] in q_gate_list: gates_to_cancel = cancellation_sets[cancel_set_key] for c_node in gates_to_cancel[:(set_len // 2) * 2]: dag.remove_op_node(c_node) elif set_len > 1 and cancel_set_key[0] in [ 'z_rotation', 'x_rotation' ]: run = cancellation_sets[cancel_set_key] run_qarg = run[0].qargs[0] total_angle = 0.0 # lambda for current_node in run: if (current_node.condition is not None or len(current_node.qargs) != 1 or current_node.qargs[0] != run_qarg): raise TranspilerError("internal error") if current_node.name in ['u1', 'rz', 'rx']: current_angle = float(current_node.op.params[0]) elif current_node.name in ['z', 'x']: current_angle = np.pi elif current_node.name == 't': current_angle = np.pi / 4 elif current_node.name == 's': current_angle = np.pi / 2 # Compose gates total_angle = current_angle + total_angle # Replace the data of the first node in the run if cancel_set_key[0] == 'z_rotation': new_op = U1Gate(total_angle) elif cancel_set_key[0] == 'x_rotation': new_op = RXGate(total_angle) if np.mod(total_angle, (2 * np.pi)) > _CUTOFF_PRECISION: new_qarg = QuantumRegister(1, 'q') new_dag = DAGCircuit() new_dag.add_qreg(new_qarg) new_dag.apply_operation_back(new_op, [new_qarg[0]]) dag.substitute_node_with_dag(run[0], new_dag) # Delete the other nodes in the run for current_node in run[1:]: dag.remove_op_node(current_node) if np.mod(total_angle, (2 * np.pi)) < _CUTOFF_PRECISION: dag.remove_op_node(run[0]) return dag
def run(self, dag): """Run the CommutativeCancellation pass on `dag`. Args: dag (DAGCircuit): the DAG to be optimized. Returns: DAGCircuit: the optimized DAG. Raises: TranspilerError: when the 1-qubit rotation gates are not found """ var_z_gate = None z_var_gates = [ gate for gate in dag.count_ops().keys() if gate in self._var_z_map ] if z_var_gates: # priortize z gates in circuit var_z_gate = self._var_z_map[next(iter(z_var_gates))] else: z_var_gates = [ gate for gate in self.basis if gate in self._var_z_map ] if z_var_gates: var_z_gate = self._var_z_map[next(iter(z_var_gates))] # Now the gates supported are hard-coded q_gate_list = ["cx", "cy", "cz", "h", "y"] # Gate sets to be cancelled cancellation_sets = defaultdict(lambda: []) # Traverse each qubit to generate the cancel dictionaries # Cancel dictionaries: # - For 1-qubit gates the key is (gate_type, qubit_id, commutation_set_id), # the value is the list of gates that share the same gate type, qubit, commutation set. # - For 2qbit gates the key: (gate_type, first_qbit, sec_qbit, first commutation_set_id, # sec_commutation_set_id), the value is the list gates that share the same gate type, # qubits and commutation sets. for wire in dag.wires: wire_commutation_set = self.property_set["commutation_set"][wire] for com_set_idx, com_set in enumerate(wire_commutation_set): if com_set[0].type in ["in", "out"]: continue for node in com_set: num_qargs = len(node.qargs) if num_qargs == 1 and node.name in q_gate_list: cancellation_sets[(node.name, wire, com_set_idx)].append(node) if num_qargs == 1 and node.name in [ "p", "z", "u1", "rz", "t", "s" ]: cancellation_sets[("z_rotation", wire, com_set_idx)].append(node) if num_qargs == 1 and node.name in ["rx", "x"]: cancellation_sets[("x_rotation", wire, com_set_idx)].append(node) # Don't deal with Y rotation, because Y rotation doesn't commute with CNOT, so # it should be dealt with by optimized1qgate pass elif num_qargs == 2 and node.qargs[0] == wire: second_qarg = node.qargs[1] q2_key = ( node.name, wire, second_qarg, com_set_idx, self.property_set["commutation_set"][( node, second_qarg)], ) cancellation_sets[q2_key].append(node) for cancel_set_key in cancellation_sets: if cancel_set_key[0] == "z_rotation" and var_z_gate is None: continue set_len = len(cancellation_sets[cancel_set_key]) if set_len > 1 and cancel_set_key[0] in q_gate_list: gates_to_cancel = cancellation_sets[cancel_set_key] for c_node in gates_to_cancel[:(set_len // 2) * 2]: dag.remove_op_node(c_node) elif set_len > 1 and cancel_set_key[0] in [ "z_rotation", "x_rotation" ]: run = cancellation_sets[cancel_set_key] run_qarg = run[0].qargs[0] total_angle = 0.0 # lambda total_phase = 0.0 for current_node in run: if (current_node.op.condition is not None or len(current_node.qargs) != 1 or current_node.qargs[0] != run_qarg): raise TranspilerError("internal error") if current_node.name in ["p", "u1", "rz", "rx"]: current_angle = float(current_node.op.params[0]) elif current_node.name in ["z", "x"]: current_angle = np.pi elif current_node.name == "t": current_angle = np.pi / 4 elif current_node.name == "s": current_angle = np.pi / 2 # Compose gates total_angle = current_angle + total_angle if current_node.op.definition: total_phase += current_node.op.definition.global_phase # Replace the data of the first node in the run if cancel_set_key[0] == "z_rotation": new_op = var_z_gate(total_angle) elif cancel_set_key[0] == "x_rotation": new_op = RXGate(total_angle) new_op_phase = 0 if np.mod(total_angle, (2 * np.pi)) > _CUTOFF_PRECISION: new_qarg = QuantumRegister(1, "q") new_dag = DAGCircuit() new_dag.add_qreg(new_qarg) new_dag.apply_operation_back(new_op, [new_qarg[0]]) dag.substitute_node_with_dag(run[0], new_dag) if new_op.definition: new_op_phase = new_op.definition.global_phase dag.global_phase = total_phase - new_op_phase # Delete the other nodes in the run for current_node in run[1:]: dag.remove_op_node(current_node) if np.mod(total_angle, (2 * np.pi)) < _CUTOFF_PRECISION: dag.remove_op_node(run[0]) return dag