Skip to content

Commit

Permalink
Formatted using black
Browse files Browse the repository at this point in the history
  • Loading branch information
KilianPoirier committed Dec 12, 2023
1 parent 0792eb3 commit 1a8906e
Show file tree
Hide file tree
Showing 7 changed files with 327 additions and 151 deletions.
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,4 @@
# app.connect(skip)

# pygments_style = 'sphinx'
# suppress_warnings = ["myst_header"]
# suppress_warnings = ["myst_header"]
268 changes: 151 additions & 117 deletions src/openqaoa-core/openqaoa/problems/bpsp.py

Large diffs are not rendered by default.

54 changes: 36 additions & 18 deletions src/openqaoa-core/tests/test_bpsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ def terms_list_equality(terms_list1, terms_list2):

return bool


def fisher_yates_shuffle(arr, rng):
"""
Perform an in-place shuffle of a list using the Fisher-Yates shuffle algorithm.
This algorithm runs in O(n) time and ensures that every permutation of the array is equally likely.
This algorithm runs in O(n) time and ensures that every permutation of the array is equally likely.
The shuffle is performed in-place, meaning that the input array `arr` is modified directly.
Parameters:
Expand Down Expand Up @@ -59,6 +60,7 @@ def fisher_yates_shuffle(arr, rng):
# Return the shuffled array
return arr


class TestBPSP(unittest.TestCase):
"""
Test suite for the BPSP problem.
Expand All @@ -71,12 +73,14 @@ def test_bpsp_qubo(self):
"""
Test the correct QUBO formation from a provided graph.
This method validates that BPSP creates the expected QUBO by comparing
This method validates that BPSP creates the expected QUBO by comparing
its terms and weights with predefined expected values.
"""
car_sequence = [3, 1, 0, 0, 2, 2, 4, 4, 3, 1]
G = nx.Graph()
G.add_weighted_edges_from([[3, 1, -2], [3, 4, -1], [1, 0, -1], [0, 2, 1], [2, 4, 1]])
G.add_weighted_edges_from(
[[3, 1, -2], [3, 4, -1], [1, 0, -1], [0, 2, 1], [2, 4, 1]]
)

gr_edges = [[3, 1], [3, 4], [1, 0], [0, 2], [2, 4]]
gr_weights = [-2, -1, -1, 1, 1]
Expand All @@ -103,12 +107,12 @@ def test_bpsp_random_instance(self):
"""
Test the random instance generation of the Binary Paint Shop Problem (BPSP).
This test verifies whether the `random_instance` method of the BPSP class
This test verifies whether the `random_instance` method of the BPSP class
correctly creates a randomized car sequence based on a given number of cars and seed.
The car sequence should be a list containing two occurrences of each car ID,
randomly shuffled using the Fisher-Yates shuffle algorithm.
The function asserts that the sequence generated by the BPSP class's method
The function asserts that the sequence generated by the BPSP class's method
is identical to the sequence produced by an explicitly defined Fisher-Yates shuffle process,
ensuring both consistency and correctness in the shuffling method based on a fixed seed.
"""
Expand All @@ -120,16 +124,19 @@ def test_bpsp_random_instance(self):
# Lambda function to create and shuffle car sequence using Fisher-Yates algorithm
# The lambda function first duplicates each car ID using np.tile, then applies the shuffle.
create_car_seq = lambda num_cars, seed: fisher_yates_shuffle(
np.tile(np.arange(num_cars), 2), np.random.default_rng(seed))
np.tile(np.arange(num_cars), 2), np.random.default_rng(seed)
)

# Generating a random BPSP instance using the class method
bpsp = BPSP.random_instance(num_cars=num_cars, seed=seed)

# Asserting if the generated car sequence in BPSP instance is identical
# to the sequence produced by our lambda function.
# This confirms the random instance generation works as expected.
self.assertTrue(all(bpsp.car_sequence == create_car_seq(num_cars, seed)),
"The generated car sequence does not match the expected shuffled sequence.")
self.assertTrue(
all(bpsp.car_sequence == create_car_seq(num_cars, seed)),
"The generated car sequence does not match the expected shuffled sequence.",
)

