Esempio n. 1
0
    def test_correctness_3(self) -> None:
        circuit = Circuit(5)
        wide_gate = IdentityGate(3)
        circuit.append_gate(HGate(), [1])
        circuit.append_gate(CNOTGate(), [2, 3])
        circuit.append_gate(wide_gate, [1, 2, 3])
        circuit.append_gate(CNOTGate(), [1, 2])
        circuit.append_gate(HGate(), [3])
        circuit.append_gate(XGate(), [0])
        circuit.append_gate(XGate(), [0])
        circuit.append_gate(XGate(), [0])
        circuit.append_gate(XGate(), [4])
        circuit.append_gate(XGate(), [4])
        circuit.append_gate(XGate(), [4])
        utry = circuit.get_unitary()

        circuit.fold(circuit.get_region([(0, 2), (1, 1), (2, 1)]))
        assert circuit.get_num_operations() == 9
        assert circuit.get_depth() == 3
        assert circuit.count(HGate()) == 2
        assert circuit.count(XGate()) == 6
        assert isinstance(circuit[1, 1].gate, CircuitGate)
        test_gate: CircuitGate = circuit[1, 1].gate
        assert test_gate._circuit[0, 1].gate is CNOTGate()
        assert test_gate._circuit[0, 2].gate is CNOTGate()
        assert test_gate._circuit[1, 0].gate is wide_gate
        assert test_gate._circuit[1, 1].gate is wide_gate
        assert test_gate._circuit[1, 2].gate is wide_gate
        check_no_idle_cycles(circuit)
        assert np.allclose(utry.get_numpy(), circuit.get_unitary().get_numpy())
Esempio n. 2
0
def check_gradient(circ: Circuit, num_params: int) -> None:
    totaldiff = [0] * num_params
    eps = 1e-5
    repeats = 100
    for _ in range(repeats):
        v = np.random.rand(num_params) * 2 * np.pi
        M, Js = circ.get_unitary_and_grad(v)
        for i in range(num_params):
            v2 = np.copy(v)
            v2[i] = v[i] + eps
            U1 = circ.get_unitary(v2)
            if isinstance(U1, UnitaryMatrix):
                utry1 = U1.get_numpy()
            else:
                utry1 = U1
            v2[i] = v[i] - eps
            U2 = circ.get_unitary(v2)
            if isinstance(U2, UnitaryMatrix):
                utry2 = U2.get_numpy()
            else:
                utry2 = U2

            FD = (utry1 - utry2) / (2 * eps)

            diffs = np.sum(np.abs(FD - Js[i]))
            totaldiff[i] += diffs
    for i in range(num_params):
        assert totaldiff[i] < eps
Esempio n. 3
0
    def test_run(self) -> None:
        """Test run with a linear topology."""
        #     0  1  2  3  4        #########
        # 0 --o-----o--P--P--    --#-o---o-#-----#######--
        # 1 --x--o--x--o-----    --#-x-o-x-#######-o---#--
        # 2 -----x--o--x--o-- => --#---x---#---o-#-x-o-#--
        # 3 --o--P--x--P--x--    --#########-o-x-#---x-#--
        # 4 --x-----------P--    ----------#-x---#######--
        #                                  #######

        num_q = 5
        circ = Circuit(num_q)
        circ.append_gate(CNOTGate(), [0, 1])
        circ.append_gate(CNOTGate(), [3, 4])
        circ.append_gate(CNOTGate(), [1, 2])
        circ.append_gate(CNOTGate(), [0, 1])
        circ.append_gate(CNOTGate(), [2, 3])
        circ.append_gate(CNOTGate(), [1, 2])
        circ.append_gate(CNOTGate(), [2, 3])
        utry = circ.get_unitary()
        ScanPartitioner(3).run(circ, {})

        assert len(circ) == 3
        assert all(isinstance(op.gate, CircuitGate) for op in circ)
        placeholder_gate = TaggedGate(IdentityGate(1), '__fold_placeholder__')
        assert all(
            op.gate._circuit.count(placeholder_gate) == 0
            for op in circ)  # type: ignore  # noqa
        assert circ.get_unitary() == utry
        for cycle_index in range(circ.get_num_cycles()):
            assert not circ._is_cycle_idle(cycle_index)
