Exemple #1
0
 def test_circuit_result(self):
     """Test circuit_result"""
     oracle = QuantumCircuit(2)
     oracle.cz(0, 1)
     # is_good_state=['00'] is intentionally selected to obtain a list of results
     problem = AmplificationProblem(oracle, is_good_state=["00"])
     grover = Grover(iterations=[1, 2, 3, 4], quantum_instance=self.qasm)
     result = grover.amplify(problem)
     expected_results = [
         {
             "11": 1024
         },
         {
             "00": 238,
             "01": 253,
             "10": 263,
             "11": 270
         },
         {
             "00": 238,
             "01": 253,
             "10": 263,
             "11": 270
         },
         {
             "11": 1024
         },
     ]
     self.assertEqual(result.circuit_results, expected_results)
Exemple #2
0
 def test_fixed_iterations(self):
     """Test the iterations argument"""
     grover = Grover(iterations=2, quantum_instance=self.statevector)
     problem = AmplificationProblem(Statevector.from_label("111"),
                                    is_good_state=["111"])
     result = grover.amplify(problem)
     self.assertEqual(result.top_measurement, "111")
 def test_iterations_with_good_state(self, iterations):
     """Test the algorithm with different iteration types and with good state"""
     grover = Grover(iterations, quantum_instance=self.statevector)
     problem = AmplificationProblem(Statevector.from_label("111"),
                                    is_good_state=["111"])
     result = grover.amplify(problem)
     self.assertEqual(result.top_measurement, "111")
 def test_max_power(self):
     """Test the iteration stops when the maximum power is reached."""
     lam = 10.0
     grover = Grover(growth_rate=lam, quantum_instance=self.statevector)
     problem = AmplificationProblem(Statevector.from_label("111"), is_good_state=["111"])
     result = grover.amplify(problem)
     self.assertEqual(len(result.iterations), 0)
Exemple #5
0
 def test_growth_rate(self):
     """Test running the algorithm on a growth rate"""
     grover = Grover(growth_rate=8 / 7, quantum_instance=self.statevector)
     problem = AmplificationProblem(Statevector.from_label("111"),
                                    is_good_state=["111"])
     result = grover.amplify(problem)
     self.assertEqual(result.top_measurement, "111")
Exemple #6
0
 def test_implicit_phase_oracle_is_good_state(self):
     """Test implicit default for is_good_state with PhaseOracle."""
     grover = Grover(iterations=2, quantum_instance=self.statevector)
     oracle = PhaseOracle("x | x")
     problem = AmplificationProblem(oracle)
     result = grover.amplify(problem)
     self.assertEqual(result.top_measurement, "0")
 def test_oracle_evaluation(self):
     """Test oracle_evaluation for PhaseOracle"""
     oracle = PhaseOracle("x1 & x2 & (not x3)")
     problem = AmplificationProblem(oracle, is_good_state=oracle.evaluate_bitstring)
     grover = Grover(quantum_instance=self.qasm)
     result = grover.amplify(problem)
     self.assertTrue(result.oracle_evaluation)
     self.assertEqual("011", result.top_measurement)
 def test_iterations_without_good_state(self, iterations):
     """Test the correct error is thrown for none/list of iterations and without good state"""
     grover = Grover(iterations, quantum_instance=self.statevector)
     problem = AmplificationProblem(Statevector.from_label("111"))
     with self.assertRaisesRegex(
         TypeError, "An is_good_state function is required with the provided oracle"
     ):
         grover.amplify(problem)
 def test_multiple_iterations(self):
     """Test the algorithm for a list of iterations."""
     grover = Grover(iterations=[1, 2, 3],
                     quantum_instance=self.statevector)
     problem = AmplificationProblem(Statevector.from_label('111'),
                                    is_good_state=['111'])
     result = grover.amplify(problem)
     self.assertEqual(result.top_measurement, '111')
