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 test_gives_the_same_unitary_as_original_gate_up_to_global_phase(
        self, gate_to_be_decomposed, target_qubits
    ):
        circuit = Circuit([gate_to_be_decomposed(*target_qubits)])
        decomposed_circuit = decompose_zquantum_circuit(circuit, DECOMPOSITION_RULES)

        assert _is_scaled_identity(
            circuit.to_unitary() @ np.linalg.inv(decomposed_circuit.to_unitary()),
        )
Beispiel #3
0
    def test_create_circuits_from_qubit_operator(self):
        # Initialize target
        circuit1 = Circuit([Z(0), X(1)])
        circuit2 = Circuit([Y(0), Z(1)])

        # Given
        qubit_op = QubitOperator("Z0 X1") + QubitOperator("Y0 Z1")

        # When
        pauli_circuits = create_circuits_from_qubit_operator(qubit_op)

        # Then
        self.assertEqual(pauli_circuits[0], circuit1)
        self.assertEqual(pauli_circuits[1], circuit2)
Beispiel #4
0
 def estimation_tasks(self):
     task_1 = EstimationTask(IsingOperator("Z0"),
                             circuit=Circuit([X(0)]),
                             number_of_shots=10)
     task_2 = EstimationTask(
         IsingOperator("Z0"),
         circuit=Circuit([RY(np.pi / 2)(0)]),
         number_of_shots=20,
     )
     task_3 = EstimationTask(
         IsingOperator((), coefficient=2.0),
         circuit=Circuit([RY(np.pi / 4)(0)]),
         number_of_shots=30,
     )
     return [task_1, task_2, task_3]
def create_X_target_unitary(number_of_params, k_body_depth=1):
    thetas = create_thetas(number_of_params)
    symbols_map = create_symbols_map(number_of_params)

    target_circuit = Circuit()
    # Add an x operator to every qubit
    for i in range(3):
        target_circuit += create_x_operator(i, thetas[i])

    if k_body_depth == 2:
        target_circuit += create_2_qubit_x_operator(0, 1, thetas[3])
        target_circuit += create_2_qubit_x_operator(0, 2, thetas[4])
        target_circuit += create_2_qubit_x_operator(1, 2, thetas[5])

    return target_circuit.bind(symbols_map).to_unitary()
Beispiel #6
0
    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)
    def _generate_circuit(self,
                          params: Optional[np.ndarray] = None) -> Circuit:
        """Returns a parametrizable circuit represention of the ansatz.
        By convention the initial state is taken to be the |+..+> state and is
        evolved first under the cost Hamiltonian and then the mixer Hamiltonian.
        Args:
            params: parameters of the circuit.
        """
        if params is not None:
            Warning(
                "This method retuns a parametrizable circuit, params will be ignored."
            )
        circuit = Circuit()

        # Prepare initial state
        circuit += create_layer_of_gates(self.number_of_qubits, H)

        # Add time evolution layers
        cost_circuit = time_evolution(
            change_operator_type(self._cost_hamiltonian, QubitOperator),
            sympy.Symbol(f"gamma"),
        )
        mixer_circuit = time_evolution(self._mixer_hamiltonian,
                                       sympy.Symbol(f"beta"))
        for i in range(self.number_of_layers):
            circuit += cost_circuit.bind(
                {sympy.Symbol(f"gamma"): sympy.Symbol(f"gamma_{i}")})
            circuit += mixer_circuit.bind(
                {sympy.Symbol(f"beta"): sympy.Symbol(f"beta_{i}")})

        return circuit
Beispiel #8
0
    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
