Пример #1
0
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
Пример #2
0
 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
Пример #3
0
    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
Пример #4
0
    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
Пример #5
0
 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])
Пример #6
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(), )
Пример #7
0
 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
Пример #8
0
    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
Пример #9
0
 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())
Пример #10
0
 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
Пример #11
0
    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
Пример #12
0
    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