Exemplo n.º 1
0
    def test_single(self) -> None:
        circuit = Circuit(4, [2, 2, 2, 2])
        assert circuit.is_qudit_idle(0)
        assert circuit.is_qudit_idle(1)
        assert circuit.is_qudit_idle(2)
        assert circuit.is_qudit_idle(3)

        circuit.append_gate(HGate(), [0])
        assert not circuit.is_qudit_idle(0)
        assert circuit.is_qudit_idle(1)
        assert circuit.is_qudit_idle(2)
        assert circuit.is_qudit_idle(3)

        circuit.append_gate(HGate(), [1])
        assert not circuit.is_qudit_idle(0)
        assert not circuit.is_qudit_idle(1)
        assert circuit.is_qudit_idle(2)
        assert circuit.is_qudit_idle(3)

        circuit.append_gate(HGate(), [2])
        assert not circuit.is_qudit_idle(0)
        assert not circuit.is_qudit_idle(1)
        assert not circuit.is_qudit_idle(2)
        assert circuit.is_qudit_idle(3)

        circuit.append_gate(HGate(), [3])
        assert not circuit.is_qudit_idle(0)
        assert not circuit.is_qudit_idle(1)
        assert not circuit.is_qudit_idle(2)
        assert not circuit.is_qudit_idle(3)

        circuit.pop((0, 0))
        assert circuit.is_qudit_idle(0)
        assert not circuit.is_qudit_idle(1)
        assert not circuit.is_qudit_idle(2)
        assert not circuit.is_qudit_idle(3)

        circuit.pop((0, 1))
        assert circuit.is_qudit_idle(0)
        assert circuit.is_qudit_idle(1)
        assert not circuit.is_qudit_idle(2)
        assert not circuit.is_qudit_idle(3)

        circuit.pop((0, 2))
        assert circuit.is_qudit_idle(0)
        assert circuit.is_qudit_idle(1)
        assert circuit.is_qudit_idle(2)
        assert not circuit.is_qudit_idle(3)

        circuit.pop((0, 3))
        assert circuit.is_qudit_idle(0)
        assert circuit.is_qudit_idle(1)
        assert circuit.is_qudit_idle(2)
        assert circuit.is_qudit_idle(3)
Exemplo n.º 2
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]))