Beispiel #1
0
    def get_exact_expectation_values(self, circuit, qubit_operator, **kwargs):
        """Run a circuit to prepare a wavefunction and measure the exact
        expectation values with respect to a given operator.

        Args:
            circuit (zquantum.core.circuit.Circuit): the circuit to prepare the state
            qubit_operator (openfermion.ops.QubitOperator): the operator to measure
        Returns:
            zquantum.core.measurement.ExpectationValues: the expectation values
                of each term in the operator
        """
        self.num_circuits_run += 1
        self.num_jobs_run += 1
        wavefunction = self.get_wavefunction(circuit)

        # Pyquil does not support PauliSums with no terms.
        if len(qubit_operator.terms) == 0:
            return ExpectationValues(np.zeros((0, )))

        values = []

        for op in qubit_operator:
            values.append(expectation(op, wavefunction))
        return expectation_values_to_real(ExpectationValues(
            np.asarray(values)))
Beispiel #2
0
    def get_exact_expectation_values(self, circuit, qubit_operator):
        self.number_of_jobs_run += 1
        self.number_of_circuits_run += 1
        if self.device_name != "wavefunction-simulator":
            raise RuntimeError(
                "To compute exact expectation values, the device name must be "
                '"wavefunction-simulator". The device name is currently '
                f"{self.device_name}."
            )
        cxn = get_forest_connection(self.device_name, self.seed)

        # Pyquil does not support PauliSums with no terms.
        if len(qubit_operator.terms) == 0:
            return ExpectationValues(np.zeros((0,)))

        pauli_sum = qubitop_to_pyquilpauli(qubit_operator)
        expectation_values = np.real(
            cxn.expectation(export_to_pyquil(circuit), pauli_sum.terms)
        )

        if expectation_values.shape[0] != len(pauli_sum):
            raise (
                RuntimeError(
                    f"Expected {len(pauli_sum)} expectation values but received "
                    f"{expectation_values.shape[0]}."
                )
            )
        return ExpectationValues(expectation_values)
def test_concatenate_expectation_values():
    expectation_values_set = [
        ExpectationValues(np.array([1.0, 2.0])),
        ExpectationValues(np.array([3.0, 4.0])),
    ]

    combined_expectation_values = concatenate_expectation_values(
        expectation_values_set)
    assert combined_expectation_values.correlations is None
    assert combined_expectation_values.estimator_covariances is None
    assert np.allclose(combined_expectation_values.values,
                       [1.0, 2.0, 3.0, 4.0])
def test_expectation_values_to_real():
    # Given
    expectation_values = ExpectationValues(
        np.array([0.0 + 0.1j, 0.0 + 1e-10j, -1.0]))
    target_expectation_values = ExpectationValues(np.array([0.0, 0.0, -1.0]))

    # When
    real_expectation_values = expectation_values_to_real(expectation_values)

    # Then
    for value in expectation_values.values:
        assert not isinstance(value, complex)
    np.testing.assert_array_equal(real_expectation_values.values,
                                  target_expectation_values.values)
Beispiel #5
0
    def get_exact_expectation_values(self, circuit, qubit_operator, **kwargs):
        if self.device_name != 'wavefunction-simulator' and self.n_samples!=None:
            raise Exception("Exact expectation values work only for the wavefunction simulator and n_samples equal to None.")
        cxn = get_forest_connection(self.device_name)

        # Pyquil does not support PauliSums with no terms.
        if len(qubit_operator.terms) == 0:
            return ExpectationValues(np.zeros((0,)))

        pauli_sum = qubitop_to_pyquilpauli(qubit_operator)
        expectation_values = cxn.expectation(circuit.to_pyquil(), pauli_sum.terms)
        if expectation_values.shape[0] != len(pauli_sum):
            raise(RuntimeError("Expected {} expectation values but received {}.".format(len(pauli_sum), expectation_values.shape[0])))
        return ExpectationValues(expectation_values)
    def __call__(
            self, backend: QuantumBackend,
            estimation_tasks: List[EstimationTask]) -> List[ExpectationValues]:
        """Given a circuit, backend, and target operators, this method produces expectation values
        using Gibbs objective function.

        Args:
            backend: the backend that will be used to run the circuits
            estimation_tasks: the estimation tasks defining the problem. Each task consist of target operator, circuit and number of shots.
            alpha: defines to exponent coefficient, `exp(-alpha * expectation_value)`. See equation 2 in the original paper.
        """
        if self.alpha <= 0:
            raise ValueError("alpha needs to be a value greater than 0.")

        circuits, operators, shots_per_circuit = zip(
            *[(e.circuit, e.operator, e.number_of_shots)
              for e in estimation_tasks])
        distributions_list = [
            backend.get_bitstring_distribution(circuit, n_samples=n_shots)
            for circuit, n_shots in zip(circuits, shots_per_circuit)
        ]

        return [
            ExpectationValues(
                np.array([
                    _calculate_expectation_value_for_distribution(
                        distribution, operator, self.alpha)
                ]))
            for distribution, operator in zip(distributions_list, operators)
        ]
Beispiel #7
0
def test_sum_expectation_values_with_covariances():
    values = np.array([5, -2, 1])
    correlations = [np.array([[1, 0.5], [0.5, 2]]), np.array([[7]])]
    covariances = [correlations[0] / 10, correlations[1] / 10]
    expectation_values = ExpectationValues(values, correlations, covariances)
    total = sum_expectation_values(expectation_values)
    assert np.isclose(total.value, 4)
    assert np.isclose(total.precision, np.sqrt((1 + 0.5 + 0.5 + 2 + 7) / 10))
