made QMC much faster by using a better data structure tostore the QMC tables.

This commit is contained in:
hneemann 2016-05-30 09:18:51 +02:00
parent ea163b569f
commit 33a24aa418
6 changed files with 201 additions and 57 deletions

View File

@ -58,8 +58,8 @@ public class ModelAnalyser {
if (inputs.size() == 0) if (inputs.size() == 0)
throw new AnalyseException(Lang.get("err_analyseNoInputs")); throw new AnalyseException(Lang.get("err_analyseNoInputs"));
if (inputs.size() > 9) if (inputs.size() > 12)
throw new AnalyseException(Lang.get("err_toManyInputs_N", 9)); throw new AnalyseException(Lang.get("err_toManyInputs_N", 12));
if (outputs.size() == 0) if (outputs.size() == 0)
throw new AnalyseException(Lang.get("err_analyseNoOutputs")); throw new AnalyseException(Lang.get("err_analyseNoOutputs"));
rows = 1 << inputs.size(); rows = 1 << inputs.size();

View File

@ -20,7 +20,7 @@ import static de.neemann.digital.analyse.expression.Operation.or;
*/ */
public class QuineMcCluskey { public class QuineMcCluskey {
private final ArrayList<TableRow> rows; private final TableRows rows;
private final ArrayList<Variable> variables; private final ArrayList<Variable> variables;
private final ArrayList<TableRow> primes; private final ArrayList<TableRow> primes;
@ -31,11 +31,11 @@ public class QuineMcCluskey {
*/ */
public QuineMcCluskey(ArrayList<Variable> variables) { public QuineMcCluskey(ArrayList<Variable> variables) {
this.variables = variables; this.variables = variables;
this.rows = new ArrayList<>(); this.rows = new TableRows();
this.primes = new ArrayList<>(); this.primes = new ArrayList<>();
} }
private QuineMcCluskey(ArrayList<Variable> variables, ArrayList<TableRow> rows, ArrayList<TableRow> primes) { private QuineMcCluskey(ArrayList<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;
@ -51,7 +51,7 @@ public class QuineMcCluskey {
public QuineMcCluskey(Expression expression) throws ExpressionException { public QuineMcCluskey(Expression expression) throws ExpressionException {
ContextFiller context = new ContextFiller(expression); ContextFiller context = new ContextFiller(expression);
variables = context.getVariables(); variables = context.getVariables();
rows = new ArrayList<>(); rows = new TableRows();
fillTableWith(new BoolTableExpression(expression, context)); fillTableWith(new BoolTableExpression(expression, context));
primes = new ArrayList<>(); primes = new ArrayList<>();
} }
@ -73,7 +73,6 @@ public class QuineMcCluskey {
add(i, value.equals(ThreeStateValue.dontCare)); add(i, value.equals(ThreeStateValue.dontCare));
} }
} }
Collections.sort(rows);
return this; return this;
} }
@ -129,27 +128,29 @@ public class QuineMcCluskey {
QuineMcCluskey simplifyStep() { QuineMcCluskey simplifyStep() {
ArrayList<TableRow> newRows = new ArrayList<>(); TableRows newRows = new TableRows();
for (int i = 0; i < rows.size() - 1; i++)
for (int j = i + 1; j < rows.size(); j++) {
TableRow r1 = rows.get(i); for (ArrayList<TableRow> list : rows.listIterable())
TableRow r2 = rows.get(j); for (int i = 0; i < list.size() - 1; i++)
for (int j = i + 1; j < list.size(); j++) {
int index = checkCompatible(r1, r2); TableRow r1 = list.get(i);
if (index >= 0) { TableRow r2 = list.get(j);
// can optimize;
TableRow newRow = new TableRow(r1);
newRow.setToOptimized(index);
newRow.addSource(r1.getSource());
newRow.addSource(r2.getSource());
r1.setUsed(); int index = checkCompatible(r1, r2);
r2.setUsed(); if (index >= 0) {
// can optimize;
TableRow newRow = new TableRow(r1);
newRow.setToOptimized(index);
newRow.addSource(r1.getSource());
newRow.addSource(r2.getSource());
newRows.add(newRow); r1.setUsed();
r2.setUsed();
newRows.add(newRow);
}
} }
}
ArrayList<TableRow> np = new ArrayList<TableRow>(); ArrayList<TableRow> np = new ArrayList<TableRow>();
np.addAll(primes); np.addAll(primes);
@ -161,13 +162,13 @@ public class QuineMcCluskey {
} }
QuineMcCluskey removeDuplicates() { QuineMcCluskey removeDuplicates() {
ArrayList<TableRow> newRows = new ArrayList<TableRow>(); TableRows newRows = new TableRows();
for (TableRow r : rows) { for (TableRow r : rows) {
int i = newRows.indexOf(r); TableRow i = newRows.findRow(r);
if (i < 0) { if (i == null) {
newRows.add(r); newRows.add(r);
} else { } else {
newRows.get(i).addSource(r.getSource()); i.addSource(r.getSource());
} }
} }
@ -185,12 +186,8 @@ public class QuineMcCluskey {
} }
private int checkCompatible(TableRow r1, TableRow r2) { private int checkCompatible(TableRow r1, TableRow r2) {
for (int i = 0; i < r1.size(); i++) { if (r1.getOptimizedFlags() != r2.getOptimizedFlags())
if (r1.get(i) == TableItem.optimized || r2.get(i) == TableItem.optimized) { return -1;
if (!r1.get(i).equals(r2.get(i)))
return -1;
}
}
int difIndex = -1; int difIndex = -1;
for (int i = 0; i < r1.size(); i++) { for (int i = 0; i < r1.size(); i++) {
@ -207,7 +204,12 @@ public class QuineMcCluskey {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
ArrayList<TableRow> newList = new ArrayList<TableRow>();
for (TableRow r : rows) { for (TableRow r : rows) {
newList.add(r);
}
Collections.sort(newList);
for (TableRow r : newList) {
sb.append(r.toString()); sb.append(r.toString());
sb.append("\n"); sb.append("\n");
} }
@ -240,7 +242,7 @@ public class QuineMcCluskey {
* @param variables the variables to use to build the expression * @param variables the variables to use to build the expression
* @return the expression * @return the expression
*/ */
public static Expression addAnd(Expression e, ArrayList<TableRow> rows, ArrayList<Variable> variables) { public static Expression addAnd(Expression e, Iterable<TableRow> rows, ArrayList<Variable> variables) {
for (TableRow r : rows) { for (TableRow r : rows) {
Expression n = r.getExpression(variables); Expression n = r.getExpression(variables);
if (e == null) if (e == null)

View File

@ -22,8 +22,9 @@ import static de.neemann.digital.analyse.expression.Operation.and;
public class TableRow implements Comparable<TableRow> { public class TableRow implements Comparable<TableRow> {
private final TableItem[] items; private final TableItem[] items;
private boolean used = false;
private final TreeSet<Integer> source; private final TreeSet<Integer> source;
private boolean used = false;
private long optimizedFlags;
/** /**
* Copies the given table row * Copies the given table row
@ -34,10 +35,11 @@ public class TableRow implements Comparable<TableRow> {
this(tr.size()); this(tr.size());
for (int i = 0; i < size(); i++) for (int i = 0; i < size(); i++)
items[i] = tr.get(i); items[i] = tr.get(i);
optimizedFlags = tr.optimizedFlags;
} }
/** /**
* Creates a new tyble row * Creates a new table row
* *
* @param cols number of columns * @param cols number of columns
*/ */
@ -52,7 +54,7 @@ public class TableRow implements Comparable<TableRow> {
* @param cols the number of columns * @param cols the number of columns
* @param bitValue the value representing the bits in the row * @param bitValue the value representing the bits in the row
* @param index the index of the original source row * @param index the index of the original source row
* @param dontCare dont 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);
@ -70,7 +72,7 @@ public class TableRow implements Comparable<TableRow> {
} }
/** /**
* The item at the given indes * The item at the given index
* *
* @param index the comumns index * @param index the comumns index
* @return the value * @return the value
@ -80,12 +82,23 @@ public class TableRow implements Comparable<TableRow> {
} }
/** /**
* Sets the given idex to optimized * Sets the given index to optimized
* *
* @param index the columns index * @param index the columns index
*/ */
public void setToOptimized(int index) { public void setToOptimized(int index) {
items[index] = TableItem.optimized; items[index] = TableItem.optimized;
optimizedFlags |= 1L << index;
}
/**
* Returns the optimized flags.
* All Variables which are deleted/optimized in this row are marked by a one bit at their position.
*
* @return the flags
*/
public long getOptimizedFlags() {
return optimizedFlags;
} }
@Override @Override
@ -151,7 +164,7 @@ public class TableRow implements Comparable<TableRow> {
@Override @Override
public int compareTo(TableRow tableRow) { public int compareTo(TableRow tableRow) {
return Integer.compare(countOnes(), tableRow.countOnes()); return toString().compareTo(tableRow.toString());
} }
/** /**

View File

@ -0,0 +1,124 @@
package de.neemann.digital.analyse.quinemc;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
/**
* Set of rows stored in a special way to make comparisons faster
*
* @author hneemann
*/
class TableRows implements Iterable<TableRow> {
private final TreeMap<Long, ArrayList<TableRow>> rows;
private int size;
TableRows() {
rows = new TreeMap<>();
}
public int size() {
return size;
}
public void add(TableRow tableRow) {
long flags = tableRow.getOptimizedFlags();
getList(flags).add(tableRow);
size++;
}
private ArrayList<TableRow> getList(long flags) {
ArrayList<TableRow> list = rows.get(flags);
if (list == null) {
list = new ArrayList<>();
rows.put(flags, list);
}
return list;
}
public void clear() {
rows.clear();
size = 0;
}
public void addAll(TableRows newRows) {
for (Map.Entry<Long, ArrayList<TableRow>> e : newRows.rows.entrySet()) {
ArrayList<TableRow> values = e.getValue();
getList(e.getKey()).addAll(values);
size += values.size();
}
}
public boolean isEmpty() {
return size == 0;
}
/**
* Returns the row stored in this list which is equal to the given row
*
* @param r the row to look for
* @return the row found
*/
TableRow findRow(TableRow r) {
ArrayList<TableRow> list = rows.get(r.getOptimizedFlags());
if (list == null)
return null;
int i = list.indexOf(r);
if (i < 0)
return null;
else
return list.get(i);
}
@Override
public Iterator<TableRow> iterator() {
return new RowIterator(rows.values().iterator());
}
public Iterable<ArrayList<TableRow>> listIterable() {
return rows.values();
}
public TableRow get(int i) {
for (Map.Entry<Long, ArrayList<TableRow>> e : rows.entrySet()) {
ArrayList<TableRow> list = e.getValue();
if (i < list.size())
return list.get(i);
else
i -= list.size();
}
throw new IndexOutOfBoundsException();
}
private class RowIterator implements Iterator<TableRow> {
private final Iterator<ArrayList<TableRow>> listIter;
private Iterator<TableRow> itemIter;
RowIterator(Iterator<ArrayList<TableRow>> iterator) {
listIter = iterator;
itemIter = null;
}
@Override
public boolean hasNext() {
while (itemIter == null && listIter.hasNext()) {
itemIter = listIter.next().iterator();
if (!itemIter.hasNext())
itemIter = null;
}
return itemIter != null;
}
@Override
public TableRow next() {
TableRow next = itemIter.next();
if (!itemIter.hasNext())
itemIter = null;
return next;
}
}
}

View File

@ -31,14 +31,15 @@ public class QuineMcCluskeyTest extends TestCase {
Expression e = or(and(a, and(c, d)), or(and(not(c), not(d)), and(not(b), c))); Expression e = or(and(a, and(c, d)), or(and(not(c), not(d)), and(not(b), c)));
QuineMcCluskey t = new QuineMcCluskey(e); QuineMcCluskey t = new QuineMcCluskey(e);
assertEquals("0000,1\n" + assertEquals(
"0000,1\n" +
"0010,2\n" + "0010,2\n" +
"0011,3\n" +
"0100,4\n" + "0100,4\n" +
"1000,5\n" + "1000,5\n" +
"0011,3\n" +
"1010,6\n" + "1010,6\n" +
"1011,7\n" +
"1100,8\n" + "1100,8\n" +
"1011,7\n" +
"1111,9\n", t.toString()); "1111,9\n", t.toString());
} }
@ -53,25 +54,28 @@ public class QuineMcCluskeyTest extends TestCase {
QuineMcCluskey t = new QuineMcCluskey(e).simplifyStep(); QuineMcCluskey t = new QuineMcCluskey(e).simplifyStep();
assertFalse(t.isFinished()); assertFalse(t.isFinished());
assertEquals("00-0,1,2\n" + assertEquals(
"0-00,1,4\n" +
"-000,1,5\n" + "-000,1,5\n" +
"-010,2,6\n" +
"-011,3,7\n" +
"-100,4,8\n" +
"0-00,1,4\n" +
"00-0,1,2\n" +
"001-,2,3\n" + "001-,2,3\n" +
"-010,2,6\n" + "1-00,5,8\n" +
"-100,4,8\n" + "1-11,7,9\n" +
"10-0,5,6\n" + "10-0,5,6\n" +
"1-00,5,8\n" + "101-,6,7\n",
"-011,3,7\n" + t.toString());
"101-,6,7\n" +
"1-11,7,9\n", t.toString());
t = t.simplifyStep(); t = t.simplifyStep();
assertFalse(t.isFinished()); assertFalse(t.isFinished());
assertEquals("-0-0,1,2,5,6\n" + assertEquals(
"--00,1,4,5,8\n" + "--00,1,4,5,8\n" +
"--00,1,4,5,8\n" +
"-0-0,1,2,5,6\n" +
"-0-0,1,2,5,6\n" + "-0-0,1,2,5,6\n" +
"--00,1,4,5,8\n" +
"-01-,2,3,6,7\n" + "-01-,2,3,6,7\n" +
"-01-,2,3,6,7\n", t.toString()); "-01-,2,3,6,7\n", t.toString());
@ -82,8 +86,9 @@ public class QuineMcCluskeyTest extends TestCase {
t = t.removeDuplicates(); t = t.removeDuplicates();
assertFalse(t.isFinished()); assertFalse(t.isFinished());
assertEquals("-0-0,1,2,5,6\n" + assertEquals(
"--00,1,4,5,8\n" + "--00,1,4,5,8\n" +
"-0-0,1,2,5,6\n" +
"-01-,2,3,6,7\n", t.toString()); "-01-,2,3,6,7\n", t.toString());
t = t.simplifyStep(); t = t.simplifyStep();
@ -94,8 +99,8 @@ public class QuineMcCluskeyTest extends TestCase {
primes = t.getPrimes(); primes = t.getPrimes();
assertEquals(4, primes.size()); assertEquals(4, primes.size());
assertEquals("1-11,7,9", primes.get(0).toString()); assertEquals("1-11,7,9", primes.get(0).toString());
assertEquals("-0-0,1,2,5,6", primes.get(1).toString()); assertEquals("-0-0,1,2,5,6", primes.get(2).toString());
assertEquals("--00,1,4,5,8", primes.get(2).toString()); assertEquals("--00,1,4,5,8", primes.get(1).toString());
assertEquals("-01-,2,3,6,7", primes.get(3).toString()); assertEquals("-01-,2,3,6,7", primes.get(3).toString());
Expression exp = t.getExpression(); Expression exp = t.getExpression();

View File

@ -83,7 +83,7 @@ public class Gal16V8JEDECExporterTest extends TestCase {
"QF2194*\r\n" + "QF2194*\r\n" +
"G0*\r\n" + "G0*\r\n" +
"F0*\r\n" + "F0*\r\n" +
"L256 10111110110111011111111111111111*\r\n" + "L256 10111110110111011111111111111111*\r\n" + // fuses are created with WinCUPL 5.0
"L288 10111101111011111111111111111111*\r\n" + "L288 10111101111011111111111111111111*\r\n" +
"L320 01111110111011101111111111111111*\r\n" + "L320 01111110111011101111111111111111*\r\n" +
"L352 01111101111111011111111111111111*\r\n" + "L352 01111101111111011111111111111111*\r\n" +