def target_unitary(self, beta, gamma, symbols_map):
     target_circuit = Circuit()
     target_circuit += H(0)
     target_circuit += H(1)
     target_circuit += RZ(2 * gamma)(0)
     target_circuit += RZ(2 * gamma)(1)
     target_circuit += RX(2 * beta)(0)
     target_circuit += RX(2 * beta)(1)
     return target_circuit.bind(symbols_map).to_unitary()
Beispiel #2
0
def time_evolution_for_term(
        term: QubitOperator, time: Union[float,
                                         sympy.Expr]) -> circuits.Circuit:
    """Evolves a Pauli term for a given time and returns a circuit representing it.
    Based on section 4 from https://arxiv.org/abs/1001.3855 .
    Args:
        term: Pauli term to be evolved
        time: time of evolution
    Returns:
        Circuit: Circuit representing evolved term.
    """

    if len(term.terms) != 1:
        raise ValueError("This function works only on a single term.")
    term_components = list(term.terms.keys())[0]
    base_changes = []
    base_reversals = []
    cnot_gates = []
    central_gate = None
    term_types = [component[1] for component in term_components]
    qubit_indices = [component[0] for component in term_components]
    coefficient = list(term.terms.values())[0]

    circuit = circuits.Circuit()

    # If constant term, return empty circuit.
    if not term_components:
        return circuit

    for i, (term_type, qubit_id) in enumerate(zip(term_types, qubit_indices)):
        if term_type == "X":
            base_changes.append(H(qubit_id))
            base_reversals.append(H(qubit_id))
        elif term_type == "Y":
            base_changes.append(RX(np.pi / 2)(qubit_id))
            base_reversals.append(RX(-np.pi / 2)(qubit_id))
        if i == len(term_components) - 1:
            central_gate = RZ(2 * time * coefficient)(qubit_id)
        else:
            cnot_gates.append(CNOT(qubit_id, qubit_indices[i + 1]))

    for gate in base_changes:
        circuit += gate

    for gate in cnot_gates:
        circuit += gate

    circuit += central_gate

    for gate in reversed(cnot_gates):
        circuit += gate

    for gate in base_reversals:
        circuit += gate

    return circuit
def create_2_qubit_x_operator(qubit1: int, qubit2: int, param):
    return Circuit(
        [
            H(qubit1),
            H(qubit2),
            CNOT(qubit1, qubit2),
            RZ(2 * param)(qubit2),
            CNOT(qubit1, qubit2),
            H(qubit1),
            H(qubit2),
        ]
    )
def _validate_constant_terms_are_included_in_output(
    estimator: EstimateExpectationValues, ):
    estimation_tasks = [
        EstimationTask(IsingOperator("Z0"), Circuit([H(0)]), 10000),
        EstimationTask(
            IsingOperator("Z0") + IsingOperator("[]", 19.971997),
            Circuit([H(0)]),
            10000,
        ),
    ]

    expectation_values = estimator(
        backend=_backend,
        estimation_tasks=estimation_tasks,
    )

    return not np.array_equal(expectation_values[0].values,
                              expectation_values[1].values)
Beispiel #5
0
    def test_get_wavefunction_seed(self):
        # Given
        circuit = Circuit([H(0), CNOT(0, 1), CNOT(1, 2)])
        backend1 = ForestSimulator("wavefunction-simulator", seed=5324)
        backend2 = ForestSimulator("wavefunction-simulator", seed=5324)

        # When
        wavefunction1 = backend1.get_wavefunction(circuit)
        wavefunction2 = backend2.get_wavefunction(circuit)

        # Then
        for (ampl1, ampl2) in zip(wavefunction1.amplitudes,
                                  wavefunction2.amplitudes):
            assert ampl1 == ampl2
    def test_cvar_estimator_returns_correct_values(self, estimator, backend,
                                                   operator):
        # Given
        estimation_tasks = [EstimationTask(operator, Circuit([H(0)]), 10000)]
        if estimator.alpha <= 0.5:
            target_value = -1
        else:
            target_value = (-1 * 0.5 + 1 *
                            (estimator.alpha - 0.5)) / estimator.alpha

        # When
        expectation_values = estimator(
            backend=backend,
            estimation_tasks=estimation_tasks,
        )

        # Then
        assert expectation_values[0].values == pytest.approx(target_value,
                                                             abs=2e-1)