Exemple #10
0
    def test_run_state_vector_oracle(self):
        """Test execution with a state vector oracle"""
        mark_state = Statevector.from_label('11')
        problem = AmplificationProblem(mark_state, is_good_state=['11'])

        grover = Grover(quantum_instance=self.qasm)
        result = grover.amplify(problem)
        self.assertIn(result.top_measurement, ['11'])
Exemple #11
0
    def test_groverop_getter(self, kind):
        """Test the default construction of the Grover operator."""
        oracle = QuantumCircuit(2)
        oracle.cz(0, 1)

        if kind == "oracle_only":
            problem = AmplificationProblem(oracle, is_good_state=["11"])
            expected = GroverOperator(oracle)
        else:
            stateprep = QuantumCircuit(2)
            stateprep.ry(0.2, [0, 1])
            problem = AmplificationProblem(oracle,
                                           state_preparation=stateprep,
                                           is_good_state=["11"])
            expected = GroverOperator(oracle, stateprep)

        self.assertEqual(Operator(expected), Operator(problem.grover_operator))
Exemple #12
0
 def test_max_probability(self):
     """Test max_probability"""
     oracle = QuantumCircuit(2)
     oracle.cz(0, 1)
     problem = AmplificationProblem(oracle, is_good_state=["11"])
     grover = Grover(quantum_instance=self.qasm)
     result = grover.amplify(problem)
     self.assertEqual(result.max_probability, 1.0)
Exemple #13
0
    def test_run_circuit_oracle(self):
        """Test execution with a quantum circuit oracle"""
        oracle = QuantumCircuit(2)
        oracle.cz(0, 1)
        problem = AmplificationProblem(oracle, is_good_state=['11'])

        grover = Grover(quantum_instance=self.qasm)
        result = grover.amplify(problem)
        self.assertIn(result.top_measurement, ['11'])
Exemple #14
0
 def test_run_circuit_oracle(self):
     """Test execution with a quantum circuit oracle"""
     oracle = QuantumCircuit(2)
     oracle.cz(0, 1)
     problem = AmplificationProblem(oracle, is_good_state=["11"])
     qi = QuantumInstance(self._provider.get_backend("fake_yorktown"),
                          seed_simulator=12,
                          seed_transpiler=32)
     grover = Grover(quantum_instance=qi)
     result = grover.amplify(problem)
     self.assertIn(result.top_measurement, ["11"])
 def test_run_circuit_oracle_single_experiment_backend(self):
     """Test execution with a quantum circuit oracle"""
     oracle = QuantumCircuit(2)
     oracle.cz(0, 1)
     problem = AmplificationProblem(oracle, is_good_state=["11"])
     backend = self._provider.get_backend("fake_vigo")
     backend._configuration.max_experiments = 1
     qi = QuantumInstance(backend, seed_simulator=12, seed_transpiler=32)
     grover = Grover(quantum_instance=qi)
     result = grover.amplify(problem)
     self.assertIn(result.top_measurement, ["11"])
Exemple #16
0
    def test_run_custom_grover_operator(self):
        """Test execution with a grover operator oracle"""
        oracle = QuantumCircuit(2)
        oracle.cz(0, 1)
        grover_op = GroverOperator(oracle)
        problem = AmplificationProblem(oracle=oracle,
                                       grover_operator=grover_op,
                                       is_good_state=['11'])

        grover = Grover(quantum_instance=self.qasm)
        ret = grover.amplify(problem)
        self.assertIn(ret.top_measurement, ['11'])
Exemple #17
0
    def test_max_num_iterations(self):
        """Test the iteration stops when the maximum number of iterations is reached."""
        def zero():
            while True:
                yield 0

        grover = Grover(iterations=zero(), quantum_instance=self.statevector)
        n = 5
        problem = AmplificationProblem(Statevector.from_label('1' * n),
                                       is_good_state=['1' * n])
        result = grover.amplify(problem)
        self.assertEqual(len(result.iterations), 2**n)
