Exemple #1
0
def build_farhi_qaoa_circuit_template(hamiltonian):
    """Constructs a circuit template for a QAOA ansatz.

    Args:
        hamiltonians (list): a list of zquantum.core.qubitoperator.QubitOperator objects

    Returns:
        circuit_template (dict): dictionary describing the ansatz
    """

    n_qubits = count_qubits(hamiltonian)

    diffusion_op = QubitOperator()
    for i in range(n_qubits):
        diffusion_op += QubitOperator((i, 'X'))

    ansatz = {
        'ansatz_type': 'singlet UCCSD',
        'ansatz_module': 'zquantum.qaoa.ansatz',
        'ansatz_func': 'build_qaoa_circuit',
        'ansatz_grad_func': 'build_qaoa_circuit_grads',
        'supports_simple_shift_rule': False,
        'ansatz_kwargs': {
            'hamiltonians': [
                convert_qubitop_to_dict(hamiltonian),
                convert_qubitop_to_dict(diffusion_op)
            ]
        },
        'n_params': [2]
    }

    return (ansatz)
    def _build_hamiltonian(self, graph: nx.Graph) -> QubitOperator:
        """Construct a qubit operator with Hamiltonian for the graph partition problem.

        The returned Hamiltonian is consistent with the definitions from
        "Ising formulations of many NP problems" by A. Lucas, page 6
        (https://arxiv.org/pdf/1302.5843.pdf).

        The operator's terms contain Pauli Z matrices applied to qubits. The qubit indices are
        based on graph node indices in the graph definition, not on the node names.

        Args:
            graph: undirected weighted graph defining the problem
            scale_factor: constant by which all the coefficients in the Hamiltonian will be multiplied
            offset: coefficient of the constant term added to the Hamiltonian to shift its energy levels

        Returns:
            operator describing the Hamiltonian
        """
        ham_a = QubitOperator()
        for i in graph.nodes:
            ham_a += QubitOperator(f"Z{i}")
        ham_a = ham_a**2

        ham_b = QubitOperator()
        for i, j in graph.edges:
            ham_b += 1 - QubitOperator(f"Z{i} Z{j}")
        ham_b /= 2

        return ham_a + ham_b
    def test_x_y_z_mode_projection(self):
        """Find the projection of a wavefunction generated from a linear
        combination of qubits.

        python2 and python3 iterate through Qubit operators differently.
        Consequently, the coeffcients must be set based on that iteration at
        test time.
        """
        n_qubits = 2
        qubits = cirq.LineQubit.range(n_qubits)
        test_wfn = numpy.array(
            [0.92377985 + 0.j, 0. - 0.20947377j, 0.32054904 + 0.j, 0. + 0.j],
            dtype=numpy.complex128)
        self.assertAlmostEqual(numpy.vdot(test_wfn, test_wfn),
                               1.0 + 0.0j,
                               places=6)
        ops = QubitOperator('X0', 1.0) + QubitOperator('Y1', 1.0) \
            + QubitOperator('Z0', 1.0)

        test_cof = numpy.zeros((3, 1), dtype=numpy.complex128)
        for indx, cluster in enumerate(ops.terms):
            if cluster[0][1] == 'X':
                test_cof[indx] = 0.32054904
            if cluster[0][1] == 'Y':
                test_cof[indx] = -0.20947377
            if cluster[0][1] == 'Z':
                test_cof[indx] = 0.92377985

        cof = numpy.zeros((3, 1), dtype=numpy.complex128)
        cirq_utils.qubit_projection(ops, qubits, test_wfn, cof)
        self.assertTrue(numpy.allclose(cof, test_cof))
Exemple #4
0
    def _build_hamiltonian(
        self,
        graph: nx.Graph,
    ) -> QubitOperator:
        """Construct a qubit operator with Hamiltonian for the vertex cover problem.

        From https://arxiv.org/pdf/1302.5843.pdf, see equations 33 and 34
        and
        https://quantumcomputing.stackexchange.com/questions/16082/vertex-cover-mappings-from-qubo-to-ising-and-vice-versa
        for corrective translation shifts

        The operator's terms contain Pauli Z matrices applied to qubits. The qubit indices are
        based on graph node indices in the graph definition, not on the node names.

        Args:
            graph: undirected weighted graph defining the problem
            scale_factor: constant by which all the coefficients in the Hamiltonian will be multiplied
            offset: coefficient of the constant term added to the Hamiltonian to shift its energy levels

        Returns:
            operator describing the Hamiltonian
        """
        ham_a = QubitOperator()
        for i, j in graph.edges:
            ham_a += (1 - QubitOperator(f"Z{i}")) * (1 - QubitOperator(f"Z{j}"))
        ham_a *= self._hamiltonian_factor / 4

        ham_b = QubitOperator()
        for i in graph.nodes:
            ham_b += QubitOperator(f"Z{i}")
        ham_b /= 2

        return ham_a + ham_b + len(graph.nodes) / 2
