コード例 #1
0
    def test_to_permutation(self):
        """Test that converting linear functions to permutations works correctly."""

        # Original circuit with two linear blocks; the second block happens to be
        # a permutation
        circuit1 = QuantumCircuit(4)
        circuit1.cx(0, 1)
        circuit1.cx(0, 2)
        circuit1.cx(0, 3)
        circuit1.h(3)
        circuit1.swap(2, 3)
        circuit1.cx(1, 2)
        circuit1.cx(2, 1)
        circuit1.cx(1, 2)

        # new circuit with linear functions extracted
        circuit2 = PassManager(CollectLinearFunctions()).run(circuit1)

        # check that we have two blocks of linear functions
        self.assertEqual(circuit2.count_ops()["linear_function"], 2)

        # new circuit with linear functions converted to permutations
        # (the first linear function should not be converted, the second should)
        circuit3 = PassManager(LinearFunctionsToPermutations()).run(circuit2)

        # check that there is one linear function and one permutation
        self.assertEqual(circuit3.count_ops()["linear_function"], 1)
        self.assertEqual(circuit3.count_ops()["permutation_[2,0,1]"], 1)

        # check that the final circuit is still equivalent to the original circuit
        self.assertEqual(Operator(circuit1), Operator(circuit3))
コード例 #2
0
    def test_real_amplitudes_circuit_5q(self):
        """Test that for the 5-qubit real amplitudes circuit
        extracting linear functions produces the expected number of linear blocks,
        and synthesizing these blocks produces an expected number of CNOTs.
        """
        ansatz = RealAmplitudes(5, reps=2)
        circuit1 = ansatz.decompose()

        # collect linear functions
        circuit2 = PassManager(CollectLinearFunctions()).run(circuit1)
        self.assertEqual(circuit2.count_ops()["linear_function"], 2)

        # synthesize linear functions
        circuit3 = PassManager(LinearFunctionsSynthesis()).run(circuit2)
        self.assertEqual(circuit3.count_ops()["cx"], 8)
コード例 #3
0
    def test_disconnected_gates2(self):
        """Test that extraction of linear functions does not create
        linear functions out of disconnected gates.
        """
        circuit1 = QuantumCircuit(4)
        circuit1.cx(0, 1)
        circuit1.cx(1, 0)
        circuit1.cx(2, 3)

        # collect linear functions
        circuit2 = PassManager(CollectLinearFunctions()).run(circuit1)

        # we expect that the first two CX gates will be combined into
        # a linear function, but the last will not
        self.assertEqual(circuit2.count_ops()["linear_function"], 1)
        self.assertEqual(circuit2.count_ops()["cx"], 1)
コード例 #4
0
    def test_optimize_cliffords(self):
        """Test OptimizeCliffords pass."""

        rng = np.random.default_rng(1234)
        for _ in range(20):
            # Create several random Cliffords
            cliffs = [random_clifford(3, rng) for _ in range(5)]

            # The first circuit contains these cliffords
            qc1 = QuantumCircuit(5)
            for cliff in cliffs:
                qc1.append(cliff, [4, 0, 2])
            self.assertEqual(qc1.count_ops()["clifford"], 5)

            # The second circuit is obtained by running the OptimizeCliffords pass.
            qc2 = PassManager(OptimizeCliffords()).run(qc1)
            self.assertEqual(qc2.count_ops()["clifford"], 1)

            # The third circuit contains the decompositions of Cliffods.
            qc3 = QuantumCircuit(5)
            for cliff in cliffs:
                qc3.append(cliff.to_circuit(), [4, 0, 2])
            self.assertNotIn("clifford", qc3.count_ops())

            # Check that qc1, qc2 and qc3 and their decompositions are all equivalent.
            self.assertTrue(Operator(qc1).equiv(Operator(qc1.decompose())))
            self.assertTrue(Operator(qc2).equiv(Operator(qc2.decompose())))
            self.assertTrue(Operator(qc3).equiv(Operator(qc3.decompose())))
            self.assertTrue(Operator(qc1).equiv(Operator(qc2)))
            self.assertTrue(Operator(qc1).equiv(Operator(qc3)))