Beispiel #9
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_ansatz_circuit_two_layers(self, n_qubits, topology):
        # Given
        number_of_layers = 2
        ansatz = QCBMAnsatz(
            number_of_layers=number_of_layers,
            number_of_qubits=n_qubits,
            topology=topology,
        )

        params = [
            np.random.rand(2 * n_qubits),
            np.random.rand(int((n_qubits * (n_qubits - 1)) / 2)),
        ]

        expected_circuit = Circuit([
            # First layer
            *[RX(params[0][i])(i) for i in range(n_qubits)],
            *[RZ(params[0][i + n_qubits])(i) for i in range(n_qubits)],
            # Second layer
            *get_entangling_layer(params[1], n_qubits, XX,
                                  topology).operations,
        ])

        params = np.concatenate(params)

        # When
        circuit = ansatz.get_executable_circuit(params)

        # Then
        assert circuit == expected_circuit
    def _generate_circuit(self,
                          params: Optional[np.ndarray] = None) -> Circuit:
        """Returns a parametrizable circuit represention of the ansatz.
        Args:
            params: parameters of the circuit.
        """
        if params is not None:
            Warning(
                "This method retuns a parametrizable circuit, params will be ignored."
            )
        circuit = Circuit()

        # Prepare initial state
        circuit += create_layer_of_gates(self.number_of_qubits, RY,
                                         self._thetas)

        # Add time evolution layers
        cost_circuit = time_evolution(
            change_operator_type(self._cost_hamiltonian, QubitOperator),
            sympy.Symbol(f"gamma"),
        )
        for i in range(self.number_of_layers):
            circuit += cost_circuit.bind(
                {sympy.Symbol(f"gamma"): sympy.Symbol(f"gamma_{i}")})
            circuit += create_layer_of_gates(self.number_of_qubits, RY,
                                             -self._thetas)
            circuit += create_layer_of_gates(
                self.number_of_qubits,
                RZ,
                [-2 * sympy.Symbol(f"beta_{i}")] * self.number_of_qubits,
            )
            circuit += create_layer_of_gates(self.number_of_qubits, RY,
                                             self._thetas)

        return circuit
