Exemple #1
0
toffoli = UnitaryMatrix(toffoli)

# Start with the circuit structure
circuit = Circuit(3)
circuit.append_gate(VariableUnitaryGate(2), [1, 2])
circuit.append_gate(VariableUnitaryGate(2), [0, 2])
circuit.append_gate(VariableUnitaryGate(2), [1, 2])
circuit.append_gate(VariableUnitaryGate(2), [0, 2])
circuit.append_gate(VariableUnitaryGate(2), [0, 1])

# Instantiate the circuit template with qfactor
circuit.instantiate(
    toffoli,
    method='qfactor',
    diff_tol_a=1e-12,  # Stopping criteria for distance change
    diff_tol_r=1e-6,  # Relative criteria for distance change
    dist_tol=1e-12,  # Stopping criteria for distance
    max_iters=100000,  # Maximum number of iterations
    min_iters=1000,  # Minimum number of iterations
    slowdown_factor=0,  # Larger numbers slowdown optimization
    # to avoid local minima
)

# Calculate and print final distance
dist = HilbertSchmidtCostGenerator().calc_cost(circuit, toffoli)
print('Final Distance: ', dist)

# If you would like to convert the unitary operations to native gates,
# you should use the KAK decomposition for 2 qubit unitaries, or
# qsearch or qfast for 3+ qubit unitaries.
Exemple #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]))