new QMC prime selector

This commit is contained in:
hneemann 2017-03-09 11:26:01 +01:00
parent 4f9239697e
commit f3e1cd743b
7 changed files with 120 additions and 54 deletions

View File

@ -32,7 +32,7 @@ public class QuineMcCluskey {
this.primes = new ArrayList<>();
}
private QuineMcCluskey(List<Variable> variables, TableRows rows, ArrayList<TableRow> primes) {
QuineMcCluskey(List<Variable> variables, TableRows rows, ArrayList<TableRow> primes) {
this.variables = variables;
this.rows = rows;
this.primes = primes;
@ -141,7 +141,7 @@ public class QuineMcCluskey {
newRow.setToOptimized(index);
TableRow r = newRows.findRow(newRow);
if (r==null) {
if (r == null) {
newRow.addSource(r1.getSource());
newRow.addSource(r2.getSource());
newRows.add(newRow);
@ -225,67 +225,64 @@ public class QuineMcCluskey {
/**
* Simplify the primes
*
* @param primeSelector the prome selector to use
* @return this for call chaning
* @param primeSelector the prime selector to use
* @return this for call chaining
*/
public QuineMcCluskey simplifyPrimes(PrimeSelector primeSelector) {
ArrayList<TableRow> primesAvail = new ArrayList<TableRow>(primes);
primes.clear();
TreeSet<Integer> termIndices = new TreeSet<>();
for (TableRow r : primesAvail)
termIndices.addAll(r.getSource());
TreeSet<Integer> columns = new TreeSet<>();
for (TableRow r : primes)
columns.addAll(r.getSource());
// Nach primtermen suchen, welche einen index exclusiv enthalten
// Diese müssen in jedem Falle enthalten sein!
for (int pr : termIndices) {
// remove all primes which are easy to remove
while (true) {
// find rows to delete
HashSet<TableRow> rowsToDelete = new HashSet<>();
for (TableRow r1 : primes)
for (TableRow r2 : primes) {
if ((r1 != r2) && !rowsToDelete.contains(r1) && r1.getSource().containsAll(r2.getSource()))
rowsToDelete.add(r2);
}
TableRow foundPrime = null;
for (TableRow tr : primesAvail) {
if (tr.getSource().contains(pr)) {
if (foundPrime == null) {
foundPrime = tr;
} else {
foundPrime = null;
break;
}
primes.removeAll(rowsToDelete);
// find the cols to delete
HashSet<Integer> colsToDelete = new HashSet<>();
for (int c1 : columns) {
for (int c2 : columns) {
if ((c1 != c2) && !colsToDelete.contains(c1) && smaller(c1, c2, primes))
colsToDelete.add(c2);
}
}
if (foundPrime != null) {
if (!primes.contains(foundPrime))
primes.add(foundPrime);
}
}
primesAvail.removeAll(primes);
if (colsToDelete.isEmpty() && rowsToDelete.isEmpty())
break;
// Die, Indices die wir schon haben können raus;
for (TableRow pr : primes) {
termIndices.removeAll(pr.getSource());
for (TableRow p : primes)
p.getSource().removeAll(colsToDelete);
columns.removeAll(colsToDelete);
}
if (!termIndices.isEmpty()) {
//Die noch übrigen Terme durchsuchen ob sie schon komplett dabei sind;
Iterator<TableRow> it = primesAvail.iterator();
while (it.hasNext()) {
TableRow tr = it.next();
boolean needed = false;
for (int i : tr.getSource()) {
if (termIndices.contains(i)) {
needed = true;
break;
}
}
if (!needed) {
it.remove();
}
}
primeSelector.select(primes, primesAvail, termIndices);
// try to reduce the number of primes needed
if (primeSelector != null && !columns.isEmpty()) {
ArrayList<TableRow> availPrimes = new ArrayList<>(primes.size());
availPrimes.addAll(primes);
primes.clear();
primeSelector.select(primes, availPrimes, columns);
if (primes.size() < availPrimes.size())
System.out.println("reduced from " + availPrimes.size() + " primes to " + primes.size()+" primes.");
}
return this;
}
private boolean smaller(int c1, int c2, ArrayList<TableRow> primes) {
for (TableRow r : primes) {
Collection<Integer> s = r.getSource();
if (s.contains(c1) && !s.contains(c2))
return false;
}
return true;
}
}

View File

@ -5,6 +5,7 @@ import de.neemann.digital.analyse.expression.Constant;
import de.neemann.digital.analyse.expression.Expression;
import de.neemann.digital.analyse.expression.Variable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.TreeSet;
@ -55,12 +56,24 @@ public final class TableRow implements Comparable<TableRow> {
* @param dontCare true if don't care
*/
public TableRow(int cols, int bitValue, int index, boolean dontCare) {
this(cols);
this(cols, bitValue);
if (!dontCare)
source.add(index);
}
/**
* Creates a new row.
* Used only for exact cover tests!
*
* @param cols the number of columns
* @param bitValue the value representing the bits in the row
*/
public TableRow(int cols, int bitValue) {
this(cols);
state = Integer.reverse(bitValue) >>> (32 - cols);
}
/**
* Sets the given index to optimized
*
@ -163,6 +176,17 @@ public final class TableRow implements Comparable<TableRow> {
source.addAll(s);
}
/**
* Adds some sources to this line
*
* @param s the sources to add
* @return this for chained calls
*/
public TableRow addSource(Integer... s) {
addSource(Arrays.asList(s));
return this;
}
/**
* Returns an expression build with the given variables
*

View File

@ -17,7 +17,7 @@ public interface PrimeSelector {
* Selects the primes to use
*
* @param primes the list to add the primes to
* @param primesAvail the available promes
* @param primesAvail the available primes
* @param termIndices the indices
*/
void select(ArrayList<TableRow> primes, ArrayList<TableRow> primesAvail, TreeSet<Integer> termIndices);

View File

@ -43,12 +43,13 @@ public class QuineMcCluskeyDontCareTest extends TestCase {
/**
* for more the 3 variables we only test some random tables
* for more then 3 variables we only test some random tables
*
* @throws ExpressionException
*/
public void testRegression() throws ExpressionException {
for (int n = 4; n < 8; n++) {
// test some tables with n variables
for (int i = 0; i < 200; i++) {
performTestCalculationRandom(n);
}
@ -63,6 +64,15 @@ public class QuineMcCluskeyDontCareTest extends TestCase {
performTestCalculation(n, tab);
}
/**
* Generates a expression from the table and then checks if
* the expression reproduces the given table.
* Does not test if the expression is minimal.
*
* @param n the number of variables
* @param tab the truth table
* @throws ExpressionException
*/
static private void performTestCalculation(int n, int[] tab) throws ExpressionException {
ArrayList<Variable> v = vars(n);
Expression e = new QuineMcCluskey(v)

View File

@ -0,0 +1,35 @@
package de.neemann.digital.analyse.quinemc;
import de.neemann.digital.analyse.expression.Variable;
import junit.framework.TestCase;
import java.util.ArrayList;
/**
* Created by hneemann on 09.03.17.
*/
public class QuineMcCluskeyExactCover extends TestCase {
public void testExactCoverLoop() {
ArrayList<Variable> vars = new ArrayList<>();
vars.add(new Variable("a"));
vars.add(new Variable("b"));
vars.add(new Variable("c"));
vars.add(new Variable("d"));
ArrayList<TableRow> primes = new ArrayList<>();
primes.add(new TableRow(9, 0).addSource(1,3,5,7,9));
primes.add(new TableRow(9, 1).addSource(0,1,2,3,5,6,7,8,9));
primes.add(new TableRow(9, 2).addSource(0,2,3,5,8,9));
primes.add(new TableRow(9, 3).addSource(1,2,4,6,8,9));
primes.add(new TableRow(9, 4).addSource(0,1,4,5,8,9));
primes.add(new TableRow(9, 5).addSource(2,3,6,8,9));
primes.add(new TableRow(9, 6).addSource(2,4,5,7,9));
primes.add(new TableRow(9, 7).addSource(0,1,3,6,7,9));
QuineMcCluskey qmc = new QuineMcCluskey(vars, null, primes);
qmc=qmc.simplifyPrimes(null);
}
}

View File

@ -59,7 +59,7 @@ public class QuineMcCluskeyRegressionTest extends TestCase {
}
public static void testRegression(int n, int j) throws Exception, FormatterException {
public static void testRegression(int n, int j) throws Exception {
int size = 1 << n;
boolean[] table = new boolean[size];

View File

@ -50,7 +50,7 @@ public class QuineMcCluskeyTest extends TestCase {
Variable c = new Variable("C");
Variable d = new Variable("D");
Expression e = or(and(a, and(c, d)), or(and(not(c), not(d)), and(not(b), c)));
Expression e = or(and(a, c, d), and(not(c), not(d)), and(not(b), c));
QuineMcCluskey t = new QuineMcCluskey(e).simplifyStep();
assertFalse(t.isFinished());