Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Space Efficient QRAO #59

Merged
merged 1 commit into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion qamomile/core/converters/qrao/qrao21.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def qrac21_encode_ising(
continue

if i == j:
offset += coeff
hamiltonian.constant += coeff
continue

pauli_i = encoded_ope[i]
Expand Down
2 changes: 1 addition & 1 deletion qamomile/core/converters/qrao/qrao31.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def qrac31_encode_ising(
continue

if i == j:
offset += coeff
hamiltonian.constant += coeff
continue

pauli_i = encoded_ope[i]
Expand Down
108 changes: 108 additions & 0 deletions qamomile/core/converters/qrao/qrao_space_efficient.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
from __future__ import annotations
import typing as typ
import numpy as np
from qamomile.core.converters.converter import QuantumConverter
from qamomile.core.ising_qubo import IsingModel
import qamomile.core.operator as qm_o
from .graph_coloring import greedy_graph_coloring, check_linear_term


def numbering_space_efficient_encode(
ising: IsingModel,
) -> dict[int, qm_o.PauliOperator]:
"""
Encodes the Ising model into a space efficient and provides corresponding Pauli operator.

Args:
ising (IsingModel): The Ising model to be encoded.

Returns:
dict[int, qm_o.PauliOperator]: A dictionary mapping qubit indices to Pauli operators.
"""
max_quad_index = max(max(t) for t in ising.quad.keys())
max_linear_index = max(ising.linear.keys())
num_vars = max(max_quad_index, max_linear_index) + 1

encode = {}
pauli_ope = [qm_o.Pauli.X, qm_o.Pauli.Y]
for i in range(num_vars):
qubit_index = i // 2
color = i % 2
encode[i] = qm_o.PauliOperator(pauli_ope[color], qubit_index)
return encode

def qrac_space_efficient_encode_ising(
ising: IsingModel,
) -> tuple[qm_o.Hamiltonian, dict[int, qm_o.PauliOperator]]:
encoded_ope = numbering_space_efficient_encode(ising)

offset = ising.constant

hamiltonian = qm_o.Hamiltonian()
hamiltonian.constant = offset

# convert linear parts of the objective function into Hamiltonian.
for idx, coeff in ising.linear.items():
if coeff == 0.0:
continue

pauli = encoded_ope[idx]
hamiltonian.add_term((pauli,), np.sqrt(3) * coeff)

# create Pauli terms
for (i, j), coeff in ising.quad.items():
if coeff == 0.0:
continue

if i == j:
hamiltonian.constant += coeff
continue

pauli_i = encoded_ope[i]

pauli_j = encoded_ope[j]

if pauli_i.index == pauli_j.index:
hamiltonian.add_term((qm_o.PauliOperator(qm_o.Pauli.Z, pauli_i.index),), np.sqrt(3) * coeff)
else:
hamiltonian.add_term((pauli_i, pauli_j), 3 * coeff)

return hamiltonian, encoded_ope



class QRACSpaceEfficientConverter(QuantumConverter):

def ising_encode(
self,
multipliers: typ.Optional[dict[str, float]] = None,
detail_parameters: typ.Optional[dict[str, dict[tuple[int, ...], tuple[float, float]]]] = None
) -> IsingModel:
ising = super().ising_encode(multipliers, detail_parameters)
return ising

def get_cost_hamiltonian(self) -> qm_o.Hamiltonian:
"""
Construct the cost Hamiltonian for Space Efficient QRAC.

Returns:
qm_o.Hamiltonian: The cost Hamiltonian.
"""
ising = self.get_ising()

hamiltonian, pauli_encoding = qrac_space_efficient_encode_ising(ising)
self.pauli_encoding = pauli_encoding
self.num_qubits = hamiltonian.num_qubits
return hamiltonian

def get_encoded_pauli_list(self) -> list[qm_o.Hamiltonian]:
# return the encoded Pauli operators as list
ising = self.get_ising()

zero_pauli = qm_o.Hamiltonian(num_qubits=self.num_qubits)
pauli_operators = [zero_pauli] * ising.num_bits()
for idx, pauli in self.pauli_encoding.items():
observable = qm_o.Hamiltonian(num_qubits=self.num_qubits)
observable.add_term((pauli,), 1.0)
pauli_operators[idx] = observable
return pauli_operators
90 changes: 88 additions & 2 deletions tests/test_qrao.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import numpy as np
import jijmodeling as jm
import jijmodeling_transpiler.core as jmt
from qamomile.core.ising_qubo import IsingModel, qubo_to_ising
from qamomile.core.converters.qrao.graph_coloring import (
greedy_graph_coloring,
check_linear_term,
)
from qamomile.core.converters.qrao.qrao31 import qrac31_encode_ising
from qamomile.core.converters.qrao.qrao21 import qrac21_encode_ising
from qamomile.core.converters.qrao.qrao31 import qrac31_encode_ising, QRAC31Converter
from qamomile.core.converters.qrao.qrao21 import qrac21_encode_ising, QRAC21Converter
from qamomile.core.converters.qrao.qrao_space_efficient import (numbering_space_efficient_encode, qrac_space_efficient_encode_ising, QRACSpaceEfficientConverter)
import qamomile.core.operator as qm_o


Expand Down Expand Up @@ -73,6 +76,21 @@ def test_check_linear_term_qrao31():
assert len(encoding) == ising.num_bits()
assert qrac_hamiltonian.terms == expected_hamiltonian

def test_QRAC31Converter():
problem = jm.Problem("sample")
x = jm.BinaryVar("x", shape = (3,))
problem += x[1]
problem += jm.Constraint("const", x[0] + x[2] == 1)
compiled_instance = jmt.compile_model(problem, {})

converter = QRAC31Converter(compiled_instance)

# Test get_cost_hamiltonian method
cost_hamiltonian = converter.get_cost_hamiltonian()

pauli_list = converter.get_encoded_pauli_list()
assert len(pauli_list) == 3


def test_check_linear_term_qrao21():
X1 = qm_o.PauliOperator(qm_o.Pauli.X, 1)
Expand Down Expand Up @@ -171,3 +189,71 @@ def test_check_no_quad_term_quri():
assert qrac_hamiltonian.num_qubits < ising.num_bits()
assert len(encoding) == ising.num_bits()
assert qrac_hamiltonian.terms == expected_hamiltonian


def test_QRAC21Converter():
problem = jm.Problem("sample")
x = jm.BinaryVar("x", shape = (3,))
problem += x[1]
problem += jm.Constraint("const", x[0] + x[2] == 1)
compiled_instance = jmt.compile_model(problem, {})

converter = QRAC21Converter(compiled_instance)

# Test get_cost_hamiltonian method
cost_hamiltonian = converter.get_cost_hamiltonian()

pauli_list = converter.get_encoded_pauli_list()
assert len(pauli_list) == 3


def test_numbering_space_efficient_encode():
ising = IsingModel({(0, 1): 2.0, (0, 2): 1.0}, {2: 5.0, 3: 2.0}, 6.0)
encoding = numbering_space_efficient_encode(ising)
expected_encoding = {
0: qm_o.PauliOperator(qm_o.Pauli.X, 0),
1: qm_o.PauliOperator(qm_o.Pauli.Y, 0),
2: qm_o.PauliOperator(qm_o.Pauli.X, 1),
3: qm_o.PauliOperator(qm_o.Pauli.Y, 1),
}
assert encoding == expected_encoding


def test_qrac_space_efficient_encode_ising():
ising = IsingModel({(0, 1): 2.0, (0, 2): 1.0}, {2: 5.0, 3: 2.0}, 6.0)
expected_hamiltonian = qm_o.Hamiltonian()
expected_hamiltonian.constant = 6.0

expected_hamiltonian.add_term((qm_o.PauliOperator(qm_o.Pauli.X, 1),), np.sqrt(3) * 5.0)
expected_hamiltonian.add_term((qm_o.PauliOperator(qm_o.Pauli.Y, 1),), np.sqrt(3) * 2.0)
expected_hamiltonian.add_term((qm_o.PauliOperator(qm_o.Pauli.X, 0), qm_o.PauliOperator(qm_o.Pauli.X, 1)), 3 * 1.0)
expected_hamiltonian.add_term((qm_o.PauliOperator(qm_o.Pauli.Z, 0), ), np.sqrt(3) * 2.0)

expected_encoding = {
0: qm_o.PauliOperator(qm_o.Pauli.X, 0),
1: qm_o.PauliOperator(qm_o.Pauli.Y, 0),
2: qm_o.PauliOperator(qm_o.Pauli.X, 1),
3: qm_o.PauliOperator(qm_o.Pauli.Y, 1),
}

hamiltonian, encoding = qrac_space_efficient_encode_ising(ising)

assert hamiltonian == expected_hamiltonian
assert encoding == expected_encoding

def test_QRACSpaceEfficientConverter():
problem = jm.Problem("sample")
x = jm.BinaryVar("x", shape = (3,))
problem += x[0] + x[1]
problem += jm.Constraint("const", x[0] + x[1] + x[2] == 1)
compiled_instance = jmt.compile_model(problem, {})

# Create an instance of QRACSpaceEfficientConverter
converter = QRACSpaceEfficientConverter(compiled_instance)

# Test get_cost_hamiltonian method
cost_hamiltonian = converter.get_cost_hamiltonian()
assert converter.num_qubits == 2
pauli_list = converter.get_encoded_pauli_list()
assert len(pauli_list) == 3
assert np.all(pauli_list == [qm_o.X(0), qm_o.Y(0), qm_o.X(1)])
Loading