Exemple #5
0
def get_maxcut_hamiltonian(graph):
    """Converts a MAXCUT instance, as described by a weighted graph, to an Ising 
    Hamiltonian.

    Args:
        graph (networkx.Graph): undirected weighted graph describing the MAXCUT 
        instance.
    
    Returns:
        zquantum.core.qubitoperator.QubitOperator object describing the 
        Hamiltonian.
    """

    output = QubitOperator()

    nodes_dict = generate_graph_node_dict(graph)

    for edge in graph.edges:
        coeff = graph.edges[edge[0], edge[1]]['weight']
        node_index1 = nodes_dict[edge[0]]
        node_index2 = nodes_dict[edge[1]]
        ZZ_term_str = 'Z' + str(node_index1) + ' Z' + str(node_index2)
        output += QubitOperator(ZZ_term_str, coeff)

    return output
    def _build_hamiltonian(self, graph: nx.Graph) -> QubitOperator:
        """Construct a qubit operator with Hamiltonian for the stable set problem.

        Based on "Efficient Combinatorial Optimization Using Quantum Annealing" p. 8
        (https://arxiv.org/pdf/1801.08653.pdf)
        and also mentioned briefly in
        "Ising formulations of many NP problems" by A. Lucas, page 11 section 4.2
        (https://arxiv.org/pdf/1302.5843.pdf).

        The operator's terms contain Pauli Z matrices applied to qubits. The qubit indices are
        based on graph node indices in the graph definition, not on the node names.

        Args:
            graph: undirected weighted graph defining the problem
            scale_factor: constant by which all the coefficients in the Hamiltonian will be multiplied
            offset: coefficient of the constant term added to the Hamiltonian to shift its energy levels

        Returns:
            operator describing the Hamiltonian
        """
        ham_a = QubitOperator()
        for i, j in graph.edges:
            ham_a += (1 - QubitOperator(f"Z{i}")) * (1 - QubitOperator(f"Z{j}"))

        ham_b = QubitOperator()
        for i in graph.nodes:
            ham_b += QubitOperator(f"Z{i}")

        return ham_a / 2 + ham_b / 2 - len(graph.nodes) / 2
Exemple #7
0
def reverse_qubit_order(qubit_operator: QubitOperator, n_qubits: Optional[int] = None):
    """Reverse the order of qubit indices in a qubit operator.

    Args:
        qubit_operator (openfermion.QubitOperator): the operator
        n_qubits (int): total number of qubits. Needs to be provided when
                    the size of the system of interest is greater than the size of qubit operator (optional)

    Returns:
        reversed_op (openfermion.ops.QubitOperator)
    """

    reversed_op = QubitOperator()

    if n_qubits is None:
        n_qubits = count_qubits(qubit_operator)
    if n_qubits < count_qubits(qubit_operator):
        raise ValueError("Invalid number of qubits specified.")

    for term in qubit_operator.terms:
        new_term = []
        for factor in term:
            new_factor = list(factor)
            new_factor[0] = n_qubits - 1 - new_factor[0]
            new_term.append(tuple(new_factor))
        reversed_op += QubitOperator(tuple(new_term), qubit_operator.terms[term])
    return reversed_op
    def test_create_circuits_from_qubit_operator(self):
        # Initialize target
        qubits = [Qubit(i) for i in range(0, 2)]

        gate_Z0 = Gate("Z", [qubits[0]])
        gate_X1 = Gate("X", [qubits[1]])

        gate_Y0 = Gate("Y", [qubits[0]])
        gate_Z1 = Gate("Z", [qubits[1]])

        circuit1 = Circuit()
        circuit1.qubits = qubits
        circuit1.gates = [gate_Z0, gate_X1]

        circuit2 = Circuit()
        circuit2.qubits = qubits
        circuit2.gates = [gate_Y0, gate_Z1]

        target_circuits_list = [circuit1, circuit2]

        # 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].gates, target_circuits_list[0].gates)
        self.assertEqual(pauli_circuits[1].gates, target_circuits_list[1].gates)
        self.assertEqual(
            str(pauli_circuits[0].qubits), str(target_circuits_list[0].qubits)
        )
        self.assertEqual(
            str(pauli_circuits[1].qubits), str(target_circuits_list[1].qubits)
        )
    def test_one_qubit_parametric_gates_using_expectation_values(
            self, backend_for_gates_test, initial_gate, tested_gate, params,
            target_values):
        n_samples = 1000
        # Given
        gate_1 = builtin_gate_by_name(initial_gate)(0)
        gate_2 = builtin_gate_by_name(tested_gate)(*params)(0)

        circuit = Circuit([gate_1, gate_2])
        operators = [
            QubitOperator("[]"),
            QubitOperator("[X0]"),
            QubitOperator("[Y0]"),
            QubitOperator("[Z0]"),
        ]

        sigma = 1 / np.sqrt(n_samples)

        for i, operator in enumerate(operators):
            # When
            estimation_tasks = [EstimationTask(operator, circuit, n_samples)]
            expectation_values = estimate_expectation_values_by_averaging(
                backend_for_gates_test, estimation_tasks)
            calculated_value = expectation_values.values[0]

            # Then
            assert calculated_value == pytest.approx(target_values[i],
                                                     abs=sigma * 3)