Beispiel #8
0
 def test_evaluate_qubit_operator(self):
     # Given
     qubit_op = QubitOperator("0.5 [] + 0.5 [Z1]")
     expectation_values = ExpectationValues([0.5, 0.5])
     # When
     value_estimate = evaluate_qubit_operator(qubit_op, expectation_values)
     # Then
     self.assertAlmostEqual(value_estimate.value, 0.5)
Beispiel #9
0
    def __call__(
            self, backend: QuantumBackend,
            estimation_tasks: List[EstimationTask]) -> List[ExpectationValues]:
        """Given a circuit, backend, and target operators, this method produces expectation values
        using CVaR method.

        Args:
            backend: the backend that will be used to run the circuits
            estimation_tasks: the estimation tasks defining the problem. Each task consist of target operator, circuit and number of shots.
        """
        if self.alpha > 1 or self.alpha <= 0:
            raise ValueError("alpha needs to be a value between 0 and 1.")

        circuits, operators, shots_per_circuit = zip(
            *[(e.circuit, e.operator, e.number_of_shots)
              for e in estimation_tasks])

        if not self.use_exact_expectation_values:
            distributions_list = [
                backend.get_bitstring_distribution(circuit, n_samples=n_shots)
                for circuit, n_shots in zip(circuits, shots_per_circuit)
            ]

            return [
                ExpectationValues(
                    np.array([
                        _calculate_expectation_value_for_distribution(
                            distribution, operator, self.alpha)
                    ])) for distribution, operator in zip(
                        distributions_list, operators)
            ]

        else:
            wavefunctions_list = [
                backend.get_wavefunction(circuit) for circuit in circuits
            ]

            return [
                ExpectationValues(
                    np.array([
                        _calculate_expectation_value_for_wavefunction(
                            distribution, operator, self.alpha)
                    ])) for distribution, operator in zip(
                        wavefunctions_list, operators)
            ]
Beispiel #10
0
    def get_estimated_expectation_values(
        self,
        backend: QuantumBackend,
        circuit: Circuit,
        target_operator: IsingOperator,
        alpha: float,
        n_samples: Optional[int] = None,
    ) -> ExpectationValues:
        """Given a circuit, backend, and target operators, this method produces expectation values
        using CVaR algorithm.

        Args:
            backend (QuantumBackend): the backend that will be used to run the circuit
            circuit (Circuit): the circuit that prepares the state.
            target_operator (SymbolicOperator): Operator to be estimated.
            alpha (float): defines what part of the best measurements should be taken into account in the estimation process.
            n_samples (int): Number of measurements done on the unknown quantum state.

        Raises:
            AttributeError: If backend is not a QuantumSimulator.

        Returns:
            ExpectationValues: expectation values for each term in the target operator.
        """
        if alpha > 1 or alpha <= 0:
            raise ValueError("alpha needs to be a value between 0 and 1.")

        if not isinstance(target_operator, IsingOperator):
            raise TypeError("Operator should be of type IsingOperator.")

        distribution = backend.get_bitstring_distribution(circuit, n_samples=n_samples)
        expected_values_per_bitstring = {}

        for bitstring in distribution.distribution_dict:
            expected_value = Measurements(bitstring).get_expectation_values(
                target_operator
            )
            expected_values_per_bitstring[bitstring] = expected_value.values[0]

        sorted_expected_values_per_bitstring_list = sorted(
            expected_values_per_bitstring.items(), key=lambda item: item[1]
        )

        cumulative_prob = 0.0
        cumulative_value = 0.0

        for bitstring, energy in sorted_expected_values_per_bitstring_list:
            prob = distribution.distribution_dict[bitstring]
            if cumulative_prob + prob < alpha:
                cumulative_prob += prob
                cumulative_value += prob * energy
            else:
                cumulative_value += (alpha - cumulative_prob) * energy
                break
        final_value = cumulative_value / alpha
        return ExpectationValues(final_value)
Beispiel #11
0
 def test_evaluate_qubit_operator_list(self):
     # Given
     qubit_op_list = [
         QubitOperator("0.5 [] + 0.5 [Z1]"),
         QubitOperator("0.3 [X1] + 0.2[Y2]"),
     ]
     expectation_values = ExpectationValues([0.5, 0.5, 0.4, 0.6])
     # When
     value_estimate = evaluate_qubit_operator_list(qubit_op_list, expectation_values)
     # Then
     self.assertAlmostEqual(value_estimate.value, 0.74)
def test_concatenate_expectation_values_with_cov_and_corr():
    expectation_values_set = [
        ExpectationValues(
            np.array([1.0, 2.0]),
            estimator_covariances=[np.array([[0.1, 0.2], [0.3, 0.4]])],
            correlations=[np.array([[-0.1, -0.2], [-0.3, -0.4]])],
        ),
        ExpectationValues(
            np.array([3.0, 4.0]),
            estimator_covariances=[np.array([[0.1]]),
                                   np.array([[0.2]])],
            correlations=[np.array([[-0.1]]),
                          np.array([[-0.2]])],
        ),
    ]
    combined_expectation_values = concatenate_expectation_values(
        expectation_values_set)
    assert len(combined_expectation_values.estimator_covariances) == 3
    assert np.allclose(
        combined_expectation_values.estimator_covariances[0],
        [[0.1, 0.2], [0.3, 0.4]],
    )
    assert np.allclose(combined_expectation_values.estimator_covariances[1],
                       [[0.1]])
    assert np.allclose(combined_expectation_values.estimator_covariances[2],
                       [[0.2]])

    assert len(combined_expectation_values.correlations) == 3
    assert np.allclose(
        combined_expectation_values.correlations[0],
        [[-0.1, -0.2], [-0.3, -0.4]],
    )
    assert np.allclose(combined_expectation_values.correlations[1], [[-0.1]])
    assert np.allclose(combined_expectation_values.correlations[2], [[-0.2]])

    assert np.allclose(combined_expectation_values.values,
                       [1.0, 2.0, 3.0, 4.0])
