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<>(); 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.variables = variables;
this.rows = rows; this.rows = rows;
this.primes = primes; this.primes = primes;
@ -141,7 +141,7 @@ public class QuineMcCluskey {
newRow.setToOptimized(index); newRow.setToOptimized(index);
TableRow r = newRows.findRow(newRow); TableRow r = newRows.findRow(newRow);
if (r==null) { if (r == null) {
newRow.addSource(r1.getSource()); newRow.addSource(r1.getSource());
newRow.addSource(r2.getSource()); newRow.addSource(r2.getSource());
newRows.add(newRow); newRows.add(newRow);
@ -225,67 +225,64 @@ public class QuineMcCluskey {
/** /**
* Simplify the primes * Simplify the primes
* *
* @param primeSelector the prome selector to use * @param primeSelector the prime selector to use
* @return this for call chaning * @return this for call chaining
*/ */
public QuineMcCluskey simplifyPrimes(PrimeSelector primeSelector) { public QuineMcCluskey simplifyPrimes(PrimeSelector primeSelector) {
ArrayList<TableRow> primesAvail = new ArrayList<TableRow>(primes);
primes.clear();
TreeSet<Integer> termIndices = new TreeSet<>(); TreeSet<Integer> columns = new TreeSet<>();
for (TableRow r : primesAvail) for (TableRow r : primes)
termIndices.addAll(r.getSource()); columns.addAll(r.getSource());
// Nach primtermen suchen, welche einen index exclusiv enthalten // remove all primes which are easy to remove
// Diese müssen in jedem Falle enthalten sein! while (true) {
for (int pr : termIndices) { // 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; primes.removeAll(rowsToDelete);
for (TableRow tr : primesAvail) {
if (tr.getSource().contains(pr)) { // find the cols to delete
if (foundPrime == null) { HashSet<Integer> colsToDelete = new HashSet<>();
foundPrime = tr; for (int c1 : columns) {
} else { for (int c2 : columns) {
foundPrime = null; if ((c1 != c2) && !colsToDelete.contains(c1) && smaller(c1, c2, primes))
break; colsToDelete.add(c2);
}
} }
} }
if (foundPrime != null) { if (colsToDelete.isEmpty() && rowsToDelete.isEmpty())
if (!primes.contains(foundPrime)) break;
primes.add(foundPrime);
}
}
primesAvail.removeAll(primes);
// Die, Indices die wir schon haben können raus; for (TableRow p : primes)
for (TableRow pr : primes) { p.getSource().removeAll(colsToDelete);
termIndices.removeAll(pr.getSource());
columns.removeAll(colsToDelete);
} }
if (!termIndices.isEmpty()) { // try to reduce the number of primes needed
if (primeSelector != null && !columns.isEmpty()) {
//Die noch übrigen Terme durchsuchen ob sie schon komplett dabei sind; ArrayList<TableRow> availPrimes = new ArrayList<>(primes.size());
Iterator<TableRow> it = primesAvail.iterator(); availPrimes.addAll(primes);
while (it.hasNext()) { primes.clear();
TableRow tr = it.next(); primeSelector.select(primes, availPrimes, columns);
boolean needed = false; if (primes.size() < availPrimes.size())
for (int i : tr.getSource()) { System.out.println("reduced from " + availPrimes.size() + " primes to " + primes.size()+" primes.");
if (termIndices.contains(i)) {
needed = true;
break;
}
}
if (!needed) {
it.remove();
}
}
primeSelector.select(primes, primesAvail, termIndices);
} }
return this; 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.Expression;
import de.neemann.digital.analyse.expression.Variable; import de.neemann.digital.analyse.expression.Variable;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.TreeSet; import java.util.TreeSet;
@ -55,12 +56,24 @@ public final class TableRow implements Comparable<TableRow> {
* @param dontCare true if don't care * @param dontCare true if don't care
*/ */
public TableRow(int cols, int bitValue, int index, boolean dontCare) { public TableRow(int cols, int bitValue, int index, boolean dontCare) {
this(cols); this(cols, bitValue);
if (!dontCare) if (!dontCare)
source.add(index); 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); state = Integer.reverse(bitValue) >>> (32 - cols);
} }
/** /**
* Sets the given index to optimized * Sets the given index to optimized
* *
@ -163,6 +176,17 @@ public final class TableRow implements Comparable<TableRow> {
source.addAll(s); 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 * Returns an expression build with the given variables
* *

View File

@ -17,7 +17,7 @@ public interface PrimeSelector {
* Selects the primes to use * Selects the primes to use
* *
* @param primes the list to add the primes to * @param primes the list to add the primes to
* @param primesAvail the available promes * @param primesAvail the available primes
* @param termIndices the indices * @param termIndices the indices
*/ */
void select(ArrayList<TableRow> primes, ArrayList<TableRow> primesAvail, TreeSet<Integer> termIndices); 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 * @throws ExpressionException
*/ */
public void testRegression() throws ExpressionException { public void testRegression() throws ExpressionException {
for (int n = 4; n < 8; n++) { for (int n = 4; n < 8; n++) {
// test some tables with n variables
for (int i = 0; i < 200; i++) { for (int i = 0; i < 200; i++) {
performTestCalculationRandom(n); performTestCalculationRandom(n);
} }
@ -63,6 +64,15 @@ public class QuineMcCluskeyDontCareTest extends TestCase {
performTestCalculation(n, tab); 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 { static private void performTestCalculation(int n, int[] tab) throws ExpressionException {
ArrayList<Variable> v = vars(n); ArrayList<Variable> v = vars(n);
Expression e = new QuineMcCluskey(v) 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; int size = 1 << n;
boolean[] table = new boolean[size]; boolean[] table = new boolean[size];

View File

@ -50,7 +50,7 @@ public class QuineMcCluskeyTest extends TestCase {
Variable c = new Variable("C"); Variable c = new Variable("C");
Variable d = new Variable("D"); 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(); QuineMcCluskey t = new QuineMcCluskey(e).simplifyStep();
assertFalse(t.isFinished()); assertFalse(t.isFinished());