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)
throw new AnalyseException(Lang.get("err_analyseNoInputs"));
if (inputs.size() > 9)
throw new AnalyseException(Lang.get("err_toManyInputs_N", 9));
if (inputs.size() > 12)
throw new AnalyseException(Lang.get("err_toManyInputs_N", 12));
if (outputs.size() == 0)
throw new AnalyseException(Lang.get("err_analyseNoOutputs"));
rows = 1 << inputs.size();

View File

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

View File

@ -22,8 +22,9 @@ import static de.neemann.digital.analyse.expression.Operation.and;
public class TableRow implements Comparable<TableRow> {
private final TableItem[] items;
private boolean used = false;
private final TreeSet<Integer> source;
private boolean used = false;
private long optimizedFlags;
/**
* Copies the given table row
@ -34,10 +35,11 @@ public class TableRow implements Comparable<TableRow> {
this(tr.size());
for (int i = 0; i < size(); i++)
items[i] = tr.get(i);
optimizedFlags = tr.optimizedFlags;
}
/**
* Creates a new tyble row
* Creates a new table row
*
* @param cols number of columns
*/
@ -52,7 +54,7 @@ public class TableRow implements Comparable<TableRow> {
* @param cols the number of columns
* @param bitValue the value representing the bits in the 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) {
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
* @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
*/
public void setToOptimized(int index) {
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
@ -151,7 +164,7 @@ public class TableRow implements Comparable<TableRow> {
@Override
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)));
QuineMcCluskey t = new QuineMcCluskey(e);
assertEquals("0000,1\n" +
assertEquals(
"0000,1\n" +
"0010,2\n" +
"0011,3\n" +
"0100,4\n" +
"1000,5\n" +
"0011,3\n" +
"1010,6\n" +
"1011,7\n" +
"1100,8\n" +
"1011,7\n" +
"1111,9\n", t.toString());
}
@ -53,25 +54,28 @@ public class QuineMcCluskeyTest extends TestCase {
QuineMcCluskey t = new QuineMcCluskey(e).simplifyStep();
assertFalse(t.isFinished());
assertEquals("00-0,1,2\n" +
"0-00,1,4\n" +
assertEquals(
"-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" +
"-010,2,6\n" +
"-100,4,8\n" +
"1-00,5,8\n" +
"1-11,7,9\n" +
"10-0,5,6\n" +
"1-00,5,8\n" +
"-011,3,7\n" +
"101-,6,7\n" +
"1-11,7,9\n", t.toString());
"101-,6,7\n",
t.toString());
t = t.simplifyStep();
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" +
"-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", t.toString());
@ -82,8 +86,9 @@ public class QuineMcCluskeyTest extends TestCase {
t = t.removeDuplicates();
assertFalse(t.isFinished());
assertEquals("-0-0,1,2,5,6\n" +
assertEquals(
"--00,1,4,5,8\n" +
"-0-0,1,2,5,6\n" +
"-01-,2,3,6,7\n", t.toString());
t = t.simplifyStep();
@ -94,8 +99,8 @@ public class QuineMcCluskeyTest extends TestCase {
primes = t.getPrimes();
assertEquals(4, primes.size());
assertEquals("1-11,7,9", primes.get(0).toString());
assertEquals("-0-0,1,2,5,6", primes.get(1).toString());
assertEquals("--00,1,4,5,8", primes.get(2).toString());
assertEquals("-0-0,1,2,5,6", primes.get(2).toString());
assertEquals("--00,1,4,5,8", primes.get(1).toString());
assertEquals("-01-,2,3,6,7", primes.get(3).toString());
Expression exp = t.getExpression();

View File

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