Skip to main content

Solve exact cover problems for multisets. Fork of exact_cover

Project description

Finding Exact Covers in NumPy for Multisets

PyPI version Deploy wheels to pypi Run Python tests

This is a Python 3 package to solve exact cover problems using Numpy. It is based on https://github.com/moygit/exact_cover_np by Moy Easwaran. Jack Grahl ported it to Python 3, fixed some bugs and made lots of small improvements to the packaging. Niklas Zapatka extended to algorithm to multisets.

The original package by Moy was designed to solve sudoku. Now this package is only designed to solve exact cover problems given as byte arrays. The number in each cell states the multiplicity of the respective elementin the multiset. It can be used to solve sudoku and a variety of combinatorial problems. However the code to reduce a sudoku to an exact cover problem is no longer part of this project. It can be found at:

Another project, 'polyomino' by Jack Grahl uses this algorithm to solve polyomino tiling problems. It can be found at:

Summary

The exact cover problem is as follows: given a set X and a collection S of subsets of X, we want to find a subcollection S* of S that is an exact cover or partition of X. In other words, S* is a bunch of subsets of X whose union is X, and which have empty intersection with each other. (Example below; more details on wikipedia.)

This NumPy module uses Donald Knuth's Algorithm X (also known as Dancing Links) to find exact covers of sets. For details on Algorithm X please see either the Wikipedia page or Knuth's paper. Specifically, we use the Knuth/Hitotsumatsu/Noshita method of Dancing Links for efficient backtracking. Please see Knuth's paper for details.

This fork extends the algorithm such that X and the sets in S are multisets (also known as bags). For instance, if X contains the element a two times, a solution must include either exactly one set containing a twice or exactly two sets containing a once.

How to Use It

Suppose X = {0,1,2,3,4}, and suppose S = {A,B,C,D}, where

A = {0, 3}
B = {0, 1, 2}
C = {1, 2}
D = {4}.

Here we can just eyeball these sets and conclude that S* = {A,C,D} forms an exact cover: each element of X is in one of these sets (i.e. is "covered" by one of these sets), and no element of X is in more than one.

We'd use exact_multiset_cover to solve the problem as follows: using 1 to denote that a particular member of X is in a subset and 0 to denote that it's not, we can represent the sets as

A = 1,0,0,1,0    # The 0th and 3rd entries are 1 since 0 and 3 are in A; the rest are 0.
B = 1,1,1,0,0    # The 0th, 1st, and 2nd entries are 1, and the rest are 0,
C = 0,1,1,0,0    # etc.
D = 0,0,0,0,1

Now we can call exact_multiset_cover:

>>> import numpy as np
>>> import exact_multiset_cover as ec
>>> S = np.array([[1,0,0,1,0],[1,1,1,0,0],[0,1,1,0,0],[0,0,0,0,1]], dtype=bool)
>>> print(ec.get_exact_cover(S))
[0 2 3]

This is telling us that the 0th row (i.e. A), the 2nd row (i.e. C), and the 3rd row (i.e. D) together form an exact cover.

To see the total number of distinct solutions, we can use the function get_solution_count:

>>> ec.get_solution_count(S)
1

See the file examples.md for more detailed examples of use.

Implementation Overview

The NumPy module (exact_multiset_cover) is implemented in four pieces:

  • The lowest level is quad_linked_list, which implements a circular linked-list with left-, right-, up-, and down-links.
  • This is used in sparse_matrix to implement the type of sparse representation of matrices that Knuth describes in his paper (in brief, each column contains all its non-zero entries, and each non-zero cell also points to the (horizontally) next non-zero cell in either direction).
  • Sparse matrices are used in dlx to implement Knuth's Dancing Links version of his Algorithm X, which calculates exact covers.
  • exact_cover provides the glue code letting us invoke dlx on NumPy arrays.

The package now has some pure Python modules for helper functions, with the main algorithm in the C-only package exact_cover_impl.

How to develop

The package uses poetry and most of the setup for development uses that tool.

To install locally (as an editable package): poetry install

To build: poetry build

To run tests: poetry run test or poetry run doctest

To open a Python shell with the package available: poetry run python

The exception is running the C unit tests: make c_tests

Repository

  • build/ The location where files are built.
  • dist/ The location for fully prepared files.
  • exact_multiset_cover/ The Python code.
  • obj/ Where the compiled C code is going to be output.
  • src/ The C sources.
  • tests/ Tests for both the Python package and the C code.
  • tools/ Code used in analysing and working with the library. This is not distributed with the package.

Acknowledgements

Thanks very much to Moy Easwaran (https://github.com/moygit) for his inspiring work!

Thanks to Jack Grahl for porting this to Python 3 and improving the code!

Munit aka µnit (https://nemequ.github.io/munit/) is a wonderful unit testing framework for C code.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

exact_multiset_cover-1.5.1.tar.gz (22.4 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

exact_multiset_cover-1.5.1-cp313-cp313-macosx_14_0_x86_64.whl (34.2 kB view details)

Uploaded CPython 3.13macOS 14.0+ x86-64

exact_multiset_cover-1.5.1-cp312-cp312-manylinux_2_39_x86_64.whl (46.7 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.39+ x86-64

File details

Details for the file exact_multiset_cover-1.5.1.tar.gz.

File metadata

  • Download URL: exact_multiset_cover-1.5.1.tar.gz
  • Upload date:
  • Size: 22.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.4 CPython/3.13.2 Darwin/23.3.0

File hashes

Hashes for exact_multiset_cover-1.5.1.tar.gz
Algorithm Hash digest
SHA256 c6d70cddcab7989f3c388b45ebd1e510ca9765eeeaaa63a174687839b9b16f0b
MD5 532ef2b9c2f28d745cedd6ca3fd761e9
BLAKE2b-256 e8eb24564d517919993f9bfe35932d83ae8903c48333691af89ba659021363d3

See more details on using hashes here.

File details

Details for the file exact_multiset_cover-1.5.1-cp313-cp313-macosx_14_0_x86_64.whl.

File metadata

File hashes

Hashes for exact_multiset_cover-1.5.1-cp313-cp313-macosx_14_0_x86_64.whl
Algorithm Hash digest
SHA256 c26115fb3bd382b4d65b9e2b134dc5e4c368334cae1ee44bb84661619709b9af
MD5 59d0e6766643d36ddfde75bed3425dca
BLAKE2b-256 e6842662694b4db1ba68991c41d2e2cd683a7526fefbe085ded2fe2e037ad406

See more details on using hashes here.

File details

Details for the file exact_multiset_cover-1.5.1-cp312-cp312-manylinux_2_39_x86_64.whl.

File metadata

File hashes

Hashes for exact_multiset_cover-1.5.1-cp312-cp312-manylinux_2_39_x86_64.whl
Algorithm Hash digest
SHA256 597229373201f8dff240d7a51158daccb7ce0396ea35864e5aebedb96ea38595
MD5 e1e47ebad58f576f85e244a5fba3f76f
BLAKE2b-256 72ff903850c69efc3309526aa4e877ce8bfcf20299df1dd72f88ffafee8466cb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page