Skip to content

Commit

Permalink
Refactor QM to use python package structure
Browse files Browse the repository at this point in the history
  • Loading branch information
djcopley committed Dec 25, 2023
1 parent 04a31b9 commit e35760a
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 136 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/python-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Run unittests
run-name: ${{ github.actor }} is running unittests

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.8

- name: Run tests
run: python -m unittest tests/test_minimization.py
8 changes: 0 additions & 8 deletions .travis.yml

This file was deleted.

35 changes: 0 additions & 35 deletions CONTRIBUTING.md

This file was deleted.

78 changes: 60 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,79 @@
# QuineMcCluskey [![Build Status](https://travis-ci.org/djcopley/QuineMcCluskey.svg?branch=master)](https://travis-ci.org/djcopley/QuineMcCluskey)
# QuineMcCluskey

### Table of Contents
**[Introduction](#introduction)**<br>
**[Requirements](#requirements)**<br>
**[Usage](#usage)**<br>
**[Resources](#resources)**<br>
**[Contributing](#contributing)**<br>
**[License](#license)**<br>

### Introduction
The Quine–McCluskey algorithm (or the method of prime implicants) is a method used for minimization of Boolean functions
that was developed by Willard V. Quine and extended by Edward J. McCluskey. It is functionally identical to
Karnaugh mapping, but the tabular form makes it more efficient for use in computer algorithms, and it also gives a
deterministic way to check that the minimal form of a Boolean function has been reached. It is also referred to as
the tabulation method.
### Quine–McCluskey Algorithm Python Library

Welcome to the Quine–McCluskey Python library – a powerful tool for minimizing Boolean functions with ease!
Developed by Willard V. Quine and extended by Edward J. McCluskey, this algorithm is your go-to method for
simplifying Boolean expressions efficiently.

### Installation

Now you can install the Quine–McCluskey Python library using `pip`. Just run the following command:

```bash
pip install quinemccluskey
```

### Getting Started

Once installed, you can leverage the library's public API directly from Python. Two essential functions are at
your disposal:

1. **`minimize`**: Minimize Boolean functions with the provided minterms and optional don't care terms.
2. **`format_minimized_expression`**: Format the minimized expression for clearer representation.

### Command Line Interface

Additionally, the library provides a convenient command-line interface. After installation, you can use the
'qm' entry point directly from the terminal:

```bash
qm
```

### Requirements
This program requires python version 3.4 or higher to run.

Ensure you have Python version 3.6 or higher installed to use this library.

### Usage
Run the minimize.py file and follow the prompts. Don't care terms are optional, leave blank if there are none. Alternatively import the minimize.py
file into your project and call the minimize() function. Usage: minimize(n_bits, minterms, xterms). Function returns list of
essential prime and prime implicants.

![Minimization Gif](https://github.com/djcopley/QuineMcCluskey/blob/master/assets/minimization.gif?raw=true)
#### From Python:

```python
from quinemccluskey import minimize, format_minimized_expression

n_bits = 4
minterms = [0, 1, 2, 4, 8, 10, 12, 15]
xterms = [5, 6]

minimized_result = minimize(n_bits, minterms, xterms)
formatted_result = format_minimized_expression(minimized_result)

print(f"Minimized Expression: {formatted_result}")
```

#### From the Terminal:

```bash
qm
```

Follow the prompts to input your Boolean function details.

![Minimization Gif](https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExZ2JheWlrcWpmdDNqMnNsdThuc2t1eGVxZ25qN2Z1bGJjdHppZnR6MSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/DFDib94LuHfto0PREA/giphy.gif)

### Resources

* [Quine McCluskey Algorithm Wikipedia](https://en.wikipedia.org/wiki/Quine%E2%80%93McCluskey_algorithm)
* [Boolean Algebra](https://en.wikipedia.org/wiki/Boolean_algebra)

### Contributing
If you would like more information, please check out the full set of guidelines [here](https://github.com/djcopley/QuineMcCluskey/blob/master/CONTRIBUTING.md).
<br>Contribution is welcomed!

### License
This project is licensed under the [GNU General Public License v3.0](https://github.com/djcopley/QuineMcCluskey/blob/master/LICENSE)

This project is licensed under the [GNU General Public License v3.0](https://github.com/djcopley/QuineMcCluskey/blob/master/LICENSE).
Binary file removed assets/minimization.gif
Binary file not shown.
42 changes: 42 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[build-system]
requires = ["setuptools>=64.0", "setuptools_scm>=8"]
build-backend = "setuptools.build_meta"

[project]
name = "quinemccluskey"
dynamic = ["version"]
dependencies = []
authors = [
{ name = "Daniel Copley", email = "djcopley@users.noreply.github.com" },
]
description = """A powerful tool for minimizing Boolean functions"""

readme = "README.md"
requires-python = ">=3.6"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Operating System :: OS Independent",
"Topic :: Scientific/Engineering :: Mathematics",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)"
]

[tool.setuptools]
packages = ["quinemccluskey"]

[tool.setuptools_scm]

[project.scripts]
qm = "quinemccluskey.cli:cli"

[project.urls]
Homepage = "https://github.com/djcopley/QuineMcCluskey"
Repository = "https://github.com/djcopley/QuineMcCluskey.git"
Issues = "https://github.com/djcopley/QuineMcCluskey/issues"
1 change: 1 addition & 0 deletions quinemccluskey/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .minimize import minimize, format_minimized_expression
3 changes: 3 additions & 0 deletions quinemccluskey/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .cli import cli

cli()
13 changes: 13 additions & 0 deletions quinemccluskey/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from .minimize import minimize, format_minimized_expression


def cli():
variables = int(input("Enter number of terms: "))
mt = list(map(int, input("Enter minterms: ").split()))
dc = list(map(int, input("Enter don't care terms: ").split()))

minimized = minimize(variables, mt, dc)
formatted_minimized = format_minimized_expression(minimized)

print('\nMinimized Implicants: {}'.format(minimized))
print('Minimized Expression: {}'.format(formatted_minimized))
75 changes: 1 addition & 74 deletions minimize.py → quinemccluskey/minimize.py
Original file line number Diff line number Diff line change
@@ -1,67 +1,6 @@
#!/usr/bin/python3
"""
Quine McCluskey digital logic simplification
"""
import itertools

__author__ = 'Daniel Copley'
__version__ = 'v1.2'

class Term:
"""
Term class is used to keep track of implicants
"""

def __init__(self, bin_str):
self.bin_str = bin_str
self.covered = False

def __eq__(self, other):
if isinstance(other, Term):
return True if self.bin_str == other.bin_str else False
elif isinstance(other, str):
return True if self.bin_str == other else False
return False

def __len__(self):
return len(self.bin_str)

def __hash__(self):
return hash(self.bin_str)

def __str__(self):
return self.bin_str

def __repr__(self):
return str(self)

def __iter__(self):
for bit in self.bin_str:
yield bit

def __getitem__(self, index):
return self.bin_str[index]

def get_covered_terms(self):
"""
Method calculates and returns terms covered by Term object
:return: integer generator of covered terms
"""
base = 0
x_index = [index for index, item in enumerate(self.bin_str[::-1]) if item == '-']

for index, item in enumerate(self.bin_str[::-1]):
if item == '1':
base += 2 ** index

yield base

for i in range(len(x_index)):
for items in itertools.combinations(x_index, i + 1):
accumulator = 0
for index in items:
accumulator += 2 ** index
yield base + accumulator
from .term import Term


def differ_by_one(nums):
Expand Down Expand Up @@ -224,15 +163,3 @@ def minimize(n_bits, m_terms, x_terms):
m_terms = [i for i in m_terms if i not in max_prime_implicant.get_covered_terms()]

return solution


if __name__ == '__main__':
variables = int(input("Enter number of terms: "))
mt = list(map(int, input("Enter minterms: ").split()))
dc = list(map(int, input("Enter don't care terms: ").split()))

minimized = minimize(variables, mt, dc)
formatted_minimized = format_minimized_expression(minimized)

print('\nMinimized Implicants: {}'.format(minimized))
print('Minimized Expression: {}'.format(formatted_minimized))
58 changes: 58 additions & 0 deletions quinemccluskey/term.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import itertools


class Term:
"""
Term class is used to keep track of implicants
"""

def __init__(self, bin_str):
self.bin_str = bin_str
self.covered = False

def __eq__(self, other):
if isinstance(other, Term):
return True if self.bin_str == other.bin_str else False
elif isinstance(other, str):
return True if self.bin_str == other else False
return False

def __len__(self):
return len(self.bin_str)

def __hash__(self):
return hash(self.bin_str)

def __str__(self):
return self.bin_str

def __repr__(self):
return str(self)

def __iter__(self):
for bit in self.bin_str:
yield bit

def __getitem__(self, index):
return self.bin_str[index]

def get_covered_terms(self):
"""
Method calculates and returns terms covered by Term object
:return: integer generator of covered terms
"""
base = 0
x_index = [index for index, item in enumerate(self.bin_str[::-1]) if item == '-']

for index, item in enumerate(self.bin_str[::-1]):
if item == '1':
base += 2 ** index

yield base

for i in range(len(x_index)):
for items in itertools.combinations(x_index, i + 1):
accumulator = 0
for index in items:
accumulator += 2 ** index
yield base + accumulator
2 changes: 1 addition & 1 deletion tests/test_minimization.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import unittest
from minimize import *
from quinemccluskey.minimize import *


class TestMinimization(unittest.TestCase):
Expand Down

0 comments on commit e35760a

Please sign in to comment.