Esempio n. 4
0
    def test_corner_case_2(self) -> None:
        circuit = Circuit(6)

        circuit.append_gate(ConstantUnitaryGate(UnitaryMatrix.random(1)), [0])
        circuit.append_gate(ConstantUnitaryGate(UnitaryMatrix.random(1)), [1])
        circuit.append_gate(ConstantUnitaryGate(UnitaryMatrix.random(1)), [5])

        circuit.append_gate(
            ConstantUnitaryGate(UnitaryMatrix.random(2), ),
            [
                3,
                0,
            ],
        )

        circuit.append_gate(
            ConstantUnitaryGate(UnitaryMatrix.random(2), ),
            [
                5,
                0,
            ],
        )
        circuit.append_gate(ConstantUnitaryGate(UnitaryMatrix.random(1)), [3])

        circuit.append_gate(
            ConstantUnitaryGate(UnitaryMatrix.random(4), ),
            [
                4,
                0,
                1,
                2,
            ],
        )
        circuit.append_gate(ConstantUnitaryGate(UnitaryMatrix.random(1)), [5])

        circuit.append_gate(
            ConstantUnitaryGate(UnitaryMatrix.random(3), ),
            [
                5,
                0,
                1,
            ],
        )

        circuit.append_gate(ConstantUnitaryGate(UnitaryMatrix.random(1)), [1])

        utry = circuit.get_unitary()
        ScanPartitioner(3).run(circuit, {})

        assert all(
            isinstance(op.gate, CircuitGate) or len(op.location) > 3
            for op in circuit)
        assert all(not isinstance(op.gate, TaggedGate)
                   or not op.gate.tag != '__fold_placeholder__'
                   for op in circuit)
        assert circuit.get_unitary() == utry
        for cycle_index in range(circuit.get_num_cycles()):
            assert not circuit._is_cycle_idle(cycle_index)
Esempio n. 5
0
    def test_run_r6(self, r6_qudit_circuit: Circuit) -> None:
        utry = r6_qudit_circuit.get_unitary()
        ClusteringPartitioner(3, 2).run(r6_qudit_circuit, {})

        assert any(isinstance(op.gate, CircuitGate) for op in r6_qudit_circuit)

        assert r6_qudit_circuit.get_unitary() == utry
        for cycle_index in range(r6_qudit_circuit.get_num_cycles()):
            assert not r6_qudit_circuit._is_cycle_idle(cycle_index)
Esempio n. 6
0
 def test_with_fold(self, r6_qudit_circuit: Circuit) -> None:
     cycle = 0
     qudit = 0
     while True:
         cycle = np.random.randint(r6_qudit_circuit.get_num_cycles())
         qudit = np.random.randint(r6_qudit_circuit.get_size())
         if not r6_qudit_circuit.is_point_idle((cycle, qudit)):
             break
     utry = r6_qudit_circuit.get_unitary()
     region = r6_qudit_circuit.surround((cycle, qudit), 4)
     r6_qudit_circuit.fold(region)
     assert r6_qudit_circuit.get_unitary() == utry
Esempio n. 7
0
    def test_run_r6(self, r6_qudit_circuit: Circuit) -> None:
        utry = r6_qudit_circuit.get_unitary()
        ScanPartitioner(3).run(r6_qudit_circuit, {})

        assert all(
            isinstance(op.gate, CircuitGate) or len(op.location) > 3
            for op in r6_qudit_circuit)
        assert all(not isinstance(op.gate, TaggedGate)
                   or not op.gate.tag != '__fold_placeholder__'
                   for op in r6_qudit_circuit)
        assert r6_qudit_circuit.get_unitary() == utry
        for cycle_index in range(r6_qudit_circuit.get_num_cycles()):
            assert not r6_qudit_circuit._is_cycle_idle(cycle_index)
