Skip to content

Commit

Permalink
fix BIBD model
Browse files Browse the repository at this point in the history
  • Loading branch information
yangeorget committed Sep 30, 2024
1 parent a89fe39 commit 29c25c1
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 20 deletions.
6 changes: 4 additions & 2 deletions nucs/examples/bibd/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

if __name__ == "__main__":
problem = BIBDProblem(8, 14, 7, 4, 3)
# problem = BIBDProblem(6, 10, 5, 3, 2)
# problem = BIBDProblem(7, 7, 3, 3, 1)
solver = BacktrackSolver(problem)
solver.solve_all()
print(get_statistics(solver.statistics))
solver.solve_all(lambda solution: print(problem.solution_as_matrix(solution)))
print(get_statistics(solver.statistics))
56 changes: 38 additions & 18 deletions nucs/examples/bibd/bibd_problem.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import List

from nucs.problems.problem import Problem
from nucs.propagators.propagators import ALG_EXACTLY_EQ, ALG_LEXICOGRAPHIC_LEQ, ALG_MIN_EQ

Expand All @@ -7,32 +9,50 @@ class BIBDProblem(Problem):
CSPLIB problem #28 - https://www.csplib.org/Problems/prob028/
"""

def __init__(self, v: int, b: int, r: int, k: int, l: int):
s = (v * (v - 1)) // 2
n = (v + s) * b
super().__init__([(0, 1)] * n)
def __init__(self, object_nb: int, block_nb: int, by_row_count: int, by_column_count: int, scalar_product: int):
self.object_nb = object_nb # number of rows
self.block_nb = block_nb # number of columns
matrix_var_nb = object_nb * block_nb # number of cells in the matrix
redundant_var_nb = ((object_nb * (object_nb - 1)) // 2) * block_nb
super().__init__([(0, 1)] * (matrix_var_nb + redundant_var_nb))
# rows: counts
for i in range(0, v):
self.add_propagator((list(range(i * b, (i + 1) * b)), ALG_EXACTLY_EQ, [1, r]))
for object_idx in range(0, object_nb):
self.add_propagator(
(list(range(object_idx * block_nb, (object_idx + 1) * block_nb)), ALG_EXACTLY_EQ, [1, by_row_count])
)
# columns: counts
for j in range(0, b):
self.add_propagator((list(range(j, v * b, b)), ALG_EXACTLY_EQ, [1, k]))
for block_idx in range(0, block_nb):
self.add_propagator(
(list(range(block_idx, object_nb * block_nb, block_nb)), ALG_EXACTLY_EQ, [1, by_column_count])
)
# scalar products: conjunctions and counts
conj_idx = v * b
for i1 in range(0, v - 1):
for i2 in range(i1 + 1, v):
conj_idx = object_nb * block_nb # index of first redundant variable
for i1 in range(0, object_nb - 1):
for i2 in range(i1 + 1, object_nb):
conj_vars = []
for j in range(0, b):
for block_idx in range(0, block_nb):
self.add_propagator(
([(i1 * b + j), (i2 * b + j), conj_idx], ALG_MIN_EQ, [])
([(i1 * block_nb + block_idx), (i2 * block_nb + block_idx), conj_idx], ALG_MIN_EQ, [])
) # TODO:replace by AND ?
conj_vars.append(conj_idx)
conj_idx += 1
self.add_propagator((conj_vars, ALG_EXACTLY_EQ, [1, l]))
self.add_propagator((conj_vars, ALG_EXACTLY_EQ, [1, scalar_product]))
# remove symmetries
# lexleq on rows
for i in range(0, v - 1):
self.add_propagator((list(range(i * b, (i + 2) * b)), ALG_LEXICOGRAPHIC_LEQ, []))
for object_idx in range(0, object_nb - 1):
self.add_propagator(
(list(range(object_idx * block_nb, (object_idx + 2) * block_nb)), ALG_LEXICOGRAPHIC_LEQ, [])
)
# lexleq on columns
for j in range(0, b - 1):
self.add_propagator((list(range(j, v * b, b)) + list(range(j + 1, v * b, b)), ALG_LEXICOGRAPHIC_LEQ, []))
for block_idx in range(0, block_nb - 1):
self.add_propagator(
(
list(range(block_idx, object_nb * block_nb, block_nb))
+ list(range(block_idx + 1, object_nb * block_nb, block_nb)),
ALG_LEXICOGRAPHIC_LEQ,
[],
)
)

def solution_as_matrix(self, solution: List[int]) -> List[List[int]]:
return [[solution[i * self.block_nb + j] for j in range(0, self.block_nb)] for i in range(0, self.object_nb)]
8 changes: 8 additions & 0 deletions tests/examples/test_bibd.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,16 @@ def test_6_10_5_3_2(self) -> None:
solver.solve_all()
assert solver.statistics[STATS_SOLVER_SOLUTION_NB] == 1

def test_7_7_3_3_1(self) -> None:
problem = BIBDProblem(7, 7, 3, 3, 1)
solver = BacktrackSolver(problem)
solver.solve_all()
assert solver.statistics[STATS_SOLVER_SOLUTION_NB] == 1

def test_8_14_7_4_3(self) -> None:
problem = BIBDProblem(8, 14, 7, 4, 3)
solver = BacktrackSolver(problem)
solver.solve_all()
assert solver.statistics[STATS_SOLVER_SOLUTION_NB] == 92


0 comments on commit 29c25c1

Please sign in to comment.