Exemple #18
0
    def test_construct_circuit(self):
        """Test construct_circuit"""
        oracle = QuantumCircuit(2)
        oracle.cz(0, 1)
        problem = AmplificationProblem(oracle)
        grover = Grover()
        constructed = grover.construct_circuit(problem, 2, measurement=False)

        grover_op = GroverOperator(oracle)
        expected = QuantumCircuit(2)
        expected.h([0, 1])
        expected.compose(grover_op.power(2), inplace=True)

        self.assertTrue(Operator(constructed).equiv(Operator(expected)))
    def test_iterator(self):
        """Test running the algorithm on an iterator."""

        # step-function iterator
        def iterator():
            wait, value, count = 3, 1, 0
            while True:
                yield value
                count += 1
                if count % wait == 0:
                    value += 1

        grover = Grover(iterations=iterator(), quantum_instance=self.statevector)
        problem = AmplificationProblem(Statevector.from_label("111"), is_good_state=["111"])
        result = grover.amplify(problem)
        self.assertEqual(result.top_measurement, "111")
Exemple #20
0
    def solve(self, problem: QuadraticProgram) -> OptimizationResult:
        """Tries to solves the given problem using the grover optimizer.

        Runs the optimizer to try to solve the optimization problem. If the problem cannot be,
        converted to a QUBO, this optimizer raises an exception due to incompatibility.

        Args:
            problem: The problem to be solved.

        Returns:
            The result of the optimizer applied to the problem.

        Raises:
            AttributeError: If the quantum instance has not been set.
            QiskitOptimizationError: If the problem is incompatible with the optimizer.
        """
        if self.quantum_instance is None:
            raise AttributeError(
                'The quantum instance or backend has not been set.')

        self._verify_compatibility(problem)

        # convert problem to QUBO
        problem_ = self._convert(problem, self._converters)
        problem_init = deepcopy(problem_)

        # convert to minimization problem
        sense = problem_.objective.sense
        if sense == problem_.objective.Sense.MAXIMIZE:
            problem_.objective.sense = problem_.objective.Sense.MINIMIZE
            problem_.objective.constant = -problem_.objective.constant
            for i, val in problem_.objective.linear.to_dict().items():
                problem_.objective.linear[i] = -val
            for (i, j), val in problem_.objective.quadratic.to_dict().items():
                problem_.objective.quadratic[i, j] = -val
        self._num_key_qubits = len(
            problem_.objective.linear.to_array())  # type: ignore

        # Variables for tracking the optimum.
        optimum_found = False
        optimum_key = math.inf
        optimum_value = math.inf
        threshold = 0
        n_key = len(problem_.variables)
        n_value = self._num_value_qubits

        # Variables for tracking the solutions encountered.
        num_solutions = 2**n_key
        keys_measured = []

        # Variables for result object.
        operation_count = {}
        iteration = 0

        # Variables for stopping if we've hit the rotation max.
        rotations = 0
        max_rotations = int(np.ceil(100 * np.pi / 4))

        # Initialize oracle helper object.
        qr_key_value = QuantumRegister(self._num_key_qubits +
                                       self._num_value_qubits)
        orig_constant = problem_.objective.constant
        measurement = not self.quantum_instance.is_statevector
        oracle, is_good_state = self._get_oracle(qr_key_value)

        while not optimum_found:
            m = 1
            improvement_found = False

            # Get oracle O and the state preparation operator A for the current threshold.
            problem_.objective.constant = orig_constant - threshold
            a_operator = self._get_a_operator(qr_key_value, problem_)

            # Iterate until we measure a negative.
            loops_with_no_improvement = 0
            while not improvement_found:
                # Determine the number of rotations.
                loops_with_no_improvement += 1
                rotation_count = int(
                    np.ceil(algorithm_globals.random.uniform(0, m - 1)))
                rotations += rotation_count
                # Apply Grover's Algorithm to find values below the threshold.
                # TODO: Utilize Grover's incremental feature - requires changes to Grover.
                amp_problem = AmplificationProblem(
                    oracle=oracle,
                    state_preparation=a_operator,
                    is_good_state=is_good_state)
                grover = Grover()
                circuit = grover.construct_circuit(problem=amp_problem,
                                                   power=rotation_count,
                                                   measurement=measurement)

                # Get the next outcome.
                outcome = self._measure(circuit)
                k = int(outcome[0:n_key], 2)
                v = outcome[n_key:n_key + n_value]
                int_v = self._bin_to_int(v, n_value) + threshold
                logger.info('Outcome: %s', outcome)
                logger.info('Value Q(x): %s', int_v)

                # If the value is an improvement, we update the iteration parameters (e.g. oracle).
                if int_v < optimum_value:
                    optimum_key = k
                    optimum_value = int_v
                    logger.info('Current Optimum Key: %s', optimum_key)
                    logger.info('Current Optimum Value: %s', optimum_value)
                    improvement_found = True
                    threshold = optimum_value
                else:
                    # Using Durr and Hoyer method, increase m.
                    m = int(np.ceil(min(m * 8 / 7, 2**(n_key / 2))))
                    logger.info('No Improvement. M: %s', m)

                    # Check if we've already seen this value.
                    if k not in keys_measured:
                        keys_measured.append(k)

                    # Assume the optimal if any of the stop parameters are true.
                    if loops_with_no_improvement >= self._n_iterations or \
                            len(keys_measured) == num_solutions or rotations >= max_rotations:
                        improvement_found = True
                        optimum_found = True

                # Track the operation count.
                operations = circuit.count_ops()
                operation_count[iteration] = operations
                iteration += 1
                logger.info('Operation Count: %s\n', operations)

        # If the constant is 0 and we didn't find a negative, the answer is likely 0.
        if optimum_value >= 0 and orig_constant == 0:
            optimum_key = 0

        opt_x = np.array([
            1 if s == '1' else 0
            for s in ('{0:%sb}' % n_key).format(optimum_key)
        ])

        # Compute function value
        fval = problem_init.objective.evaluate(opt_x)

        # cast binaries back to integers
        return cast(
            GroverOptimizationResult,
            self._interpret(x=opt_x,
                            converters=self._converters,
                            problem=problem,
                            result_class=GroverOptimizationResult,
                            operation_counts=operation_count,
                            n_input_qubits=n_key,
                            n_output_qubits=n_value,
                            intermediate_fval=fval,
                            threshold=threshold))
    def solve(self, problem: QuadraticProgram) -> OptimizationResult:
        """Tries to solves the given problem using the grover optimizer.

        Runs the optimizer to try to solve the optimization problem. If the problem cannot be,
        converted to a QUBO, this optimizer raises an exception due to incompatibility.

        Args:
            problem: The problem to be solved.

        Returns:
            The result of the optimizer applied to the problem.

        Raises:
            AttributeError: If the quantum instance has not been set.
            QiskitOptimizationError: If the problem is incompatible with the optimizer.
        """
        if self.quantum_instance is None:
            raise AttributeError("The quantum instance or backend has not been set.")

        self._verify_compatibility(problem)

        # convert problem to minimization QUBO problem
        problem_ = self._convert(problem, self._converters)
        problem_init = deepcopy(problem_)

        self._num_key_qubits = len(problem_.objective.linear.to_array())

        # Variables for tracking the optimum.
        optimum_found = False
        optimum_key = math.inf
        optimum_value = math.inf
        threshold = 0
        n_key = self._num_key_qubits
        n_value = self._num_value_qubits

        # Variables for tracking the solutions encountered.
        num_solutions = 2**n_key
        keys_measured = []

        # Variables for result object.
        operation_count = {}
        iteration = 0

        # Variables for stopping if we've hit the rotation max.
        rotations = 0
        max_rotations = int(np.ceil(100 * np.pi / 4))

        # Initialize oracle helper object.
        qr_key_value = QuantumRegister(self._num_key_qubits + self._num_value_qubits)
        orig_constant = problem_.objective.constant
        measurement = not self.quantum_instance.is_statevector
        oracle, is_good_state = self._get_oracle(qr_key_value)

        while not optimum_found:
            m = 1
            improvement_found = False

            # Get oracle O and the state preparation operator A for the current threshold.
            problem_.objective.constant = orig_constant - threshold
            a_operator = self._get_a_operator(qr_key_value, problem_)

            # Iterate until we measure a negative.
            loops_with_no_improvement = 0
            while not improvement_found:
                # Determine the number of rotations.
                loops_with_no_improvement += 1
                rotation_count = algorithm_globals.random.integers(0, m)
                rotations += rotation_count
                # Apply Grover's Algorithm to find values below the threshold.
                # TODO: Utilize Grover's incremental feature - requires changes to Grover.
                amp_problem = AmplificationProblem(
                    oracle=oracle,
                    state_preparation=a_operator,
                    is_good_state=is_good_state,
                )
                grover = Grover()
                circuit = grover.construct_circuit(
                    problem=amp_problem, power=rotation_count, measurement=measurement
                )

                # Get the next outcome.
                outcome = self._measure(circuit)
                k = int(outcome[0:n_key], 2)
                v = outcome[n_key : n_key + n_value]
                int_v = self._bin_to_int(v, n_value) + threshold
                logger.info("Outcome: %s", outcome)
                logger.info("Value Q(x): %s", int_v)
                # If the value is an improvement, we update the iteration parameters (e.g. oracle).
                if int_v < optimum_value:
                    optimum_key = k
                    optimum_value = int_v
                    logger.info("Current Optimum Key: %s", optimum_key)
                    logger.info("Current Optimum Value: %s", optimum_value)
                    improvement_found = True
                    threshold = optimum_value

                    # trace out work qubits and store samples
                    if self._quantum_instance.is_statevector:
                        indices = list(range(n_key, len(outcome)))
                        rho = partial_trace(self._circuit_results, indices)
                        self._circuit_results = cast(Dict, np.diag(rho.data) ** 0.5)
                    else:
                        self._circuit_results = {
                            i[-1 * n_key :]: v for i, v in self._circuit_results.items()
                        }

                    raw_samples = self._eigenvector_to_solutions(
                        self._circuit_results, problem_init
                    )
                    raw_samples.sort(key=lambda x: x.fval)
                    samples, _ = self._interpret_samples(problem, raw_samples, self._converters)
                else:
                    # Using Durr and Hoyer method, increase m.
                    m = int(np.ceil(min(m * 8 / 7, 2 ** (n_key / 2))))
                    logger.info("No Improvement. M: %s", m)

                    # Check if we've already seen this value.
                    if k not in keys_measured:
                        keys_measured.append(k)

                    # Assume the optimal if any of the stop parameters are true.
                    if (
                        loops_with_no_improvement >= self._n_iterations
                        or len(keys_measured) == num_solutions
                        or rotations >= max_rotations
                    ):
                        improvement_found = True
                        optimum_found = True

                # Track the operation count.
                operations = circuit.count_ops()
                operation_count[iteration] = operations
                iteration += 1
                logger.info("Operation Count: %s\n", operations)

        # If the constant is 0 and we didn't find a negative, the answer is likely 0.
        if optimum_value >= 0 and orig_constant == 0:
            optimum_key = 0

        opt_x = np.array([1 if s == "1" else 0 for s in f"{optimum_key:{n_key}b}"])
        # Compute function value of minimization QUBO
        fval = problem_init.objective.evaluate(opt_x)

        # cast binaries back to integers and eventually minimization to maximization
        return cast(
            GroverOptimizationResult,
            self._interpret(
                x=opt_x,
                converters=self._converters,
                problem=problem,
                result_class=GroverOptimizationResult,
                samples=samples,
                raw_samples=raw_samples,
                operation_counts=operation_count,
                n_input_qubits=n_key,
                n_output_qubits=n_value,
                intermediate_fval=fval,
                threshold=threshold,
            ),
        )
 def test_fixed_iterations_without_good_state(self):
     """Test the algorithm with iterations as an int and without good state"""
     grover = Grover(iterations=2, quantum_instance=self.statevector)
     problem = AmplificationProblem(Statevector.from_label("111"))
     result = grover.amplify(problem)
     self.assertEqual(result.top_measurement, "111")