Beispiel #13
0
    def get_exact_expectation_values(self, circuit, qubit_operator, **kwargs):
        if self.n_samples != None:
            raise Exception(
                "Exact expectation values work only for n_samples equal to None."
            )

        expectation_values = []
        qulacs_state = self.get_qulacs_state_from_circuit(circuit)

        for op in qubit_operator:
            qulacs_observable = create_observable_from_openfermion_text(str(op))

            for term_id in range(qulacs_observable.get_term_count()):
                term = qulacs_observable.get_term(term_id)
                expectation_values.append(
                    np.real(term.get_expectation_value(qulacs_state))
                )
        return ExpectationValues(np.array(expectation_values))
def test_expectation_values_io():
    expectation_values = np.array([0.0, 0.0, -1.0])
    correlations = []
    correlations.append(np.array([[1.0, -1.0], [-1.0, 1.0]]))
    correlations.append(np.array([[1.0]]))

    estimator_covariances = []
    estimator_covariances.append(np.array([[0.1, -0.1], [-0.1, 0.1]]))
    estimator_covariances.append(np.array([[0.1]]))

    expectation_values_object = ExpectationValues(expectation_values,
                                                  correlations,
                                                  estimator_covariances)

    save_expectation_values(expectation_values_object,
                            "expectation_values.json")
    expectation_values_object_loaded = load_expectation_values(
        "expectation_values.json")

    assert np.allclose(
        expectation_values_object.values,
        expectation_values_object_loaded.values,
    )
    assert len(expectation_values_object.correlations) == len(
        expectation_values_object_loaded.correlations)
    assert len(expectation_values_object.estimator_covariances) == len(
        expectation_values_object_loaded.estimator_covariances)
    for i in range(len(expectation_values_object.correlations)):
        assert np.allclose(
            expectation_values_object.correlations[i],
            expectation_values_object_loaded.correlations[i],
        )
    for i in range(len(expectation_values_object.estimator_covariances)):
        assert np.allclose(
            expectation_values_object.estimator_covariances[i],
            expectation_values_object_loaded.estimator_covariances[i],
        )

    remove_file_if_exists("expectation_values.json")
Beispiel #15
0
    def get_exact_expectation_values(self, circuit, qubit_operator, **kwargs):
        """
        Calculates the expectation values for given operator, based on the exact quantum state produced by circuit.

        Args:
            circuit (core.circuit.Circuit): quantum circuit to be executed.
            qubit_operator (openfermion): Operator for which we calculate the expectation value.

        Returns:
            ExpectationValues: object representing expectation values for given operator.
        """
        # convert the OpenFermion operator to PennyLane observables
        coeffs, obs = qml.qchem.convert_hamiltonian(qubit_operator).terms
        num_qubits = len(circuit.get_qubits())
        dev = qml.device(self.device, wires=num_qubits)

        ansatz = qml.from_qiskit(circuit.to_qiskit())
        qnodes = qml.map(lambda weights, **kwargs: ansatz(**kwargs),
                         obs,
                         dev,
                         measure="expval")
        return ExpectationValues(
            values=[coeff * qnode([]) for coeff, qnode in zip(coeffs, qnodes)])