Esempio n. 8
0
    def test_parameters(self) -> None:
        circ = Circuit(2)
        circ.append_gate(CNOTGate(), [1, 0])
        circ.append_gate(U3Gate(), [0], [0, 0, 0.23])
        circ.append_gate(CNOTGate(), [1, 0])

        before_fold = circ.get_unitary()

        circ.fold(circ.get_region([(0, 0), (1, 0), (2, 0)]))

        after_fold = circ.get_unitary()

        assert after_fold == before_fold
Esempio n. 9
0
    def test_no_change(self) -> None:
        u1 = unitary_group.rvs(8)
        g1 = VariableUnitaryGate(3)
        circuit = Circuit(3)
        circuit.append_gate(g1, [0, 1, 2])
        utry_before = circuit.get_unitary()
        # The following call should not make any changes in circuit
        QFactor().instantiate(circuit, u1, circuit.get_params())
        utry_after = circuit.get_unitary()

        assert np.allclose(
            utry_before.get_numpy(),
            utry_after.get_numpy(),
        )
Esempio n. 10
0
    def run(self, circuit: Circuit, data: dict[str, Any]) -> None:
        """Perform the pass's operation, see BasePass for more info."""

        # Check data for windows markers
        if 'window_markers' not in data:
            _logger.warning('Did not find any window markers.')
            return

        window_markers = data['window_markers']
        _logger.debug('Found window_markers: %s.' % str(window_markers))

        if not is_iterable(window_markers):
            _logger.debug('Invalid type for window_markers.')
            return

        if not all(is_integer(marker) for marker in window_markers):
            _logger.debug('Invalid type for window_markers.')
            return

        # Resynthesis each window
        index_shift = 0
        for marker in window_markers:
            marker -= index_shift

            # Slice window
            begin_cycle = int(marker - self.window_size // 2)
            end_cycle = int(marker + np.ceil(self.window_size / 2))

            if begin_cycle < 0:
                begin_cycle = 0

            if end_cycle > circuit.get_num_cycles():
                end_cycle = circuit.get_num_cycles() - 1

            window = Circuit(circuit.get_size(), circuit.get_radixes())
            window.extend(circuit[begin_cycle:end_cycle])

            _logger.info(
                'Resynthesizing window from cycle '
                f'{begin_cycle} to {end_cycle}.', )

            # Synthesize
            utry = window.get_unitary()
            new_window = self.synthesispass.synthesize(utry, data)

            # Replace
            if self.replace_filter(new_window, window):
                _logger.debug('Replacing window with synthesized circuit.')

                actual_window_size = end_cycle - begin_cycle
                for _ in range(actual_window_size):
                    circuit.pop_cycle(begin_cycle)

                circuit.insert_circuit(
                    begin_cycle,
                    new_window,
                    list(range(circuit.get_size())),
                )

                index_shift += actual_window_size - new_window.get_num_cycles()
Esempio n. 11
0
def test_hilbert_schmidt_residuals(r3_qubit_circuit: Circuit) -> None:
    x0 = np.random.random((r3_qubit_circuit.get_num_params(), ))
    cost = HilbertSchmidtResidualsGenerator().gen_cost(
        r3_qubit_circuit,
        r3_qubit_circuit.get_unitary(x0),
    )
    assert cost.get_cost(x0) < 1e-10
Esempio n. 12
0
    def run(self, circuit: Circuit, data: dict[str, Any]) -> None:
        """Perform the pass's operation, see BasePass for more info."""
        start = 'left' if self.start_from_left else 'right'
        _logger.debug(f'Starting scan gate removal from {start}.')

        target = circuit.get_unitary()

        circuit_copy = circuit.copy()
        reverse_iter = not self.start_from_left
        for cycle, op in circuit.operations_with_cycles(reverse=reverse_iter):

            if not self.collection_filter(op):
                _logger.debug(f'Skipping operation {op} at cycle {cycle}.')
                continue

            _logger.info(f'Attempting removal of operation at cycle {cycle}.')
            _logger.debug(f'Operation: {op}')

            working_copy = circuit_copy.copy()

            # If removing gates from the left, we need to track index changes.
            if self.start_from_left:
                idx_shift = circuit.get_num_cycles()
                idx_shift -= working_copy.get_num_cycles()
                cycle -= idx_shift

            working_copy.pop((cycle, op.location[0]))
            working_copy.instantiate(target, **self.instantiate_options)

            if self.cost(working_copy, target) < self.success_threshold:
                _logger.info('Successfully removed operation.')
                circuit_copy = working_copy

        circuit.become(circuit_copy)
Esempio n. 13
0
    def test_2_gate(self) -> None:
        g1 = VariableUnitaryGate(2)
        g2 = VariableUnitaryGate(3)
        g3 = RXGate()
        circuit = Circuit(4)
        circuit.append_gate(g1, [0, 1])
        circuit.append_gate(g2, [1, 2, 3])
        circuit.append_gate(g3, [1])
        utry = circuit.get_unitary(np.random.random(circuit.get_num_params()))
        params = QFactor().instantiate(circuit, utry, circuit.get_params())

        circuit.set_params(params)

        assert np.allclose(
            circuit.get_unitary().get_numpy(),
            utry.get_numpy(),
        )
Esempio n. 14
0
    def test_1_gate(self) -> None:
        u1 = unitary_group.rvs(8)
        g1 = VariableUnitaryGate(3)
        circuit = Circuit(3)
        circuit.append_gate(g1, [0, 1, 2])
        params = QFactor().instantiate(circuit, u1, circuit.get_params())
        circuit.set_params(params)

        g1_params = list(np.reshape(u1, (64, )))
        g1_params = list(np.real(g1_params)) + list(np.imag(g1_params))

        assert np.allclose(
            circuit.get_unitary().get_numpy(),
            g1.get_unitary(g1_params).get_numpy(),
        )
Esempio n. 15
0
def test_toffoli_simulation(
    toffoli_unitary: UnitaryMatrix,
    toffoli_circuit: Circuit,
) -> None:
    calc_unitary = toffoli_circuit.get_unitary()
    assert toffoli_unitary.get_distance_from(calc_unitary) < 1e8
Esempio n. 16
0
    def test_correctness_1(self) -> None:
        circuit = Circuit(4)
        wide_gate = IdentityGate(4)
        circuit.append_gate(wide_gate, [0, 1, 2, 3])
        circuit.append_gate(wide_gate, [0, 1, 2, 3])
        circuit.append_gate(wide_gate, [0, 1, 2, 3])
        circuit.append_gate(wide_gate, [0, 1, 2, 3])
        assert circuit.get_num_operations() == 4
        assert circuit.get_depth() == 4
        utry = circuit.get_unitary()

        circuit.fold(circuit.get_region([(0, 0), (1, 0)]))
        assert circuit.get_num_operations() == 3
        assert circuit.get_depth() == 3
        check_no_idle_cycles(circuit)
        for q in range(4):
            assert isinstance(circuit[0, q].gate, CircuitGate)
        for c in range(1, 3, 1):
            for q in range(4):
                assert isinstance(circuit[c, q].gate, IdentityGate)
                assert isinstance(circuit[c, q].gate, IdentityGate)
        test_gate: CircuitGate = circuit[0, 0].gate  # type: ignore
        assert test_gate._circuit.get_num_operations() == 2
        assert test_gate._circuit.get_num_cycles() == 2
        for q in range(4):
            assert isinstance(test_gate._circuit[0, q].gate, IdentityGate)
            assert isinstance(test_gate._circuit[1, q].gate, IdentityGate)

        circuit.fold(circuit.get_region([(1, 0), (2, 0)]))
        assert circuit.get_num_operations() == 2
        assert circuit.get_depth() == 2
        check_no_idle_cycles(circuit)
        for c in range(2):
            for q in range(4):
                assert isinstance(circuit[c, q].gate, CircuitGate)
        test_gate: CircuitGate = circuit[0, 0].gate  # type: ignore
        assert test_gate._circuit.get_num_operations() == 2
        assert test_gate._circuit.get_num_cycles() == 2
        for q in range(4):
            assert isinstance(test_gate._circuit[0, q].gate, IdentityGate)
            assert isinstance(test_gate._circuit[1, q].gate, IdentityGate)
        test_gate: CircuitGate = circuit[1, 0].gate  # type: ignore
        assert test_gate._circuit.get_num_operations() == 2
        assert test_gate._circuit.get_num_cycles() == 2
        for q in range(4):
            assert isinstance(test_gate._circuit[0, q].gate, IdentityGate)
            assert isinstance(test_gate._circuit[1, q].gate, IdentityGate)

        circuit.fold(circuit.get_region([(0, 0), (1, 0)]))
        assert circuit.get_num_operations() == 1
        assert circuit.get_depth() == 1
        check_no_idle_cycles(circuit)
        for q in range(4):
            assert isinstance(circuit[0, q].gate, CircuitGate)
        test_gate: CircuitGate = circuit[0, 0].gate  # type: ignore
        assert test_gate._circuit.get_num_operations() == 2
        assert test_gate._circuit.get_num_cycles() == 2
        for q in range(4):
            assert isinstance(test_gate._circuit[0, q].gate, CircuitGate)
            assert isinstance(test_gate._circuit[1, q].gate, CircuitGate)
        inner_gate1: CircuitGate = test_gate._circuit[0,
                                                      0].gate  # type: ignore
        inner_gate2: CircuitGate = test_gate._circuit[1,
                                                      0].gate  # type: ignore
        assert inner_gate1._circuit.get_num_operations() == 2
        assert inner_gate1._circuit.get_num_cycles() == 2
        for q in range(4):
            assert isinstance(inner_gate1._circuit[0, q].gate, IdentityGate)
            assert isinstance(inner_gate1._circuit[1, q].gate, IdentityGate)
            assert isinstance(inner_gate2._circuit[0, q].gate, IdentityGate)
            assert isinstance(inner_gate2._circuit[1, q].gate, IdentityGate)

        check_no_idle_cycles(circuit)
        assert np.allclose(utry.get_numpy(), circuit.get_unitary().get_numpy())
Esempio n. 17
0
    def synthesize(self, utry: UnitaryMatrix, data: dict[str, Any]) -> Circuit:
        """Synthesize `utry` into a circuit, see SynthesisPass for more info."""

        # 0. Skip any unitaries too small for the configured block.
        if self.block_size_start > utry.get_size():
            _logger.warning(
                'Skipping synthesis: block size is larger than input unitary.',
            )
            return Circuit.from_unitary(utry)

        # 1. Create empty circuit with same size and radixes as `utry`.
        circuit = Circuit(utry.get_size(), utry.get_radixes())

        # 2. Calculate block sizes
        block_size_end = utry.get_size() - 1
        if self.block_size_limit is not None:
            block_size_end = self.block_size_limit

        # 3. Calculate relevant coupling_graphs
        # TODO: Look for topology info in `data`, use all-to-all otherwise.
        model = MachineModel(utry.get_size())
        locations = [
            model.get_locations(i)
            for i in range(self.block_size_start, block_size_end + 1)
        ]

        # 3. Bottom-up synthesis: build circuit up one gate at a time
        layer = 1
        last_cost = 1.0
        last_loc = None

        while True:
            remainder = utry.get_dagger() @ circuit.get_unitary()
            sorted_locations = self.analyze_remainder(remainder, locations)

            for loc in sorted_locations:

                # Never predict the previous location
                if loc == last_loc:
                    continue

                _logger.info(f'Trying next predicted location {loc}.')
                circuit.append_gate(VariableUnitaryGate(len(loc)), loc)
                circuit.instantiate(
                    utry,
                    **self.instantiate_options,  # type: ignore
                )
                cost = self.cost.calc_cost(circuit, utry)
                _logger.info(f'Instantiated; layers: {layer}, cost: {cost:e}.')

                if cost < self.success_threshold:
                    _logger.info(f'Circuit found with cost: {cost:e}.')
                    _logger.info('Successful synthesis.')
                    return circuit

                progress_threshold = self.progress_threshold_a
                progress_threshold += self.progress_threshold_r * np.abs(cost)
                if last_cost - cost >= progress_threshold:
                    _logger.info('Progress has been made, depth increasing.')
                    last_loc = loc
                    last_cost = cost
                    layer += 1
                    break

                _logger.info('Progress has not been made.')
                circuit.pop((-1, loc[0]))