コード例 #5
0
    def test_can_combine_cliffords(self):
        """Test that we can combine a pair of Cliffords over the same qubits
        using OptimizeCliffords transpiler pass."""

        cliff1 = self.create_cliff1()
        cliff2 = self.create_cliff2()
        cliff3 = self.create_cliff3()

        # Create a circuit with two consective cliffords
        qc1 = QuantumCircuit(4)
        qc1.append(cliff1, [3, 1, 2])
        qc1.append(cliff2, [3, 1, 2])
        self.assertEqual(qc1.count_ops()["clifford"], 2)

        # Run OptimizeCliffords pass, and check that only one Clifford remains
        qc1opt = PassManager(OptimizeCliffords()).run(qc1)
        self.assertEqual(qc1opt.count_ops()["clifford"], 1)

        # Create the expected circuit
        qc2 = QuantumCircuit(4)
        qc2.append(cliff3, [3, 1, 2])

        # Check that all possible operators are equal
        self.assertTrue(Operator(qc1).equiv(Operator(qc1.decompose())))
        self.assertTrue(Operator(qc1opt).equiv(Operator(qc1opt.decompose())))
        self.assertTrue(Operator(qc1).equiv(Operator(qc1opt)))
        self.assertTrue(Operator(qc2).equiv(Operator(qc2.decompose())))
        self.assertTrue(Operator(qc1opt).equiv(Operator(qc2)))
コード例 #6
0
    def test_connected_gates(self):
        """Test that extraction of linear functions combines gates
        which become connected later.
        """
        circuit1 = QuantumCircuit(4)
        circuit1.cx(0, 1)
        circuit1.cx(1, 0)
        circuit1.cx(2, 3)
        circuit1.swap(0, 3)

        # collect linear functions
        circuit2 = PassManager(CollectLinearFunctions()).run(circuit1)

        # we expect that the first two CX gates will be combined into
        # a linear function, but the last will not
        self.assertEqual(circuit2.count_ops()["linear_function"], 1)
        self.assertNotIn("cx", circuit2.count_ops().keys())
        self.assertNotIn("swap", circuit2.count_ops().keys())
コード例 #7
0
    def test_two_linear_blocks(self):
        """Test that when we have two blocks of linear gates with one nonlinear gate in the middle,
        we end up with two LinearFunctions."""
        # Create a circuit with a nonlinear gate (h) cleanly separating it into two linear blocks.
        circuit1 = QuantumCircuit(4)
        circuit1.cx(0, 1)
        circuit1.cx(0, 2)
        circuit1.cx(0, 3)
        circuit1.h(3)
        circuit1.swap(2, 3)
        circuit1.cx(1, 2)
        circuit1.cx(0, 1)

        # new circuit with linear functions extracted using transpiler pass
        circuit2 = PassManager(CollectLinearFunctions()).run(circuit1)

        # We expect to see 3 gates (linear, h, linear)
        self.assertEqual(len(circuit2.data), 3)
        inst1, qargs1, cargs1 = circuit2.data[0]
        inst2, qargs2, cargs2 = circuit2.data[2]
        self.assertIsInstance(inst1, LinearFunction)
        self.assertIsInstance(inst2, LinearFunction)

        # Check that the first linear function represents the subcircuit before h
        resulting_subcircuit1 = QuantumCircuit(4)
        resulting_subcircuit1.append(inst1, qargs1, cargs1)

        expected_subcircuit1 = QuantumCircuit(4)
        expected_subcircuit1.cx(0, 1)
        expected_subcircuit1.cx(0, 2)
        expected_subcircuit1.cx(0, 3)
        self.assertEqual(Operator(resulting_subcircuit1),
                         Operator(expected_subcircuit1))

        # Check that the second linear function represents the subcircuit after h
        resulting_subcircuit2 = QuantumCircuit(4)
        resulting_subcircuit2.append(inst2, qargs2, cargs2)

        expected_subcircuit2 = QuantumCircuit(4)
        expected_subcircuit2.swap(2, 3)
        expected_subcircuit2.cx(1, 2)
        expected_subcircuit2.cx(0, 1)
        self.assertEqual(Operator(resulting_subcircuit2),
                         Operator(expected_subcircuit2))

        # now a circuit with linear functions synthesized
        synthesized_circuit = PassManager(
            LinearFunctionsSynthesis()).run(circuit2)

        # check that there are no LinearFunctions present in synthesized_circuit
        self.assertNotIn("linear_function",
                         synthesized_circuit.count_ops().keys())

        # check that we have an equivalent circuit
        self.assertEqual(Operator(circuit2), Operator(synthesized_circuit))
