From fc2787444d23031d7b5f006f9c6dfc57aa699c24 Mon Sep 17 00:00:00 2001 From: Matthew Henderson Date: Mon, 2 Dec 2024 10:17:02 +0000 Subject: [PATCH 01/10] Remove Latin class. --- ryser/__init__.py | 54 ----------------------------------------------- 1 file changed, 54 deletions(-) diff --git a/ryser/__init__.py b/ryser/__init__.py index 2275938..14b230b 100644 --- a/ryser/__init__.py +++ b/ryser/__init__.py @@ -130,57 +130,3 @@ 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) - From fa3f2cfce63ccc7658422221cb5c8a52f4eb27c7 Mon Sep 17 00:00:00 2001 From: Matthew Henderson Date: Mon, 2 Dec 2024 10:17:25 +0000 Subject: [PATCH 02/10] Bump version number: 0.1.0 -> 0.1.0.9000. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 49898a5..a190c76 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "ryser" -version = "0.1.0" +version = "0.1.0.9000" description = "Latin squares and related designs." authors = ["Matthew Henderson "] readme = "README.md" From 62efec1c6101f2a7624e370adef072192925e06f Mon Sep 17 00:00:00 2001 From: Matthew Henderson Date: Mon, 2 Dec 2024 10:39:40 +0000 Subject: [PATCH 03/10] Add Makefile. --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..97e25de --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +test: + poetry run pytest + +install: + poetry install From 53f7212367b435c961e82aa7c4ee39f5bc991a59 Mon Sep 17 00:00:00 2001 From: Matthew Henderson Date: Mon, 2 Dec 2024 10:39:58 +0000 Subject: [PATCH 04/10] Remove testing of removed Latin class. --- tests/test_latin.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/test_latin.py b/tests/test_latin.py index 7eb4a2f..a330123 100644 --- a/tests/test_latin.py +++ b/tests/test_latin.py @@ -1,5 +1,2 @@ import ryser -def test_latin(): - a = ryser.Latin({1:1, 12:3}, 9) - assert a.fixed_cells() == {1:1, 12:3} From f2f60abaefcb49eb2ed7532c20da6fee607e3c0e Mon Sep 17 00:00:00 2001 From: Matthew Henderson Date: Wed, 4 Dec 2024 10:08:38 +0000 Subject: [PATCH 05/10] Remove gitpod config. --- .gitpod.yml | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 .gitpod.yml diff --git a/.gitpod.yml b/.gitpod.yml deleted file mode 100644 index 63a3e4f..0000000 --- a/.gitpod.yml +++ /dev/null @@ -1,10 +0,0 @@ -# This configuration file was automatically generated by Gitpod. -# Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml) -# and commit this file to your remote git repository to share the goodness with others. - -# Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart - -tasks: - - init: make - - From 887d7b4f0684fca6e0889172263a66c1c33449be Mon Sep 17 00:00:00 2001 From: Matthew Henderson Date: Wed, 4 Dec 2024 10:08:53 +0000 Subject: [PATCH 06/10] Add networkx to dependencies. --- poetry.lock | 23 +++++++++++++++++++++-- pyproject.toml | 7 ++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index b0e7c25..e5e404f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "colorama" @@ -36,6 +36,25 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "networkx" +version = "3.4.2" +description = "Python package for creating and manipulating graphs and networks" +optional = false +python-versions = ">=3.10" +files = [ + {file = "networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f"}, + {file = "networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1"}, +] + +[package.extras] +default = ["matplotlib (>=3.7)", "numpy (>=1.24)", "pandas (>=2.0)", "scipy (>=1.10,!=1.11.0,!=1.11.1)"] +developer = ["changelist (==0.5)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] +doc = ["intersphinx-registry", "myst-nb (>=1.1)", "numpydoc (>=1.8.0)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.15)", "sphinx (>=7.3)", "sphinx-gallery (>=0.16)", "texext (>=0.6.7)"] +example = ["cairocffi (>=1.7)", "contextily (>=1.6)", "igraph (>=0.11)", "momepy (>=0.7.2)", "osmnx (>=1.9)", "scikit-learn (>=1.5)", "seaborn (>=0.13)"] +extra = ["lxml (>=4.6)", "pydot (>=3.0.1)", "pygraphviz (>=1.14)", "sympy (>=1.10)"] +test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] + [[package]] name = "packaging" version = "24.0" @@ -98,4 +117,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "b9db7cc3b54b4d01fa0dabeb26a042fc6f773eaf8aa452caa6151fa6668550df" +content-hash = "2bc1bd453dd69fc123bcd77602ce785a7cdd32eff29ed4f3b9e5a9d094bac417" diff --git a/pyproject.toml b/pyproject.toml index a190c76..3cf0fe4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,13 @@ [tool.poetry] name = "ryser" -version = "0.1.0.9000" +version = "0.1.0.9001" description = "Latin squares and related designs." authors = ["Matthew Henderson "] readme = "README.md" [tool.poetry.dependencies] python = "^3.10" +networkx = "^3.4.2" [tool.poetry.group.test.dependencies] @@ -16,7 +17,3 @@ pytest = "^8.1.1" requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" -[tool.pytest.ini_options] -pythonpath = [ - "." -] From 91c92d74a0ffb5a51c21589ae2e28759793d99ad Mon Sep 17 00:00:00 2001 From: Matthew Henderson Date: Wed, 4 Dec 2024 10:10:09 +0000 Subject: [PATCH 07/10] Implement partial latin square list colouring problem. --- ryser/__init__.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/ryser/__init__.py b/ryser/__init__.py index 14b230b..9155f3a 100644 --- a/ryser/__init__.py +++ b/ryser/__init__.py @@ -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. @@ -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]) @@ -130,3 +132,20 @@ def com_2_csm(P, size): L[cell(row, col, size)] = int(P[i][j]) return L + +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) + From 5b3d2835461c7c21640d90f6ed04b703dacee569 Mon Sep 17 00:00:00 2001 From: Matthew Henderson Date: Wed, 4 Dec 2024 10:10:38 +0000 Subject: [PATCH 08/10] Add tests for new function. Remove tests for removed Latin class. --- tests/test_latin.py | 2 -- tests/test_pls-list-colouring-problem.py | 7 +++++++ 2 files changed, 7 insertions(+), 2 deletions(-) delete mode 100644 tests/test_latin.py create mode 100644 tests/test_pls-list-colouring-problem.py diff --git a/tests/test_latin.py b/tests/test_latin.py deleted file mode 100644 index a330123..0000000 --- a/tests/test_latin.py +++ /dev/null @@ -1,2 +0,0 @@ -import ryser - diff --git a/tests/test_pls-list-colouring-problem.py b/tests/test_pls-list-colouring-problem.py new file mode 100644 index 0000000..4769ed4 --- /dev/null +++ b/tests/test_pls-list-colouring-problem.py @@ -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]})] From 28a884d00c266d24dfd0a86db805e3cd2369067a Mon Sep 17 00:00:00 2001 From: Matthew Henderson Date: Wed, 4 Dec 2024 10:11:45 +0000 Subject: [PATCH 09/10] Move library under src folder. --- {ryser => src/ryser}/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {ryser => src/ryser}/__init__.py (100%) diff --git a/ryser/__init__.py b/src/ryser/__init__.py similarity index 100% rename from ryser/__init__.py rename to src/ryser/__init__.py From f83071d4f29fae18ab2225b529e5d9427dc0c731 Mon Sep 17 00:00:00 2001 From: Matthew Henderson Date: Wed, 4 Dec 2024 10:14:34 +0000 Subject: [PATCH 10/10] Add versions 3.11 and 3.12 to packaging workflow matrix. --- .github/workflows/python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index bcdf535..f668a15 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -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