Exemple #10
0
    def test_qubitop_to_paulisum_more_terms(self):
        # Given
        qubit_operator = (
            QubitOperator("Z0 Z1 Z2", -1.5)
            + QubitOperator("X0", 2.5)
            + QubitOperator("Y1", 3.5)
        )
        expected_qubits = (LineQubit(0), LineQubit(5), LineQubit(8))
        expected_paulisum = (
            PauliSum()
            + (
                PauliString(Z.on(expected_qubits[0]))
                * PauliString(Z.on(expected_qubits[1]))
                * PauliString(Z.on(expected_qubits[2]))
                * -1.5
            )
            + (PauliString(X.on(expected_qubits[0]) * 2.5))
            + (PauliString(Y.on(expected_qubits[1]) * 3.5))
        )

        # When
        paulisum = qubitop_to_paulisum(qubit_operator, qubits=expected_qubits)

        # Then
        self.assertEqual(paulisum.qubits, expected_qubits)
        self.assertEqual(paulisum, expected_paulisum)
def qiskitpauli_to_qubitop(
        qiskit_pauli: WeightedPauliOperator) -> QubitOperator:
    """
    Convert a qiskit's qiskit.aqua.operators.WeightedPauliOperator to a OpenFermion QubitOperator.

    Args:
        qiskit_pauli: WeightedPauliOperator to convert to an
    OpenFermion QubitOperator

    Returns:
        QubitOperator representing the WeightedPauliOperator
    """

    if not isinstance(qiskit_pauli, WeightedPauliOperator):
        raise TypeError("qiskit_pauli must be a qiskit WeightedPauliOperator")

    transformed_term = QubitOperator()

    for weight, qiskit_term in qiskit_pauli.paulis:
        openfermion_term = QubitOperator()
        for (term_qubit, term_pauli) in enumerate(str(qiskit_term)):
            if term_pauli != "I":
                if openfermion_term == QubitOperator():
                    openfermion_term = QubitOperator(
                        f"[{term_pauli}{term_qubit}]")
                else:
                    openfermion_term *= QubitOperator(
                        f"[{term_pauli}{term_qubit}]")

        transformed_term += openfermion_term * weight

    return transformed_term
 def test_get_pauli_strings(self):
     qubit_operator = (QubitOperator(
         ((0, "X"), (1, "Y"))) - 0.5 * QubitOperator(
             ((1, "Y"), )) + 0.5 * QubitOperator(()))
     constructed_list = get_pauli_strings(qubit_operator)
     target_list = ["X0Y1", "Y1", ""]
     self.assertListEqual(constructed_list, target_list)
    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
 def ansatz(self, thetas, number_of_layers):
     cost_hamiltonian = QubitOperator((0, "Z")) + QubitOperator((1, "Z"))
     return WarmStartQAOAAnsatz(
         number_of_layers=number_of_layers,
         cost_hamiltonian=cost_hamiltonian,
         thetas=thetas,
     )
 def ansatz(self):
     cost_hamiltonian = QubitOperator((0, "Z")) + QubitOperator((1, "Z"))
     mixer_hamiltonian = QubitOperator((0, "X")) + QubitOperator((1, "X"))
     return QAOAFarhiAnsatz(
         number_of_layers=1,
         cost_hamiltonian=cost_hamiltonian,
         mixer_hamiltonian=mixer_hamiltonian,
     )
Exemple #16
0
def create_one_qubit_operator(x_coeff: float, y_coeff: float, z_coeff: float,
                              constant: float) -> None:

    qubit_operator = (x_coeff * QubitOperator("X0") +
                      y_coeff * QubitOperator("Y0") +
                      z_coeff * QubitOperator("Z0") + constant * QubitOperator(
                          ()))
    save_qubit_operator(qubit_operator, "qubit_operator.json")