def test_bpsp_car_pos(self):
"""Test the retrieval of car positions."""
Expand All @@ -140,22 +147,26 @@ def test_bpsp_graph(self):
"""Test the generation of a graph representation of the BPSP instance."""
car_sequence = [3, 1, 0, 0, 2, 2, 4, 4, 3, 1]
G = nx.Graph()
G.add_weighted_edges_from([[3, 1, -2], [3, 4, -1], [1, 0, -1], [0, 2, 1], [2, 4, 1]])
G.add_weighted_edges_from(
[[3, 1, -2], [3, 4, -1], [1, 0, -1], [0, 2, 1], [2, 4, 1]]
)

bpsp_graph = BPSP(car_sequence).graph

assert nx.is_isomorphic(G, bpsp_graph), "The created graph and BPSP graph are not identical,"
assert nx.is_isomorphic(
G, bpsp_graph
), "The created graph and BPSP graph are not identical,"

def test_bpsp_docplex_bpsp_model(self):
"""Test if the docplex model representation of BPSP is generated."""
bpsp = BPSP.random_instance(num_cars=2, seed=1234)

# Obtain the model
mdl = bpsp.docplex_bpsp_model # Access as attribute due to @property decorator

# Verify that the function returns a valid model instance
self.assertIsInstance(mdl, Model, "Model is not an instance of DOcplex Model")

# Manually retrieve binary variables based on their expected names
sequence = bpsp.car_sequence
expected_var_names = [f"w_{w}_{i}" for i, w in enumerate(sequence)]
Expand All @@ -168,13 +179,19 @@ def test_bpsp_docplex_bpsp_model(self):
self.assertTrue(var.is_binary(), f"Variable {var} is not binary")

# Check number of constraints
self.assertEqual(mdl.number_of_constraints, 11, "Unexpected number of constraints")

self.assertEqual(
mdl.number_of_constraints, 11, "Unexpected number of constraints"
)

# Check if objective function exists
self.assertIsNotNone(mdl.objective_expr, "Objective function is missing")

# Check if the objective is to minimize
self.assertEqual(mdl.objective_sense, ObjectiveSense.Minimize, "Objective should be of type 'minimize'")
self.assertEqual(
mdl.objective_sense,
ObjectiveSense.Minimize,
"Objective should be of type 'minimize'",
)

