diff --git a/src/main/java/de/neemann/digital/analyse/ModelAnalyser.java b/src/main/java/de/neemann/digital/analyse/ModelAnalyser.java index 01d1fa557..fcec51714 100644 --- a/src/main/java/de/neemann/digital/analyse/ModelAnalyser.java +++ b/src/main/java/de/neemann/digital/analyse/ModelAnalyser.java @@ -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(); diff --git a/src/main/java/de/neemann/digital/analyse/quinemc/QuineMcCluskey.java b/src/main/java/de/neemann/digital/analyse/quinemc/QuineMcCluskey.java index 140bdcd55..1abc3bd72 100644 --- a/src/main/java/de/neemann/digital/analyse/quinemc/QuineMcCluskey.java +++ b/src/main/java/de/neemann/digital/analyse/quinemc/QuineMcCluskey.java @@ -20,7 +20,7 @@ import static de.neemann.digital.analyse.expression.Operation.or; */ public class QuineMcCluskey { - private final ArrayList rows; + private final TableRows rows; private final ArrayList variables; private final ArrayList primes; @@ -31,11 +31,11 @@ public class QuineMcCluskey { */ public QuineMcCluskey(ArrayList variables) { this.variables = variables; - this.rows = new ArrayList<>(); + this.rows = new TableRows(); this.primes = new ArrayList<>(); } - private QuineMcCluskey(ArrayList variables, ArrayList rows, ArrayList primes) { + private QuineMcCluskey(ArrayList variables, TableRows rows, ArrayList 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 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 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 np = new ArrayList(); np.addAll(primes); @@ -161,13 +162,13 @@ public class QuineMcCluskey { } QuineMcCluskey removeDuplicates() { - ArrayList newRows = new ArrayList(); + 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 newList = new ArrayList(); 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 rows, ArrayList variables) { + public static Expression addAnd(Expression e, Iterable rows, ArrayList variables) { for (TableRow r : rows) { Expression n = r.getExpression(variables); if (e == null) diff --git a/src/main/java/de/neemann/digital/analyse/quinemc/TableRow.java b/src/main/java/de/neemann/digital/analyse/quinemc/TableRow.java index 8535e1de8..32a7f3ee2 100644 --- a/src/main/java/de/neemann/digital/analyse/quinemc/TableRow.java +++ b/src/main/java/de/neemann/digital/analyse/quinemc/TableRow.java @@ -22,8 +22,9 @@ import static de.neemann.digital.analyse.expression.Operation.and; public class TableRow implements Comparable { private final TableItem[] items; - private boolean used = false; private final TreeSet source; + private boolean used = false; + private long optimizedFlags; /** * Copies the given table row @@ -34,10 +35,11 @@ public class TableRow implements Comparable { 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 { * @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 { } /** - * 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 { } /** - * 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 { @Override public int compareTo(TableRow tableRow) { - return Integer.compare(countOnes(), tableRow.countOnes()); + return toString().compareTo(tableRow.toString()); } /** diff --git a/src/main/java/de/neemann/digital/analyse/quinemc/TableRows.java b/src/main/java/de/neemann/digital/analyse/quinemc/TableRows.java new file mode 100644 index 000000000..2014abc6d --- /dev/null +++ b/src/main/java/de/neemann/digital/analyse/quinemc/TableRows.java @@ -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 { + private final TreeMap> 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 getList(long flags) { + ArrayList 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> e : newRows.rows.entrySet()) { + ArrayList 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 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 iterator() { + return new RowIterator(rows.values().iterator()); + } + + public Iterable> listIterable() { + return rows.values(); + } + + + public TableRow get(int i) { + for (Map.Entry> e : rows.entrySet()) { + ArrayList list = e.getValue(); + if (i < list.size()) + return list.get(i); + else + i -= list.size(); + } + throw new IndexOutOfBoundsException(); + } + + private class RowIterator implements Iterator { + private final Iterator> listIter; + private Iterator itemIter; + + RowIterator(Iterator> 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; + } + } +} diff --git a/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyTest.java b/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyTest.java index d6d594dc5..91aedf4ba 100644 --- a/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyTest.java +++ b/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyTest.java @@ -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(); diff --git a/src/test/java/de/neemann/digital/builder/Gal16v8/Gal16V8JEDECExporterTest.java b/src/test/java/de/neemann/digital/builder/Gal16v8/Gal16V8JEDECExporterTest.java index 2a955e909..878ce2f7b 100644 --- a/src/test/java/de/neemann/digital/builder/Gal16v8/Gal16V8JEDECExporterTest.java +++ b/src/test/java/de/neemann/digital/builder/Gal16v8/Gal16V8JEDECExporterTest.java @@ -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" +