Exemple #17
0
 def binary_string_rep_inv(binary_string):
     n_qubit = len(binary_string) // 2
     qop = QubitOperator(())
     for i, k in enumerate(binary_string):
         if k == 0: continue
         if i < n_qubit:
             qop *= QubitOperator((i, 'X'))
         else:
             qop *= QubitOperator((i - n_qubit, 'Z'))
     return qop
    def test_set_cost_hamiltonian(self, ansatz):
        # Given
        new_cost_hamiltonian = QubitOperator((0, "Z")) - QubitOperator(
            (1, "Z"))

        # When
        ansatz.cost_hamiltonian = new_cost_hamiltonian

        # Then
        assert ansatz._cost_hamiltonian == new_cost_hamiltonian
    def test_set_mixer_hamiltonian(self, ansatz):
        # Given
        new_mixer_hamiltonian = QubitOperator((0, "Z")) - QubitOperator(
            (1, "Z"))

        # When
        ansatz.mixer_hamiltonian = new_mixer_hamiltonian

        # Then
        ansatz._mixer_hamiltonian == new_mixer_hamiltonian
    def test_set_mixer_hamiltonian_invalidates_circuit(self, ansatz):
        # Given
        new_mixer_hamiltonian = QubitOperator((0, "Z")) - QubitOperator(
            (1, "Z"))

        # When
        ansatz.mixer_hamiltonian = new_mixer_hamiltonian

        # Then
        assert ansatz._parametrized_circuit is None
def test_create_all_x_mixer_hamiltonian():
    # Given
    number_of_qubits = 4
    target_operator = (QubitOperator("X0") + QubitOperator("X1") +
                       QubitOperator("X2") + QubitOperator("X3"))

    # When
    operator = create_all_x_mixer_hamiltonian(number_of_qubits)

    # Then
    assert operator == target_operator
    def test_get_number_of_qubits(self, ansatz):
        # Given
        new_cost_hamiltonian = (QubitOperator((0, "Z")) + QubitOperator(
            (1, "Z")) + QubitOperator((2, "Z")))
        target_number_of_qubits = 3

        # When
        ansatz.cost_hamiltonian = new_cost_hamiltonian

        # Then
        assert ansatz.number_of_qubits == target_number_of_qubits
def test_exception_convert_observable():
    r"""Test that an error is raised if the QubitOperator contains complex coefficients.
    Currently the vqe.Hamiltonian class does not support complex coefficients.
    """
    qubit_op = (QubitOperator("Y0 Y1", 1 + 0j) +
                QubitOperator("Z0 X1", 4.5 + 1.5j) + QubitOperator("Y0 X1", 2))

    with pytest.raises(
            TypeError,
            match="The coefficients entering the QubitOperator must be real"):
        qchem.convert_observable(qubit_op)
def test_create_farhi_qaoa_circuits_fails_when_length_of_inputs_is_not_equal():
    # Given
    hamiltonians = [
        QubitOperator("Z0 Z1"),
        QubitOperator("Z0") + QubitOperator("Z1"),
    ]
    number_of_layers = [2]

    # When
    with pytest.raises(AssertionError):
        create_farhi_qaoa_circuits(hamiltonians, number_of_layers)
Exemple #25
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)
Exemple #26
0
    def test_get_maxcut_hamiltonian(self):
        # Given
        graph = nx.Graph()
        graph.add_edge(1, 2, weight=0.4)
        graph.add_edge(2, 3, weight=-0.1)
        graph.add_edge(1, 3, weight=0.2)
        target_hamiltonian = 0.4*QubitOperator('Z0 Z1') - 0.1*QubitOperator('Z1 Z2') + 0.2*QubitOperator('Z0 Z2')

        # When
        hamiltonian = get_maxcut_hamiltonian(graph)
        
        # Then
        self.assertEqual(hamiltonian, target_hamiltonian)
    def test_get_number_of_qubits_with_ising_hamiltonian(self, ansatz):
        # Given
        new_cost_hamiltonian = (QubitOperator((0, "Z")) + QubitOperator(
            (1, "Z")) + QubitOperator((2, "Z")))
        new_cost_hamiltonian = change_operator_type(new_cost_hamiltonian,
                                                    IsingOperator)
        target_number_of_qubits = 3

        # When
        ansatz.cost_hamiltonian = new_cost_hamiltonian

        # Then
        assert ansatz.number_of_qubits == target_number_of_qubits
Exemple #28
0
    def test_get_expectation_value(self):
        """Check <Z0> and <Z1> for the state |100>"""
        # Given
        wf = pyquil.wavefunction.Wavefunction([0, 1, 0, 0, 0, 0, 0, 0])
        op1 = QubitOperator("Z0")
        op2 = QubitOperator("Z1")
        # When
        exp_op1 = get_expectation_value(op1, wf)
        exp_op2 = get_expectation_value(op2, wf)

        # Then
        self.assertAlmostEqual(-1, exp_op1)
        self.assertAlmostEqual(1, exp_op2)
    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_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