Skip to content

Commit

Permalink
Merge pull request #9 from MHenderson/8-implement-partial-latin-squar…
Browse files Browse the repository at this point in the history
…e-to-list-colouring-problem

Implement partial latin square to list colouring problem
  • Loading branch information
MHenderson authored Dec 4, 2024
2 parents 6f420b6 + f83071d commit 2e87a79
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 77 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.10"]
python-version: ["3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v3
Expand Down
10 changes: 0 additions & 10 deletions .gitpod.yml

This file was deleted.

5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
test:
poetry run pytest

install:
poetry install
23 changes: 21 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 2 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
[tool.poetry]
name = "ryser"
version = "0.1.0"
version = "0.1.0.9001"
description = "Latin squares and related designs."
authors = ["Matthew Henderson <[email protected]>"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.10"
networkx = "^3.4.2"


[tool.poetry.group.test.dependencies]
Expand All @@ -16,7 +17,3 @@ pytest = "^8.1.1"
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.pytest.ini_options]
pythonpath = [
"."
]
73 changes: 19 additions & 54 deletions ryser/__init__.py → src/ryser/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import networkx as nx

def row_string(fixed, size, row, col_sep='|', padding=0):
"""
Converts a dict of fixed cells to a string.
Expand Down Expand Up @@ -87,12 +89,12 @@ def list_assignment(partial_latin_square, size):
if i in P.keys():
L[row(i,size),col(i,size)] = [P[i]]
else:
L[row(i,size),col(i,size)] = range(1, size + 1)
L[row(i,size),col(i,size)] = list(range(1, size + 1))
# update lists (remove used symbols from lists of same row/col)
for i in range(1, size**2 + 1):
if i in P.keys():
# then remove P[i] from any list of a cell not in P from the same row/col
for j in row_r(i, size) + col_r(i, size):
for j in list(row_r(i, size)) + list(col_r(i, size)):
if j not in P.keys():
if P[i] in L[row(j, size), col(j, size)]:
L[row(j, size), col(j, size)].remove(P[i])
Expand Down Expand Up @@ -130,57 +132,20 @@ def com_2_csm(P, size):
L[cell(row, col, size)] = int(P[i][j])
return L

class Latin:

def __init__(self, P, size, symbols = None, format = ''):
self._size = size
if symbols == None:
self._symbols = range(1, size + 1)
else:
self._symbols = symbols
if format == 'sim':
self._P = sim_2_csm(P, size)
elif format == 'com':
self._P = com_2_csm(P, size)
else:
self._P = P

def __repr__(self):
return dict_to_string_simple(self._P, self._size)

def __str__(self):
return self.__repr__()

def __getitem__(self, key):
return self._P[cell(key[0], key[1], self._size)]

def size(self):
return self._size

def symbols(self):
return self._symbols

def row_presences(self, row_index):
result = []
first_cell = cell(row_index, 1, self._size)
row = row_r(first_cell, self._size)
for cell_ in row:
symbol = self._P.get(cell_)
if symbol!=None:
result.append(symbol)
return result

def row_absences(self, row_index):
result = self.symbols()[:]
presences = self.row_presences(row_index)
for x in presences:
if x in result:
result.remove(x)
return result

def fixed_cells(self):
return self._P

def extend(self, disjoint_fixed):
self._P.update(disjoint_fixed)
def pls_list_colouring_problem(fixed, size):
"""
Return a complete digraph (including self-loops on every node) with a list-assignment
to edges such that the list on edge (i, j) is the set of all symbols not used in row i
or column j in the partial latin square represented by the input dictionary.
:param fixed: A dictionary of filled cells of a partial latin square.
:param size: Number of rows and columns in the completed latin square.
:return A complete digraph with edge list-assignment representing a partial latin square completion problem.
"""
G = nx.complete_graph(size, create_using = nx.DiGraph)
for node in G.nodes():
G.add_edge(node, node)
nx.set_edge_attributes(G, list_assignment(fixed, size), "permissible")
return(G)

5 changes: 0 additions & 5 deletions tests/test_latin.py

This file was deleted.

7 changes: 7 additions & 0 deletions tests/test_pls-list-colouring-problem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import ryser as ry

def test_pls_list_colouring_problem():
F = {1:1, 2:2, 6:1}
G = ry.pls_list_colouring_problem(F, 3)
assert list(G.nodes()) == [0, 1, 2]
assert list(G.edges(data = True)) == [(0, 1, {'permissible': [2]}), (0, 2, {'permissible': [3]}), (0, 0, {'permissible': [1]}), (1, 0, {'permissible': [2, 3]}), (1, 2, {'permissible': [1]}), (1, 1, {'permissible': [3]}), (2, 0, {'permissible': [2, 3]}), (2, 1, {'permissible': [1, 3]}), (2, 2, {'permissible': [2, 3]})]

0 comments on commit 2e87a79

Please sign in to comment.