class TestEstimatorUtils:
    def test_get_context_selection_circuit_offdiagonal(self):
        term = QubitOperator("X0 Y1")
        circuit, ising_operator = get_context_selection_circuit(term)

        # Need to convert to QubitOperator in order to get matrix representation
        qubit_operator = change_operator_type(ising_operator, QubitOperator)

        target_unitary = qubit_operator_sparse(term)
        transformed_unitary = (
            circuit.to_unitary().conj().T
            @ qubit_operator_sparse(qubit_operator) @ circuit.to_unitary())
        assert np.allclose(target_unitary.todense(), transformed_unitary)

    def test_get_context_selection_circuit_diagonal(self):
        term = QubitOperator("Z2 Z4")
        circuit, ising_operator = get_context_selection_circuit(term)
        assert len(circuit.gates) == 0
        assert ising_operator == change_operator_type(term, IsingOperator)

    def test_get_context_selection_circuit_for_group(self):
        group = QubitOperator("X0 Y1") - 0.5 * QubitOperator((1, "Y"))
        circuit, ising_operator = get_context_selection_circuit_for_group(
            group)

        # Need to convert to QubitOperator in order to get matrix representation
        qubit_operator = change_operator_type(ising_operator, QubitOperator)

        target_unitary = qubit_operator_sparse(group)
        transformed_unitary = (
            circuit.to_unitary().conj().T
            @ qubit_operator_sparse(qubit_operator) @ circuit.to_unitary())

        assert np.allclose(target_unitary.todense(), transformed_unitary)

    def test_perform_context_selection(self):
        target_operators = []
        target_operators.append(10.0 * QubitOperator("Z0"))
        target_operators.append(-3 * QubitOperator("Y0"))
        target_operators.append(1 * QubitOperator("X0"))
        target_operators.append(20 * QubitOperator(""))

        expected_operators = []
        expected_operators.append(10.0 * QubitOperator("Z0"))
        expected_operators.append(-3 * QubitOperator("Z0"))
        expected_operators.append(1 * QubitOperator("Z0"))
        expected_operators.append(20 * QubitOperator(""))

        base_circuit = Circuit(Program(X(0)))
        x_term_circuit = Circuit(Program(RX(np.pi / 2, 0)))
        y_term_circuit = Circuit(Program(RY(-np.pi / 2, 0)))

        expected_circuits = [
            base_circuit,
            base_circuit + x_term_circuit,
            base_circuit + y_term_circuit,
            base_circuit,
        ]

        estimation_tasks = [
            EstimationTask(operator, base_circuit, None)
            for operator in target_operators
        ]

        tasks_with_context_selection = perform_context_selection(
            estimation_tasks)

        for task, expected_circuit, expected_operator in zip(
                tasks_with_context_selection, expected_circuits,
                expected_operators):
            assert task.operator.terms == expected_operator.terms
            assert task.circuit == expected_circuit

    @pytest.fixture()
    def frame_operators(self):
        operators = [
            2.0 * IsingOperator((1, "Z")) * IsingOperator((2, "Z")),
            1.0 * IsingOperator((3, "Z")) * IsingOperator((0, "Z")),
            -1.0 * IsingOperator((2, "Z")),
        ]

        return operators

    @pytest.fixture()
    def circuits(self):
        circuits = [Circuit() for _ in range(5)]
        for circuit in circuits:
            circuit.qubits = [Qubit(i) for i in range(2)]

        circuits[1].gates = [
            Gate("Rx", [circuits[1].qubits[0]], [1.2]),
            Gate("Ry", [circuits[1].qubits[1]], [1.5]),
            Gate("Rx", [circuits[1].qubits[0]], [-0.0002]),
            Gate("Ry", [circuits[1].qubits[1]], [0]),
        ]

        for circuit in circuits[2:]:
            circuit.gates = [
                Gate("Rx", [circuit.qubits[0]], [sympy.Symbol("theta_0")]),
                Gate("Ry", [circuit.qubits[1]], [sympy.Symbol("theta_1")]),
                Gate("Rx", [circuit.qubits[0]], [sympy.Symbol("theta_2")]),
                Gate("Ry", [circuit.qubits[1]], [sympy.Symbol("theta_3")]),
            ]

        return circuits

    @pytest.mark.parametrize(
        "n_samples, target_n_samples_list",
        [
            (100, [100, 100, 100]),
            (17, [17, 17, 17]),
        ],
    )
    def test_allocate_shots_uniformly(
        self,
        frame_operators,
        n_samples,
        target_n_samples_list,
    ):
        allocate_shots = partial(allocate_shots_uniformly,
                                 number_of_shots=n_samples)
        circuit = Circuit()
        estimation_tasks = [
            EstimationTask(operator, circuit, 1)
            for operator in frame_operators
        ]

        new_estimation_tasks = allocate_shots(estimation_tasks)

        for task, target_n_samples in zip(new_estimation_tasks,
                                          target_n_samples_list):
            assert task.number_of_shots == target_n_samples

    @pytest.mark.parametrize(
        "total_n_shots, prior_expectation_values, target_n_samples_list",
        [
            (400, None, [200, 100, 100]),
            (400, ExpectationValues(np.array([0, 0, 0])), [200, 100, 100]),
            (400, ExpectationValues(np.array([1, 0.3, 0.3])), [0, 200, 200]),
        ],
    )
    def test_allocate_shots_proportionally(
        self,
        frame_operators,
        total_n_shots,
        prior_expectation_values,
        target_n_samples_list,
    ):
        allocate_shots = partial(
            allocate_shots_proportionally,
            total_n_shots=total_n_shots,
            prior_expectation_values=prior_expectation_values,
        )
        circuit = Circuit()
        estimation_tasks = [
            EstimationTask(operator, circuit, 1)
            for operator in frame_operators
        ]

        new_estimation_tasks = allocate_shots(estimation_tasks)

        for task, target_n_samples in zip(new_estimation_tasks,
                                          target_n_samples_list):
            assert task.number_of_shots == target_n_samples

    @pytest.mark.parametrize(
        "n_samples",
        [-1],
    )
    def test_allocate_shots_uniformly_invalid_inputs(
        self,
        n_samples,
    ):
        estimation_tasks = []
        with pytest.raises(ValueError):
            allocate_shots_uniformly(estimation_tasks,
                                     number_of_shots=n_samples)

    @pytest.mark.parametrize(
        "total_n_shots, prior_expectation_values",
        [
            (-1, ExpectationValues(np.array([0, 0, 0]))),
        ],
    )
    def test_allocate_shots_proportionally_invalid_inputs(
        self,
        total_n_shots,
        prior_expectation_values,
    ):
        estimation_tasks = []
        with pytest.raises(ValueError):
            allocate_shots = allocate_shots_proportionally(
                estimation_tasks, total_n_shots, prior_expectation_values)

    def test_evaluate_estimation_circuits_no_symbols(
        self,
        circuits,
    ):
        evaluate_circuits = partial(evaluate_estimation_circuits,
                                    symbols_maps=[[] for _ in circuits])
        operator = QubitOperator()
        estimation_tasks = [
            EstimationTask(operator, circuit, 1) for circuit in circuits
        ]

        new_estimation_tasks = evaluate_circuits(estimation_tasks)

        for old_task, new_task in zip(estimation_tasks, new_estimation_tasks):
            assert old_task.circuit == new_task.circuit

    def test_evaluate_estimation_circuits_all_symbols(
        self,
        circuits,
    ):
        symbols_maps = [[
            (sympy.Symbol("theta_0"), 0),
            (sympy.Symbol("theta_1"), 0),
            (sympy.Symbol("theta_2"), 0),
            (sympy.Symbol("theta_3"), 0),
        ] for _ in circuits]
        evaluate_circuits = partial(
            evaluate_estimation_circuits,
            symbols_maps=symbols_maps,
        )
        operator = QubitOperator()
        estimation_tasks = [
            EstimationTask(operator, circuit, 1) for circuit in circuits
        ]

        new_estimation_tasks = evaluate_circuits(estimation_tasks)

        for new_task in new_estimation_tasks:
            assert new_task.circuit.symbolic_params == []

    def test_group_greedily_all_different_groups(self):
        target_operator = 10.0 * QubitOperator("Z0")
        target_operator -= 3.0 * QubitOperator("Y0")
        target_operator += 1.0 * QubitOperator("X0")
        target_operator += 20.0 * QubitOperator("")

        expected_operators = [
            10.0 * QubitOperator("Z0"),
            -3.0 * QubitOperator("Y0"),
            1.0 * QubitOperator("X0"),
            20.0 * QubitOperator(""),
        ]

        circuit = Circuit(Program(X(0)))

        estimation_tasks = [EstimationTask(target_operator, circuit, None)]

        grouped_tasks = group_greedily(estimation_tasks)

        for task, operator in zip(grouped_tasks, expected_operators):
            assert task.operator == operator

        for initial_task, modified_task in zip(estimation_tasks,
                                               grouped_tasks):
            assert modified_task.circuit == initial_task.circuit
            assert modified_task.number_of_shots == initial_task.number_of_shots

    def test_group_greedily_all_comeasureable(self):
        target_operator = 10.0 * QubitOperator("Y0")
        target_operator -= 3.0 * QubitOperator("Y0 Y1")
        target_operator += 1.0 * QubitOperator("Y1")
        target_operator += 20.0 * QubitOperator("Y0 Y1 Y2")

        circuit = Circuit(Program([X(0), X(1), X(2)]))

        estimation_tasks = [EstimationTask(target_operator, circuit, None)]

        grouped_tasks = group_greedily(estimation_tasks)

        assert len(grouped_tasks) == 1
        assert grouped_tasks[0].operator == target_operator

        for initial_task, modified_task in zip(estimation_tasks,
                                               grouped_tasks):
            assert modified_task.circuit == initial_task.circuit
            assert modified_task.number_of_shots == initial_task.number_of_shots

    def test_group_individually(self):
        target_operator = 10.0 * QubitOperator("Z0")
        target_operator += 5.0 * QubitOperator("Z1")
        target_operator -= 3.0 * QubitOperator("Y0")
        target_operator += 1.0 * QubitOperator("X0")
        target_operator += 20.0 * QubitOperator("")

        expected_operator_terms_per_frame = [
            (10.0 * QubitOperator("Z0")).terms,
            (5.0 * QubitOperator("Z1")).terms,
            (-3.0 * QubitOperator("Y0")).terms,
            (1.0 * QubitOperator("X0")).terms,
            (20.0 * QubitOperator("")).terms,
        ]

        circuit = Circuit(Program(X(0)))

        estimation_tasks = [EstimationTask(target_operator, circuit, None)]

        grouped_tasks = group_individually(estimation_tasks)

        assert len(grouped_tasks) == 5

        for task in grouped_tasks:
            assert task.operator.terms in expected_operator_terms_per_frame
 (
     [QubitOperator("[Z0 Z1] + [Z0]"), QubitOperator("[X0 X1] + [X0]")],
     None,
     np.array([2.0, 2.0]),
 ),
 (
     [
         QubitOperator("[Z0 Z1] + [Z0] + []"),
         QubitOperator("[X0 X1] + [X0] + 5 []"),
     ],
     None,
     np.array([2.0, 2.0]),
 ),
 (
     [QubitOperator("[Z0 Z1] + [Z0]"), QubitOperator("[X0 X1] + [X0]")],
     ExpectationValues(np.zeros(4)),
     np.array([2.0, 2.0]),
 ),
 (
     [QubitOperator("2 [Z0 Z1] + 3 [Z0]"), QubitOperator("[X0 X1] + [X0]")],
     ExpectationValues(np.zeros(4)),
     np.array([13.0, 2.0]),
 ),
 (
     [QubitOperator("2[]")],
     ExpectationValues(np.array([1])),
     np.array([0.0]),
 ),
 (
     [
         QubitOperator("2 [Z0 Z1] + 3 [Z0] + 8[]"),
Beispiel #18
0
 def test_sum_expectation_values(self):
     expectation_values = ExpectationValues(np.array([5, -2, 1]))
     total = sum_expectation_values(expectation_values)
     assert np.isclose(total.value, 4)
     assert total.precision is None
Beispiel #19
0
            _ = evaluate_non_measured_estimation_tasks(estimation_tasks)


TEST_CASES_EIGENSTATES = [
    (
        [
            EstimationTask(IsingOperator("Z0"),
                           circuit=Circuit([X(0)]),
                           number_of_shots=10),
            EstimationTask(
                IsingOperator((), coefficient=2.0),
                circuit=Circuit([RY(np.pi / 4)(0)]),
                number_of_shots=30,
            ),
        ],
        [ExpectationValues(np.array([-1])),
         ExpectationValues(np.array([2]))],
    ),
]
TEST_CASES_NONEIGENSTATES = [
    (
        [
            EstimationTask(
                IsingOperator("Z0"),
                circuit=Circuit([H(0)]),
                number_of_shots=1000,
            ),
            EstimationTask(
                IsingOperator("Z0", coefficient=-2),
                circuit=Circuit([RY(np.pi / 4)(0)]),
                number_of_shots=1000,
Beispiel #20
0
 def target_expectation_values(self):
     return [
         ExpectationValues(-1),
         ExpectationValues(0),
         ExpectationValues(2)
     ]
Beispiel #21
0
class TestEstimatorUtils:
    def test_get_context_selection_circuit_for_group(self):
        group = QubitOperator("X0 Y1") - 0.5 * QubitOperator((1, "Y"))
        circuit, ising_operator = get_context_selection_circuit_for_group(
            group)

        # Need to convert to QubitOperator in order to get matrix representation
        qubit_operator = change_operator_type(ising_operator, QubitOperator)

        target_unitary = qubit_operator_sparse(group)
        transformed_unitary = (
            circuit.to_unitary().conj().T
            @ qubit_operator_sparse(qubit_operator) @ circuit.to_unitary())

        assert np.allclose(target_unitary.todense(), transformed_unitary)

    def test_perform_context_selection(self):
        target_operators = []
        target_operators.append(10.0 * QubitOperator("Z0"))
        target_operators.append(-3 * QubitOperator("Y0"))
        target_operators.append(1 * QubitOperator("X0"))
        target_operators.append(20 * QubitOperator(""))

        expected_operators = []
        expected_operators.append(10.0 * QubitOperator("Z0"))
        expected_operators.append(-3 * QubitOperator("Z0"))
        expected_operators.append(1 * QubitOperator("Z0"))
        expected_operators.append(20 * QubitOperator(""))

        base_circuit = Circuit([X(0)])
        x_term_circuit = Circuit([RY(-np.pi / 2)(0)])
        y_term_circuit = Circuit([RX(np.pi / 2)(0)])

        expected_circuits = [
            base_circuit,
            base_circuit + y_term_circuit,
            base_circuit + x_term_circuit,
            base_circuit,
        ]

        estimation_tasks = [
            EstimationTask(operator, base_circuit, None)
            for operator in target_operators
        ]

        tasks_with_context_selection = perform_context_selection(
            estimation_tasks)

        for task, expected_circuit, expected_operator in zip(
                tasks_with_context_selection, expected_circuits,
                expected_operators):
            assert task.operator.terms == expected_operator.terms
            assert task.circuit == expected_circuit

    @pytest.fixture()
    def frame_operators(self):
        operators = [
            2.0 * IsingOperator((1, "Z")) * IsingOperator((2, "Z")),
            1.0 * IsingOperator((3, "Z")) * IsingOperator((0, "Z")),
            -1.0 * IsingOperator((2, "Z")),
        ]

        return operators

    @pytest.fixture()
    def circuits(self):
        circuits = [Circuit() for _ in range(5)]

        circuits[1] += RX(1.2)(0)
        circuits[1] += RY(1.5)(1)
        circuits[1] += RX(-0.0002)(0)
        circuits[1] += RY(0)(1)

        for circuit in circuits[2:]:
            circuit += RX(sympy.Symbol("theta_0"))(0)
            circuit += RY(sympy.Symbol("theta_1"))(1)
            circuit += RX(sympy.Symbol("theta_2"))(0)
            circuit += RY(sympy.Symbol("theta_3"))(1)

        return circuits

    @pytest.mark.parametrize(
        "n_samples, target_n_samples_list",
        [
            (100, [100, 100, 100]),
            (17, [17, 17, 17]),
        ],
    )
    def test_allocate_shots_uniformly(
        self,
        frame_operators,
        n_samples,
        target_n_samples_list,
    ):
        allocate_shots = partial(allocate_shots_uniformly,
                                 number_of_shots=n_samples)
        circuit = Circuit()
        estimation_tasks = [
            EstimationTask(operator, circuit, 1)
            for operator in frame_operators
        ]

        new_estimation_tasks = allocate_shots(estimation_tasks)

        for task, target_n_samples in zip(new_estimation_tasks,
                                          target_n_samples_list):
            assert task.number_of_shots == target_n_samples

    @pytest.mark.parametrize(
        "total_n_shots, prior_expectation_values, target_n_samples_list",
        [
            (400, None, [200, 100, 100]),
            (400, ExpectationValues(np.array([0, 0, 0])), [200, 100, 100]),
            (400, ExpectationValues(np.array([1, 0.3, 0.3])), [0, 200, 200]),
        ],
    )
    def test_allocate_shots_proportionally(
        self,
        frame_operators,
        total_n_shots,
        prior_expectation_values,
        target_n_samples_list,
    ):
        allocate_shots = partial(
            allocate_shots_proportionally,
            total_n_shots=total_n_shots,
            prior_expectation_values=prior_expectation_values,
        )
        circuit = Circuit()
        estimation_tasks = [
            EstimationTask(operator, circuit, 1)
            for operator in frame_operators
        ]

        new_estimation_tasks = allocate_shots(estimation_tasks)

        for task, target_n_samples in zip(new_estimation_tasks,
                                          target_n_samples_list):
            assert task.number_of_shots == target_n_samples

    @pytest.mark.parametrize(
        "n_samples",
        [-1],
    )
    def test_allocate_shots_uniformly_invalid_inputs(
        self,
        n_samples,
    ):
        estimation_tasks = []
        with pytest.raises(ValueError):
            allocate_shots_uniformly(estimation_tasks,
                                     number_of_shots=n_samples)

    @pytest.mark.parametrize(
        "total_n_shots, prior_expectation_values",
        [
            (-1, ExpectationValues(np.array([0, 0, 0]))),
        ],
    )
    def test_allocate_shots_proportionally_invalid_inputs(
        self,
        total_n_shots,
        prior_expectation_values,
    ):
        estimation_tasks = []
        with pytest.raises(ValueError):
            _ = allocate_shots_proportionally(estimation_tasks, total_n_shots,
                                              prior_expectation_values)

    def test_evaluate_estimation_circuits_no_symbols(
        self,
        circuits,
    ):
        evaluate_circuits = partial(evaluate_estimation_circuits,
                                    symbols_maps=[[] for _ in circuits])
        operator = QubitOperator()
        estimation_tasks = [
            EstimationTask(operator, circuit, 1) for circuit in circuits
        ]

        new_estimation_tasks = evaluate_circuits(estimation_tasks)

        for old_task, new_task in zip(estimation_tasks, new_estimation_tasks):
            assert old_task.circuit == new_task.circuit

    def test_evaluate_estimation_circuits_all_symbols(
        self,
        circuits,
    ):
        symbols_maps = [[
            (sympy.Symbol("theta_0"), 0),
            (sympy.Symbol("theta_1"), 0),
            (sympy.Symbol("theta_2"), 0),
            (sympy.Symbol("theta_3"), 0),
        ] for _ in circuits]
        evaluate_circuits = partial(
            evaluate_estimation_circuits,
            symbols_maps=symbols_maps,
        )
        operator = QubitOperator()
        estimation_tasks = [
            EstimationTask(operator, circuit, 1) for circuit in circuits
        ]

        new_estimation_tasks = evaluate_circuits(estimation_tasks)

        for new_task in new_estimation_tasks:
            assert len(new_task.circuit.free_symbols) == 0

    def test_group_greedily_all_different_groups(self):
        target_operator = 10.0 * QubitOperator("Z0")
        target_operator -= 3.0 * QubitOperator("Y0")
        target_operator += 1.0 * QubitOperator("X0")
        target_operator += 20.0 * QubitOperator("")

        expected_operators = [
            10.0 * QubitOperator("Z0"),
            -3.0 * QubitOperator("Y0"),
            1.0 * QubitOperator("X0"),
            20.0 * QubitOperator(""),
        ]

        circuit = Circuit([X(0)])

        estimation_tasks = [EstimationTask(target_operator, circuit, None)]

        grouped_tasks = group_greedily(estimation_tasks)

        for task, operator in zip(grouped_tasks, expected_operators):
            assert task.operator == operator

        for initial_task, modified_task in zip(estimation_tasks,
                                               grouped_tasks):
            assert modified_task.circuit == initial_task.circuit
            assert modified_task.number_of_shots == initial_task.number_of_shots

    def test_group_greedily_all_comeasureable(self):
        target_operator = 10.0 * QubitOperator("Y0")
        target_operator -= 3.0 * QubitOperator("Y0 Y1")
        target_operator += 1.0 * QubitOperator("Y1")
        target_operator += 20.0 * QubitOperator("Y0 Y1 Y2")

        circuit = Circuit([X(0), X(1), X(2)])

        estimation_tasks = [EstimationTask(target_operator, circuit, None)]

        grouped_tasks = group_greedily(estimation_tasks)

        assert len(grouped_tasks) == 1
        assert grouped_tasks[0].operator == target_operator

        for initial_task, modified_task in zip(estimation_tasks,
                                               grouped_tasks):
            assert modified_task.circuit == initial_task.circuit
            assert modified_task.number_of_shots == initial_task.number_of_shots

    def test_group_individually(self):
        target_operator = 10.0 * QubitOperator("Z0")
        target_operator += 5.0 * QubitOperator("Z1")
        target_operator -= 3.0 * QubitOperator("Y0")
        target_operator += 1.0 * QubitOperator("X0")
        target_operator += 20.0 * QubitOperator("")

        expected_operator_terms_per_frame = [
            (10.0 * QubitOperator("Z0")).terms,
            (5.0 * QubitOperator("Z1")).terms,
            (-3.0 * QubitOperator("Y0")).terms,
            (1.0 * QubitOperator("X0")).terms,
            (20.0 * QubitOperator("")).terms,
        ]

        circuit = Circuit([X(0)])

        estimation_tasks = [EstimationTask(target_operator, circuit, None)]

        grouped_tasks = group_individually(estimation_tasks)

        assert len(grouped_tasks) == 5

        for task in grouped_tasks:
            assert task.operator.terms in expected_operator_terms_per_frame

    @pytest.mark.parametrize(
        ",".join([
            "estimation_tasks",
            "ref_estimation_tasks_to_measure",
            "ref_non_measured_estimation_tasks",
            "ref_indices_to_measure",
            "ref_non_measured_indices",
        ]),
        [
            (
                [
                    EstimationTask(IsingOperator("2[Z0] + 3 [Z1 Z2]"),
                                   Circuit([X(0)]), 10),
                    EstimationTask(
                        IsingOperator("2[Z0] + 3 [Z1 Z2] + 4[]"),
                        Circuit([RZ(np.pi / 2)(0)]),
                        1000,
                    ),
                    EstimationTask(
                        IsingOperator("4[Z3]"),
                        Circuit([RY(np.pi / 2)(0)]),
                        17,
                    ),
                ],
                [
                    EstimationTask(IsingOperator("2[Z0] + 3 [Z1 Z2]"),
                                   Circuit([X(0)]), 10),
                    EstimationTask(
                        IsingOperator("2[Z0] + 3 [Z1 Z2] + 4 []"),
                        Circuit([RZ(np.pi / 2)(0)]),
                        1000,
                    ),
                    EstimationTask(
                        IsingOperator("4[Z3]"),
                        Circuit([RY(np.pi / 2)(0)]),
                        17,
                    ),
                ],
                [],
                [0, 1, 2],
                [],
            ),
            (
                [
                    EstimationTask(IsingOperator("2[Z0] + 3 [Z1 Z2]"),
                                   Circuit([X(0)]), 10),
                    EstimationTask(
                        IsingOperator("4[] "),
                        Circuit([RZ(np.pi / 2)(0)]),
                        1000,
                    ),
                    EstimationTask(
                        IsingOperator("4[Z3]"),
                        Circuit([RY(np.pi / 2)(0)]),
                        17,
                    ),
                ],
                [
                    EstimationTask(IsingOperator("2[Z0] + 3 [Z1 Z2]"),
                                   Circuit([X(0)]), 10),
                    EstimationTask(
                        IsingOperator("4[Z3]"),
                        Circuit([RY(np.pi / 2)(0)]),
                        17,
                    ),
                ],
                [
                    EstimationTask(IsingOperator("4[]"),
                                   Circuit([RZ(np.pi / 2)(0)]), 1000)
                ],
                [0, 2],
                [1],
            ),
            (
                [
                    EstimationTask(IsingOperator("- 3 []"), Circuit([X(0)]),
                                   0),
                    EstimationTask(
                        IsingOperator("2[Z0] + 3 [Z1 Z2] + 4[]"),
                        Circuit([RZ(np.pi / 2)(0)]),
                        1000,
                    ),
                    EstimationTask(
                        IsingOperator("4[Z3]"),
                        Circuit([RY(np.pi / 2)(0)]),
                        17,
                    ),
                ],
                [
                    EstimationTask(
                        IsingOperator("2[Z0] + 3 [Z1 Z2] + 4 []"),
                        Circuit([RZ(np.pi / 2)(0)]),
                        1000,
                    ),
                    EstimationTask(
                        IsingOperator("4[Z3]"),
                        Circuit([RY(np.pi / 2)(0)]),
                        17,
                    ),
                ],
                [
                    EstimationTask(IsingOperator("- 3 []"), Circuit([X(0)]),
                                   0),
                ],
                [1, 2],
                [0],
            ),
            (
                [
                    EstimationTask(IsingOperator("- 3 []"), Circuit([X(0)]),
                                   0),
                    EstimationTask(
                        IsingOperator("2[Z0] + 3 [Z1 Z2] + 4[]"),
                        Circuit([RZ(np.pi / 2)(0)]),
                        1000,
                    ),
                    EstimationTask(
                        IsingOperator("4[Z3]"),
                        Circuit([RY(np.pi / 2)(0)]),
                        0,
                    ),
                ],
                [
                    EstimationTask(
                        IsingOperator("2[Z0] + 3 [Z1 Z2] + 4 []"),
                        Circuit([RZ(np.pi / 2)(0)]),
                        1000,
                    ),
                ],
                [
                    EstimationTask(IsingOperator("- 3 []"), Circuit([X(0)]),
                                   0),
                    EstimationTask(
                        IsingOperator("4[Z3]"),
                        Circuit([RY(np.pi / 2)(0)]),
                        0,
                    ),
                ],
                [1],
                [0, 2],
            ),
        ],
    )
    def test_split_estimation_tasks_to_measure(
        self,
        estimation_tasks,
        ref_estimation_tasks_to_measure,
        ref_non_measured_estimation_tasks,
        ref_indices_to_measure,
        ref_non_measured_indices,
    ):

        (
            estimation_task_to_measure,
            non_measured_estimation_tasks,
            indices_to_measure,
            indices_for_non_measureds,
        ) = split_estimation_tasks_to_measure(estimation_tasks)

        assert estimation_task_to_measure == ref_estimation_tasks_to_measure
        assert non_measured_estimation_tasks == ref_non_measured_estimation_tasks
        assert indices_to_measure == ref_indices_to_measure
        assert ref_non_measured_indices == indices_for_non_measureds

    @pytest.mark.parametrize(
        "estimation_tasks,ref_expectation_values",
        [
            (
                [
                    EstimationTask(
                        IsingOperator("4[] "),
                        Circuit([RZ(np.pi / 2)(0)]),
                        1000,
                    ),
                ],
                [
                    ExpectationValues(
                        np.asarray([4.0]),
                        correlations=[np.asarray([[0.0]])],
                        estimator_covariances=[np.asarray([[0.0]])],
                    ),
                ],
            ),
            (
                [
                    EstimationTask(IsingOperator("- 2.5 [] - 0.5 []"),
                                   Circuit([X(0)]), 0),
                    EstimationTask(IsingOperator("0.001[] "),
                                   Circuit([RZ(np.pi / 2)(0)]), 2),
                    EstimationTask(
                        IsingOperator("2.5 [Z1] + 1.0 [Z2 Z3]"),
                        Circuit([RY(np.pi / 2)(0)]),
                        0,
                    ),
                ],
                [
                    ExpectationValues(
                        np.asarray([-3.0]),
                        correlations=[np.asarray([[0.0]])],
                        estimator_covariances=[np.asarray([[0.0]])],
                    ),
                    ExpectationValues(
                        np.asarray([0.001]),
                        correlations=[np.asarray([[0.0]])],
                        estimator_covariances=[np.asarray([[0.0]])],
                    ),
                    ExpectationValues(
                        np.asarray([0.0]),
                        correlations=[np.asarray([[0.0]])],
                        estimator_covariances=[np.asarray([[0.0]])],
                    ),
                ],
            ),
        ],
    )
    def test_evaluate_non_measured_estimation_tasks(self, estimation_tasks,
                                                    ref_expectation_values):

        expectation_values = evaluate_non_measured_estimation_tasks(
            estimation_tasks)

        for ex_val, ref_ex_val in zip(expectation_values,
                                      ref_expectation_values):
            assert np.allclose(ex_val.values, ref_ex_val.values)
            assert np.allclose(ex_val.correlations, ref_ex_val.correlations)
            assert np.allclose(ex_val.estimator_covariances,
                               ref_ex_val.estimator_covariances)

    @pytest.mark.parametrize(
        "estimation_tasks",
        [
            ([
                EstimationTask(IsingOperator("- 2.5 [] - 0.5 [Z1]"),
                               Circuit([X(0)]), 1),
            ]),
            ([
                EstimationTask(
                    IsingOperator("0.001 [Z0]"),
                    Circuit([RZ(np.pi / 2)(0)]),
                    0,
                ),
                EstimationTask(IsingOperator("2.0[] "),
                               Circuit([RZ(np.pi / 2)(0)]), 2),
                EstimationTask(
                    IsingOperator("1.5 [Z0 Z1]"),
                    Circuit([RY(np.pi / 2)(0)]),
                    10,
                ),
            ]),
        ],
    )
    def test_evaluate_non_measured_estimation_tasks_fails_with_non_zero_shots(
            self, estimation_tasks):
        with pytest.raises(RuntimeError):
            _ = evaluate_non_measured_estimation_tasks(estimation_tasks)