def _validate_expectation_value_includes_coefficients(
    estimator: EstimateExpectationValues, ):
    estimation_tasks = [
        EstimationTask(IsingOperator("Z0"), Circuit([RX(np.pi / 3)(0)]),
                       10000),
        EstimationTask(IsingOperator("Z0", 19.971997),
                       Circuit([RX(np.pi / 3)(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 #13
0
 def test_exact_expectation_values_without_wavefunction_simulator(
         self, backend):
     if backend.device_name != "wavefunction-simulator":
         operator = QubitOperator("Z0 Z1")
         circuit = Circuit([X(0), X(1)])
         with pytest.raises(Exception):
             backend.get_exact_expectation_values(circuit, operator)
Beispiel #14
0
def get_entangling_layer_graph_topology(
    params: np.ndarray,
    n_qubits: int,
    entangling_gate: GatePrototype,
    adjacency_matrix: np.ndarray,
) -> Circuit:
    """Builds a circuit representing an entangling layer according to a general graph topology.

    Args:
        params: parameters of the circuit.
        n_qubits: number of qubits in the circuit.
        entangling_gate: gate specification for the entangling layer.
        adjacency_matrix: adjacency matrix for the entangling layer.
    """
    assert adjacency_matrix.shape[0] == adjacency_matrix.shape[1] == n_qubits

    circuit = Circuit()
    i = 0
    for qubit1_index in range(n_qubits - 1):
        for qubit2_index in range(qubit1_index + 1, n_qubits):
            if (adjacency_matrix[qubit1_index][qubit2_index]
                    or adjacency_matrix[qubit2_index][qubit1_index]):
                circuit += entangling_gate(params[i])(qubit1_index,
                                                      qubit2_index)
                i += 1
    return circuit
def create_XZ1_target_unitary(number_of_params, k_body_depth=1):
    thetas = create_thetas(number_of_params)
    symbols_map = create_symbols_map(number_of_params)

    target_circuit = Circuit()
    target_circuit += create_x_operator(0, thetas[0])
    target_circuit += RZ(2 * thetas[1])(0)

    target_circuit += create_x_operator(1, thetas[2])
    target_circuit += RZ(2 * thetas[3])(1)

    if k_body_depth == 2:
        target_circuit += create_2_qubit_x_operator(0, 1, thetas[4])
        target_circuit += CNOT(0, 1)
        target_circuit += RZ(2 * thetas[5])(1)
        target_circuit += CNOT(0, 1)

    return target_circuit.bind(symbols_map).to_unitary()
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)
    def test_ansatz_circuit_nine_layers(self, n_qubits, topology):
        # Given
        number_of_layers = 9
        ansatz = QCBMAnsatz(
            number_of_layers=number_of_layers,
            number_of_qubits=n_qubits,
            topology=topology,
        )
        params = [
            np.random.rand(2 * n_qubits),
            np.random.rand(int((n_qubits * (n_qubits - 1)) / 2)),
            np.random.rand(2 * n_qubits),
            np.random.rand(int((n_qubits * (n_qubits - 1)) / 2)),
            np.random.rand(2 * n_qubits),
            np.random.rand(int((n_qubits * (n_qubits - 1)) / 2)),
            np.random.rand(3 * n_qubits),
            np.random.rand(int((n_qubits * (n_qubits - 1)) / 2)),
            np.random.rand(2 * n_qubits),
        ]
        expected_circuit = Circuit([
            # First layer
            *[RX(params[0][i])(i) for i in range(n_qubits)],
            *[RZ(params[0][i + n_qubits])(i) for i in range(n_qubits)],
            # Second layer
            *get_entangling_layer(params[1], n_qubits, XX,
                                  topology).operations,
            # Third layer
            *[RX(params[2][i])(i) for i in range(n_qubits)],
            *[RZ(params[2][i + n_qubits])(i) for i in range(n_qubits)],
            # Fouth layer
            *get_entangling_layer(params[3], n_qubits, XX,
                                  topology).operations,
            # Fifth layer
            *[RX(params[4][i])(i) for i in range(n_qubits)],
            *[RZ(params[4][i + n_qubits])(i) for i in range(n_qubits)],
            # Sixth layer
            *get_entangling_layer(params[5], n_qubits, XX,
                                  topology).operations,
            # Seventh layer
            *[RX(params[6][i])(i) for i in range(n_qubits)],
            *[RZ(params[6][i + n_qubits])(i) for i in range(n_qubits)],
            *[RX(params[6][i + 2 * n_qubits])(i) for i in range(n_qubits)],
            # Eigth layer
            *get_entangling_layer(params[7], n_qubits, XX,
                                  topology).operations,
            # Ningth layer
            *[RZ(params[8][i])(i) for i in range(n_qubits)],
            *[RX(params[8][i + n_qubits])(i) for i in range(n_qubits)],
        ])

        params = np.concatenate(params)

        # When
        circuit = ansatz.get_executable_circuit(params)

        # Then
        assert circuit == expected_circuit
Beispiel #18
0
    def test_U3_decomposition_comprises_only_rotations(
        self, gate_to_be_decomposed, target_qubits
    ):
        circuit = Circuit([gate_to_be_decomposed(*target_qubits)])
        decomposed_circuit = decompose_zquantum_circuit(circuit, DECOMPOSITION_RULES)

        assert all(
            isinstance(op, GateOperation) and op.gate.name in ("RZ", "RY")
            for op in decomposed_circuit.operations
        )
    def test_run_circuitset_and_measure_n_samples(self, backend):
        # We override the base test because the qiskit integration may return
        # more samples than requested due to the fact that each circuit in a
        # batch must have the same number of measurements.

        # Note: this test may fail with noisy devices
        # Given
        backend.number_of_circuits_run = 0
        backend.number_of_jobs_run = 0

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

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

        n_samples = [100, 105]

        # When
        backend.n_samples = n_samples
        measurements_set = backend.run_circuitset_and_measure(
            [first_circuit, second_circuit], n_samples)

        # Then (since SPAM error could result in unexpected bitstrings, we make sure the
        # most common bitstring is the one we expect)
        counts = measurements_set[0].get_counts()
        assert max(counts, key=counts.get) == "001"
        counts = measurements_set[1].get_counts()
        assert max(counts, key=counts.get) == "111"

        assert len(measurements_set[0].bitstrings) >= n_samples[0]
        assert len(measurements_set[1].bitstrings) >= n_samples[1]

        assert backend.number_of_circuits_run == 2
Beispiel #20
0
def create_target_unitary(thetas, number_of_layers):
    target_circuit = Circuit()
    target_circuit += RY(thetas[0])(0)
    target_circuit += RY(thetas[1])(1)
    betas = create_betas(number_of_layers)
    gammas = create_gammas(number_of_layers)
    symbols_map = create_symbols_map(number_of_layers)
    for layer_id in range(number_of_layers):
        beta = betas[layer_id]
        gamma = gammas[layer_id]
        target_circuit += RZ(2.0 * gamma)(0)
        target_circuit += RZ(2.0 * gamma)(1)
        target_circuit += RY(-thetas[0])(0)
        target_circuit += RY(-thetas[1])(1)
        target_circuit += RZ(-2.0 * beta)(0)
        target_circuit += RZ(-2.0 * beta)(1)
        target_circuit += RY(thetas[0])(0)
        target_circuit += RY(thetas[1])(1)

    return target_circuit.bind(symbols_map).to_unitary()
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),
        ]
    )
Beispiel #22
0
 def test_build_hartree_fock_circuit_jordan_wigner(self):
     number_of_qubits = 4
     number_of_alpha_electrons = 1
     number_of_beta_electrons = 1
     transformation = "Jordan-Wigner"
     expected_circuit = Circuit([X(0), X(1)], n_qubits=number_of_qubits)
     actual_circuit = build_hartree_fock_circuit(
         number_of_qubits,
         number_of_alpha_electrons,
         number_of_beta_electrons,
         transformation,
     )
     assert actual_circuit == expected_circuit
Beispiel #23
0
 def test_build_hartree_fock_circuit_bravyi_kitaev(self):
     number_of_qubits = 4
     number_of_alpha_electrons = 1
     number_of_beta_electrons = 1
     transformation = "Bravyi-Kitaev"
     expected_circuit = Circuit([X(0)], n_qubits=number_of_qubits)
     actual_circuit = build_hartree_fock_circuit(
         number_of_qubits,
         number_of_alpha_electrons,
         number_of_beta_electrons,
         transformation,
     )
     assert actual_circuit == expected_circuit
Beispiel #24
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
Beispiel #25
0
 def get_qulacs_state_from_circuit(self, circuit: Circuit):
     qulacs_state = qulacs.QuantumState(circuit.n_qubits)
     for executable, operations_group in itertools.groupby(
             circuit.operations, self.can_be_executed_natively):
         if executable:
             qulacs_circuit = convert_to_qulacs(
                 Circuit(operations_group, circuit.n_qubits))
             qulacs_circuit.update_quantum_state(qulacs_state)
         else:
             wavefunction = qulacs_state.get_vector()
             for operation in operations_group:
                 wavefunction = operation.apply(wavefunction)
             qulacs_state.load(wavefunction)
     return qulacs_state
Beispiel #26
0
    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
def _zquantum_exponentiate_hamiltonian(hamiltonian, time, trotter_order):
    ops = []
    for term in hamiltonian.get_operators():
        mat = _zquantum_exponentiate_qubit_hamiltonian_term(
            term, time, trotter_order)
        ops.append(
            circuits.CustomGateDefinition(
                gate_name="custom_a",
                matrix=sympy.Matrix(mat),
                params_ordering=(),
            )()(0, 1))

    circuit = Circuit(operations=ops * trotter_order)

    return circuit
Beispiel #28
0
    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
    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 #30
0
    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