Beispiel #7
0
    def test_gibbs_estimator_returns_correct_values(self, estimator, backend,
                                                    operator):
        # Given
        estimation_tasks = [EstimationTask(operator, Circuit([H(0)]), 10000)]

        expval_0 = np.exp(1 *
                          -estimator.alpha)  # Expectation value of bitstring 0
        expval_1 = np.exp(-1 *
                          -estimator.alpha)  # Expectation value of bitstring 1

        # Target value is the -log of the mean of the expectation values of the 2 bitstrings
        target_value = -np.log((expval_1 + expval_0) / 2)

        # When
        expectation_values = estimator(
            backend=backend,
            estimation_tasks=estimation_tasks,
        )

        # Then
        assert expectation_values[0].values == pytest.approx(target_value,
                                                             abs=2e-2)
Beispiel #8
0
class TestCreatingUnitaryFromCircuit:
    @pytest.fixture
    def cirq_unitaries(self):
        """
        Note: We decided to go with file-based approach after extracting cirq
        from z-quantum-core and not being able to use `export_to_cirq` anymore.
        """
        path_to_array = ("/".join(__file__.split("/")[:-1]) +
                         "/hardcoded_cirq_unitaries.npy")
        return np.load(path_to_array, allow_pickle=True)

    @pytest.mark.parametrize(
        "circuit, unitary_index",
        [
            # Identity gates in some test cases below are used so that comparable
            # Cirq circuits have the same number of qubits as Zquantum ones.
            (Circuit([RX(np.pi / 5)(0)]), 0),
            (Circuit([RY(np.pi / 2)(0), RX(np.pi / 5)(0)]), 1),
            (
                Circuit(
                    [I(1),
                     I(2),
                     I(3),
                     I(4),
                     RX(np.pi / 5)(0),
                     XX(0.1)(5, 0)]),
                2,
            ),
            (
                Circuit([
                    XY(np.pi).controlled(1)(3, 1, 4),
                    RZ(0.1 * np.pi).controlled(2)(0, 2, 1),
                ]),
                3,
            ),
            (
                Circuit(
                    [H(1),
                     YY(0.1).controlled(1)(0, 1, 2),
                     X(2),
                     Y(3),
                     Z(4)]),
                4,
            ),
        ],
    )
    def test_without_free_params_gives_the_same_result_as_cirq(
            self, circuit, unitary_index, cirq_unitaries):
        zquantum_unitary = circuit.to_unitary()

        assert isinstance(
            zquantum_unitary, np.ndarray
        ), "Unitary constructed from non-parameterized circuit is not a numpy array."

        np.testing.assert_array_almost_equal(zquantum_unitary,
                                             cirq_unitaries[unitary_index])

    def test_commutes_with_parameter_substitution(self):
        theta, gamma = sympy.symbols("theta, gamma")
        circuit = Circuit([
            RX(theta / 2)(0),
            X(1),
            RY(gamma / 4).controlled(1)(1, 2),
            YY(0.1)(0, 4)
        ])

        symbols_map = {theta: 0.1, gamma: 0.5}
        parameterized_unitary = circuit.to_unitary()
        unitary = circuit.bind(symbols_map).to_unitary()

        np.testing.assert_array_almost_equal(
            np.array(parameterized_unitary.subs(symbols_map), dtype=complex),
            unitary)
        assert contract(estimator)
"""

import numpy as np
from openfermion import IsingOperator
from zquantum.core.circuits import RX, RY, RZ, Circuit, H
from zquantum.core.interfaces.estimation import (
    EstimateExpectationValues,
    EstimationTask,
)
from zquantum.core.symbolic_simulator import SymbolicSimulator

_backend = SymbolicSimulator(seed=1997)

_estimation_tasks = [
    EstimationTask(IsingOperator("Z0"), Circuit([H(0)]), 10000),
    EstimationTask(
        IsingOperator("Z0") + IsingOperator("Z1") + IsingOperator("Z2"),
        Circuit([H(0), RX(np.pi / 3)(0), H(2)]),
        10000,
    ),
    EstimationTask(
        IsingOperator("Z0") + IsingOperator("Z1", 4),
        Circuit([
            RX(np.pi)(0),
            RY(0.12)(1),
            RZ(np.pi / 3)(1),
            RY(1.9213)(0),
        ]),
        10000,
    ),
Beispiel #10
0
            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,
            ),
        ],
        [
            ExpectationValues(np.array([0])),
            ExpectationValues(np.array([-2 * (np.cos(np.pi / 8)**2 - 0.5) * 2
                                        ])),
        ],
    ),
]
def create_x_operator(qubit: int, param):
    return Circuit([H(qubit), RZ(2 * param)(qubit), H(qubit)])