コード例 #8
0
    def test_single_linear_block(self):
        """Test that when all gates in a circuit are either CX or SWAP,
        we end up with a single LinearFunction."""

        # original circuit
        circuit = QuantumCircuit(4)
        circuit.cx(0, 1)
        circuit.cx(0, 2)
        circuit.cx(0, 3)
        circuit.swap(2, 3)
        circuit.cx(0, 1)
        circuit.cx(0, 3)

        # new circuit with linear functions extracted using transpiler pass
        optimized_circuit = PassManager(CollectLinearFunctions()).run(circuit)

        # check that this circuit consists of a single LinearFunction
        self.assertIn("linear_function", optimized_circuit.count_ops().keys())
        self.assertEqual(len(optimized_circuit.data), 1)
        inst1, _, _ = optimized_circuit.data[0]
        self.assertIsInstance(inst1, LinearFunction)

        # construct a circuit with linear function directly, without the transpiler pass
        expected_circuit = QuantumCircuit(4)
        expected_circuit.append(LinearFunction(circuit), [0, 1, 2, 3])

        # check that we have an equivalent circuit
        self.assertEqual(Operator(optimized_circuit),
                         Operator(expected_circuit))

        # now a circuit with linear functions synthesized
        synthesized_circuit = PassManager(
            LinearFunctionsSynthesis()).run(optimized_circuit)

        # check that there are no LinearFunctions present in synthesized_circuit
        self.assertNotIn("linear_function",
                         synthesized_circuit.count_ops().keys())

        # check that we have an equivalent circuit
        self.assertEqual(Operator(optimized_circuit),
                         Operator(synthesized_circuit))
コード例 #9
0
    def test_disconnected_gates1(self):
        """Test that extraction of linear functions does not create
        linear functions out of disconnected gates.
        """
        circuit1 = QuantumCircuit(4)
        circuit1.cx(0, 1)
        circuit1.cx(2, 3)

        # collect linear functions
        circuit2 = PassManager(CollectLinearFunctions()).run(circuit1)

        # check that there are no LinearFunctions present in synthesized_circuit
        self.assertNotIn("linear_function", circuit2.count_ops().keys())
コード例 #10
0
    def test_accept_dagdependency(self):
        """
        Check that users can supply DAGDependency in the template list.
        """
        circuit_in = QuantumCircuit(2)
        circuit_in.cnot(0, 1)
        circuit_in.cnot(0, 1)

        templates = [circuit_to_dagdependency(circuit_in)]

        pass_ = TemplateOptimization(template_list=templates)
        circuit_out = PassManager(pass_).run(circuit_in)

        self.assertEqual(circuit_out.count_ops().get('cx', 0), 0)
コード例 #11
0
    def test_topological_ordering(self):
        """Test that Clifford optimization pass optimizes Cliffords across a gate
        on a different qubit."""

        cliff1 = self.create_cliff1()
        cliff2 = self.create_cliff1()

        qc1 = QuantumCircuit(5)
        qc1.append(cliff1, [0, 1, 2])
        qc1.h(4)
        qc1.append(cliff2, [0, 1, 2])

        # The second circuit is obtained by running the OptimizeCliffords pass.
        qc2 = PassManager(OptimizeCliffords()).run(qc1)
        self.assertEqual(qc2.count_ops()["clifford"], 1)
コード例 #12
0
    def test_not_collecting_single_gates2(self):
        """Test that extraction of linear functions does not create
        linear functions out of single gates.
        """
        circuit1 = QuantumCircuit(3)
        circuit1.h(0)
        circuit1.h(1)
        circuit1.swap(0, 1)
        circuit1.s(1)
        circuit1.swap(1, 2)
        circuit1.h(2)

        # collect linear functions
        circuit2 = PassManager(CollectLinearFunctions()).run(circuit1)

        # check that there are no LinearFunctions present in synthesized_circuit
        self.assertNotIn("linear_function", circuit2.count_ops().keys())
コード例 #13
0
    def test_unbound_parameters(self):
        """
        Test that partial matches with parameters will not raise errors.
        This tests that if parameters are still in the temporary template after
        _attempt_bind then they will not be used.
        """

        class PhaseSwap(Gate):
            """CZ gates used for the test."""

            def __init__(self, num_qubits, params):
                super().__init__("p", num_qubits, params)

            def inverse(self):
                inverse = UnitaryGate(
                    np.diag(
                        [1.0, 1.0, np.exp(-1.0j * self.params[0]), np.exp(-1.0j * self.params[0])]
                    )
                )
                inverse.name = "p"
                return inverse

        def template():
            beta = Parameter("β")
            qc = QuantumCircuit(2)
            qc.cx(1, 0)
            qc.cx(1, 0)
            qc.p(beta, 1)
            qc.append(PhaseSwap(2, [beta]), [0, 1])

            return qc

        circuit_in = QuantumCircuit(2)
        circuit_in.cx(1, 0)
        circuit_in.cx(1, 0)

        pass_ = TemplateOptimization(template_list=[template()])
        circuit_out = PassManager(pass_).run(circuit_in)

        # This template will not fully match as long as gates with parameters do not
        # commute with any other gates in the DAG dependency.
        self.assertEqual(circuit_out.count_ops().get("cx", 0), 2)