def test_bpsp_solve_cplex(self):
"""
Expand All @@ -191,7 +208,7 @@ def test_bpsp_solve_cplex(self):
def test_bpsp_paintseq_from_bits(self):
"""Test the solution of the BPSP problem using QAOA."""
bpsp = BPSP(np.array([0, 1, 0, 1]))
sequence, color_swaps = bpsp.paintseq_from_bits('10')
sequence, color_swaps = bpsp.paintseq_from_bits("10")
self.assertEqual(sequence, [1, 0, 0, 1])
self.assertEqual(color_swaps, 2)

Expand All @@ -209,5 +226,6 @@ def test_bpsp_solve_greedy(self):
self.assertEqual(sequence, [0, 0, 1, 1])
self.assertEqual(color_swaps, 1)


if __name__ == "__main__":
unittest.main()
7 changes: 6 additions & 1 deletion src/openqaoa-core/tests/test_qubo.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,12 @@ def test_problem_instance(self):
],
"sherrington_kirkpatrick": ["problem_type", "G"],
"k_color": ["problem_type", "G", "k", "penalty"],
"binary_paint_shop_problem": ["problem_type", "car_sequence", "car_positions", "bpsp_graph"],
"binary_paint_shop_problem": [
"problem_type",
"car_sequence",
"car_positions",
"bpsp_graph",
],
"generic_qubo": ["problem_type"],
}

Expand Down
142 changes: 129 additions & 13 deletions src/openqaoa-qiskit/tests/test_circuit_routing_qiskit.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,44 @@ def setUp(self):
],
# problem_to_solve = [[0,1],[1,2],[2,3]],
initial_mapping=None,
gate_indices_list = [[0, 1], [2, 3], [3, 4], [1, 2], [2, 3], [3, 4], [1, 2], [0, 1], [1, 2], [1, 2], [2, 3], [3, 4], [2, 3], [0, 1], [1, 2], [2, 3]],
swap_mask = [False, False, False, False, True, False, False, True, False, True, False, True, False, True, True, False],
initial_physical_to_logical_mapping = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4},
final_logical_qubit_order = [1, 2, 4, 0, 3],
gate_indices_list=[
[0, 1],
[2, 3],
[3, 4],
[1, 2],
[2, 3],
[3, 4],
[1, 2],
[0, 1],
[1, 2],
[1, 2],
[2, 3],
[3, 4],
[2, 3],
[0, 1],
[1, 2],
[2, 3],
],
swap_mask=[
False,
False,
False,
False,
True,
False,
False,
True,
False,
True,
False,
True,
False,
True,
True,
False,
],
initial_physical_to_logical_mapping={0: 0, 1: 1, 2: 2, 3: 3, 4: 4},
final_logical_qubit_order=[1, 2, 4, 0, 3],
)

# case qubits problem == 2 (IBM kyoto)
Expand All @@ -108,12 +142,12 @@ def setUp(self):
"project": "main",
"as_emulator": True,
},
problem_to_solve=[(0,1), (0, 2)],
problem_to_solve=[(0, 1), (0, 2)],
initial_mapping=None,
gate_indices_list = [[0, 1], [1, 2], [0, 1]],
swap_mask = [False, True, False],
initial_physical_to_logical_mapping = {0: 0, 1: 1, 2: 2},
final_logical_qubit_order = [0, 2, 1],
gate_indices_list=[[0, 1], [1, 2], [0, 1]],
swap_mask=[False, True, False],
initial_physical_to_logical_mapping={0: 0, 1: 1, 2: 2},
final_logical_qubit_order=[0, 2, 1],
)

# case qubits device == qubits problem (IBM perth)
Expand Down Expand Up @@ -151,10 +185,92 @@ def setUp(self):
(5, 6),
],
initial_mapping=None,
gate_indices_list = [[4, 5], [1, 2], [0, 1], [2, 3], [3, 4], [5, 6], [1, 2], [0, 1], [2, 3], [3, 4], [2, 3], [4, 5], [2, 3], [1, 2], [4, 5], [5, 6], [3, 4], [0, 1], [1, 2], [3, 4], [5, 6], [4, 5], [2, 3], [1, 2], [4, 5], [3, 4], [1, 2], [0, 1], [2, 3], [3, 4], [3, 4], [4, 5], [5, 6], [2, 3], [0, 1], [1, 2]],
swap_mask = [False, False, False, False, False, False, True, False, False, True, False, False, True, False, True, False, False, True, False, True, True, False, True, False, True, False, True, False, True, False, True, True, False, True, True, False],
initial_physical_to_logical_mapping = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6},
final_logical_qubit_order = [5, 4, 1, 6, 3, 0, 2],
gate_indices_list=[
[4, 5],
[1, 2],
[0, 1],
[2, 3],
[3, 4],
[5, 6],
[1, 2],
[0, 1],
[2, 3],
[3, 4],
[2, 3],
[4, 5],
[2, 3],
[1, 2],
[4, 5],
[5, 6],
[3, 4],
[0, 1],
[1, 2],
[3, 4],
[5, 6],
[4, 5],
[2, 3],
[1, 2],
[4, 5],
[3, 4],
[1, 2],
[0, 1],
[2, 3],
[3, 4],
[3, 4],
[4, 5],
[5, 6],
[2, 3],
[0, 1],
[1, 2],
],
swap_mask=[
False,
False,
False,
False,
False,
False,
True,
False,
False,
True,
False,
False,
True,
False,
True,
False,
False,
True,
False,
True,
True,
False,
True,
False,
True,
False,
True,
False,
True,
False,
True,
True,
False,
True,
True,
False,
],
initial_physical_to_logical_mapping={
0: 0,
1: 1,
2: 2,
3: 3,
4: 4,
5: 5,
6: 6,
},
final_logical_qubit_order=[5, 4, 1, 6, 3, 0, 2],
)

# create a list of all the cases
Expand Down
1 change: 1 addition & 0 deletions src/openqaoa-qiskit/tests/test_gate_applicators_qiskit.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from qiskit.circuit import gate as qsk_gate
from qiskit.circuit import controlledgate as qsk_c_gate
from qiskit.circuit.library import standard_gates as qsk_s_gate

# from qiskit.circuit import singleton as qsk_sgt
from qiskit import QuantumCircuit

Expand Down
4 changes: 3 additions & 1 deletion tests/test_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ def test_all_module_import(self):
"""

folder_names = [
each_file for each_file in os.listdir("src") if ("openqaoa-" in each_file and not "openqaoa-pyquil")
each_file
for each_file in os.listdir("src")
if ("openqaoa-" in each_file and not "openqaoa-pyquil")
]

packages_import = []
Expand Down

0 comments on commit 1a8906e

Please sign in to comment.