mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-17 17:04:42 -04:00
added the algorithm from Quine and McClusky
This commit is contained in:
parent
5aeb8525a0
commit
ba4df394cb
@ -0,0 +1,18 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class ComplexityInclNotVisitor implements ExpressionVisitor {
|
||||
private int counter = 0;
|
||||
|
||||
@Override
|
||||
public boolean visit(Expression expression) {
|
||||
counter++;
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getComplexity() {
|
||||
return counter;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class ComplexityVisitor implements ExpressionVisitor {
|
||||
private int counter = 0;
|
||||
|
||||
@Override
|
||||
public boolean visit(Expression expression) {
|
||||
if (!(expression instanceof Not))
|
||||
counter++;
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getComplexity() {
|
||||
return counter;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
import de.neemann.digital.analyse.expression.ExpressionException;
|
||||
|
||||
/**
|
||||
* A simple bool table
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public interface BoolTable {
|
||||
/**
|
||||
* @return the table row count
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* returns the value at the given row
|
||||
*
|
||||
* @param i the index
|
||||
* @return the value
|
||||
* @throws ExpressionException ExpressionException
|
||||
*/
|
||||
ThreeStateValue get(int i) throws ExpressionException;
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.expression.ExpressionException;
|
||||
|
||||
/**
|
||||
* A simple boolean array
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public class BoolTableBoolArray implements BoolTable {
|
||||
|
||||
private final boolean[] table;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param table the bool values
|
||||
*/
|
||||
public BoolTableBoolArray(boolean[] table) {
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return table.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreeStateValue get(int i) throws ExpressionException {
|
||||
return ThreeStateValue.value(table[i]);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.expression.ContextFiller;
|
||||
import de.neemann.digital.analyse.expression.Expression;
|
||||
import de.neemann.digital.analyse.expression.ExpressionException;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class BoolTableExpression implements BoolTable {
|
||||
private final Expression expression;
|
||||
private final ContextFiller context;
|
||||
|
||||
public BoolTableExpression(Expression expression, ContextFiller context) {
|
||||
this.expression = expression;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 1 << context.getVarCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreeStateValue get(int i) throws ExpressionException {
|
||||
context.setContextTo(i);
|
||||
return ThreeStateValue.value(expression.calculate(context));
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.expression.ExpressionException;
|
||||
|
||||
/**
|
||||
* A int array.
|
||||
* Zero and one behave as expected, any other value represents "don't care"
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public class BoolTableIntArray implements BoolTable {
|
||||
|
||||
private final int[] table;
|
||||
|
||||
/**
|
||||
* Creates a new instace
|
||||
*
|
||||
* @param table the int values
|
||||
*/
|
||||
public BoolTableIntArray(int[] table) {
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return table.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreeStateValue get(int i) throws ExpressionException {
|
||||
return ThreeStateValue.value(table[i]);
|
||||
}
|
||||
}
|
@ -0,0 +1,317 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.expression.*;
|
||||
import de.neemann.digital.analyse.quinemc.primeselector.PrimeSelector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static de.neemann.digital.analyse.expression.Operation.or;
|
||||
|
||||
/**
|
||||
* The algorithm from Quine and McClusky
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public class QuineMcClusky {
|
||||
|
||||
private final ArrayList<TableRow> rows;
|
||||
private final ArrayList<Variable> variables;
|
||||
private final ArrayList<TableRow> primes;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param variables the variables to use
|
||||
*/
|
||||
public QuineMcClusky(ArrayList<Variable> variables) {
|
||||
this.variables = variables;
|
||||
this.rows = new ArrayList<>();
|
||||
this.primes = new ArrayList<>();
|
||||
}
|
||||
|
||||
private QuineMcClusky(ArrayList<Variable> variables, ArrayList<TableRow> rows, ArrayList<TableRow> primes) {
|
||||
this.variables = variables;
|
||||
this.rows = rows;
|
||||
this.primes = primes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* The Bool table is build using the given expression
|
||||
*
|
||||
* @param expression the expression used to build the table
|
||||
* @throws ExpressionException ExpressionException
|
||||
*/
|
||||
public QuineMcClusky(Expression expression) throws ExpressionException {
|
||||
ContextFiller context = new ContextFiller(expression);
|
||||
variables = context.getVariables();
|
||||
rows = new ArrayList<>();
|
||||
fillTableWith(new BoolTableExpression(expression, context));
|
||||
primes = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the instance with the given values
|
||||
*
|
||||
* @param values the values
|
||||
* @return this for chained calls
|
||||
* @throws ExpressionException ExpressionException
|
||||
*/
|
||||
public QuineMcClusky fillTableWith(BoolTable values) throws ExpressionException {
|
||||
int n = 1 << variables.size();
|
||||
if (n != values.size())
|
||||
throw new ExpressionException("exact " + n + " values necessary, not " + values.size());
|
||||
for (int i = 0; i < n; i++) {
|
||||
ThreeStateValue value = values.get(i);
|
||||
if (!value.equals(ThreeStateValue.zero)) {
|
||||
add(i, value.equals(ThreeStateValue.dontCare));
|
||||
}
|
||||
}
|
||||
Collections.sort(rows);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
private void add(int i, boolean dontCare) {
|
||||
rows.add(new TableRow(variables.size(), i, rows.size() + 1, dontCare));
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplifies the given expression
|
||||
*
|
||||
* @param expression the expression to simplify
|
||||
* @return the simplified expression
|
||||
* @throws ExpressionException ExpressionException
|
||||
*/
|
||||
public static Expression simplify(Expression expression) throws ExpressionException {
|
||||
int initialCplx = expression.traverse(new ComplexityInclNotVisitor()).getComplexity();
|
||||
|
||||
Expression newExp = new QuineMcClusky(expression)
|
||||
.simplify()
|
||||
.getExpression();
|
||||
|
||||
int newCplx = newExp.traverse(new ComplexityInclNotVisitor()).getComplexity();
|
||||
|
||||
if (newCplx < initialCplx)
|
||||
return newExp;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplifies the table the the default {@link PrimeSelector}
|
||||
*
|
||||
* @return the simplified QMC instance
|
||||
*/
|
||||
public QuineMcClusky simplify() {
|
||||
return simplify(PrimeSelector.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplifies the table the the given {@link PrimeSelector}
|
||||
*
|
||||
* @param ps the prome selector
|
||||
* @return the simplified QMC instance
|
||||
*/
|
||||
public QuineMcClusky simplify(PrimeSelector ps) {
|
||||
QuineMcClusky t = this;
|
||||
while (!t.isFinished())
|
||||
t = t.simplifyStep().removeDuplicates();
|
||||
return t.simplifyPrimes(ps);
|
||||
}
|
||||
|
||||
|
||||
QuineMcClusky simplifyStep() {
|
||||
ArrayList<TableRow> newRows = new ArrayList<>();
|
||||
for (int i = 0; i < rows.size() - 1; i++)
|
||||
for (int j = i + 1; j < rows.size(); j++) {
|
||||
|
||||
TableRow r1 = rows.get(i);
|
||||
TableRow r2 = rows.get(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());
|
||||
|
||||
r1.setUsed();
|
||||
r2.setUsed();
|
||||
|
||||
newRows.add(newRow);
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<TableRow> np = new ArrayList<TableRow>();
|
||||
np.addAll(primes);
|
||||
for (TableRow row : rows)
|
||||
if (!row.isUsed() && row.getSource().size() > 0)
|
||||
np.add(row);
|
||||
|
||||
return new QuineMcClusky(variables, newRows, np);
|
||||
}
|
||||
|
||||
QuineMcClusky removeDuplicates() {
|
||||
ArrayList<TableRow> newRows = new ArrayList<TableRow>();
|
||||
for (TableRow r : rows) {
|
||||
int i = newRows.indexOf(r);
|
||||
if (i < 0) {
|
||||
newRows.add(r);
|
||||
} else {
|
||||
newRows.get(i).addSource(r.getSource());
|
||||
}
|
||||
}
|
||||
|
||||
rows.clear();
|
||||
rows.addAll(newRows);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true id simplification is complete
|
||||
*/
|
||||
public boolean isFinished() {
|
||||
return rows.isEmpty();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
int difIndex = -1;
|
||||
for (int i = 0; i < r1.size(); i++) {
|
||||
if (!r1.get(i).equals(r2.get(i))) {
|
||||
if (difIndex >= 0)
|
||||
return -1;
|
||||
difIndex = i;
|
||||
}
|
||||
}
|
||||
return difIndex;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (TableRow r : rows) {
|
||||
sb.append(r.toString());
|
||||
sb.append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the final primes
|
||||
*/
|
||||
public ArrayList<TableRow> getPrimes() {
|
||||
return primes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the simplified expression which represent this table
|
||||
*/
|
||||
public Expression getExpression() {
|
||||
if (primes.isEmpty() && rows.isEmpty())
|
||||
return Constant.ZERO;
|
||||
|
||||
Expression e = addAnd(null, primes, variables);
|
||||
return addAnd(e, rows, variables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the final expression
|
||||
*
|
||||
* @param e the expression to complete
|
||||
* @param rows the rows to add
|
||||
* @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) {
|
||||
for (TableRow r : rows) {
|
||||
Expression n = r.getExpression(variables);
|
||||
if (e == null)
|
||||
e = n;
|
||||
else
|
||||
e = or(e, n);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplify the primes
|
||||
*
|
||||
* @param primeSelector the prome selector to use
|
||||
* @return this for call chaning
|
||||
*/
|
||||
public QuineMcClusky 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());
|
||||
|
||||
// Nach primtermen suchen, welche einen index exclusiv enthalten
|
||||
// Diese müssen in jedem Falle enthalten sein!
|
||||
for (int pr : termIndices) {
|
||||
|
||||
TableRow foundPrime = null;
|
||||
for (TableRow tr : primesAvail) {
|
||||
if (tr.getSource().contains(pr)) {
|
||||
if (foundPrime == null) {
|
||||
foundPrime = tr;
|
||||
} else {
|
||||
foundPrime = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundPrime != null) {
|
||||
if (!primes.contains(foundPrime))
|
||||
primes.add(foundPrime);
|
||||
}
|
||||
}
|
||||
primesAvail.removeAll(primes);
|
||||
|
||||
// Die, Indices die wir schon haben können raus;
|
||||
for (TableRow pr : primes) {
|
||||
termIndices.removeAll(pr.getSource());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
/**
|
||||
* A QMC tables entry
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public enum TableItem {
|
||||
zero,
|
||||
one,
|
||||
optimized
|
||||
}
|
211
src/main/java/de/neemann/digital/analyse/quinemc/TableRow.java
Normal file
211
src/main/java/de/neemann/digital/analyse/quinemc/TableRow.java
Normal file
@ -0,0 +1,211 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.expression.BitSetter;
|
||||
import de.neemann.digital.analyse.expression.Constant;
|
||||
import de.neemann.digital.analyse.expression.Expression;
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static de.neemann.digital.analyse.expression.Not.not;
|
||||
import static de.neemann.digital.analyse.expression.Operation.and;
|
||||
|
||||
/**
|
||||
* Represents a row in a QMC table
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public class TableRow implements Comparable<TableRow> {
|
||||
|
||||
private final TableItem[] items;
|
||||
private boolean used = false;
|
||||
private final TreeSet<Integer> source;
|
||||
|
||||
/**
|
||||
* Copies the given table row
|
||||
*
|
||||
* @param tr the row to copy
|
||||
*/
|
||||
public TableRow(TableRow tr) {
|
||||
this(tr.size());
|
||||
for (int i = 0; i < size(); i++)
|
||||
items[i] = tr.get(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new tyble row
|
||||
*
|
||||
* @param cols number of columns
|
||||
*/
|
||||
public TableRow(int cols) {
|
||||
items = new TableItem[cols];
|
||||
source = new TreeSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new row
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public TableRow(int cols, int bitValue, int index, boolean dontCare) {
|
||||
this(cols);
|
||||
if (!dontCare)
|
||||
source.add(index);
|
||||
new BitSetter(cols) {
|
||||
@Override
|
||||
public void setBit(int row, int bit, boolean value) {
|
||||
if (value)
|
||||
items[bit] = TableItem.one;
|
||||
else
|
||||
items[bit] = TableItem.zero;
|
||||
}
|
||||
}.fill(bitValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* The item at the given indes
|
||||
*
|
||||
* @param index the comumns index
|
||||
* @return the value
|
||||
*/
|
||||
public TableItem get(int index) {
|
||||
return items[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given idex to optimized
|
||||
*
|
||||
* @param index the columns index
|
||||
*/
|
||||
public void setToOptimized(int index) {
|
||||
items[index] = TableItem.optimized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int c = 0; c < items.length; c++)
|
||||
switch (items[c]) {
|
||||
case zero:
|
||||
sb.append('0');
|
||||
break;
|
||||
case one:
|
||||
sb.append('1');
|
||||
break;
|
||||
case optimized:
|
||||
sb.append('-');
|
||||
break;
|
||||
}
|
||||
for (Integer i : source)
|
||||
sb.append(",").append(i);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
TableRow tableRow = (TableRow) o;
|
||||
|
||||
// Probably incorrect - comparing Object[] arrays with Arrays.equals
|
||||
return Arrays.equals(items, tableRow.items);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the used flag
|
||||
*/
|
||||
public void setUsed() {
|
||||
this.used = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the used flag
|
||||
*/
|
||||
public boolean isUsed() {
|
||||
return used;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of one values in this row
|
||||
*/
|
||||
public int countOnes() {
|
||||
int c = 0;
|
||||
for (int i = 0; i < items.length; i++)
|
||||
if (items[i] == TableItem.one)
|
||||
c++;
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(TableRow tableRow) {
|
||||
return Integer.compare(countOnes(), tableRow.countOnes());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of columns
|
||||
*/
|
||||
public int size() {
|
||||
return items.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the source line numbers
|
||||
*/
|
||||
public Collection<Integer> getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds some sources to this line
|
||||
*
|
||||
* @param s the sources to add
|
||||
*/
|
||||
public void addSource(Collection<Integer> s) {
|
||||
source.addAll(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an expression build with the given variables
|
||||
*
|
||||
* @param vars the variables to use
|
||||
* @return the expression
|
||||
*/
|
||||
public Expression getExpression(ArrayList<Variable> vars) {
|
||||
Expression e = null;
|
||||
for (int i = 0; i < size(); i++) {
|
||||
Expression term = null;
|
||||
switch (items[i]) {
|
||||
case one:
|
||||
term = vars.get(i);
|
||||
break;
|
||||
case zero:
|
||||
term = not(vars.get(i));
|
||||
break;
|
||||
}
|
||||
if (term != null) {
|
||||
if (e == null)
|
||||
e = term;
|
||||
else
|
||||
e = and(e, term);
|
||||
}
|
||||
}
|
||||
if (e == null)
|
||||
return Constant.ONE;
|
||||
else
|
||||
return e;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public enum ThreeStateValue {
|
||||
one,
|
||||
zero,
|
||||
dontCare;
|
||||
|
||||
|
||||
public static ThreeStateValue value(boolean bool) {
|
||||
if (bool) {
|
||||
return one;
|
||||
} else {
|
||||
return zero;
|
||||
}
|
||||
}
|
||||
|
||||
public static ThreeStateValue value(int value) {
|
||||
switch (value) {
|
||||
case 0:
|
||||
return ThreeStateValue.zero;
|
||||
case 1:
|
||||
return ThreeStateValue.one;
|
||||
default:
|
||||
return ThreeStateValue.dontCare;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Implementation of the algorithm from Quine and McClusky
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
package de.neemann.digital.analyse.quinemc;
|
@ -0,0 +1,54 @@
|
||||
package de.neemann.digital.analyse.quinemc.primeselector;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.quinemc.TableRow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class BruteForce implements PrimeSelector {
|
||||
@Override
|
||||
public void select(ArrayList<TableRow> primes, ArrayList<TableRow> primesAvail, TreeSet<Integer> termIndices) {
|
||||
int comb = 1 << primesAvail.size();
|
||||
ArrayList<Integer> list = new ArrayList<>(comb);
|
||||
for (int i = 1; i < comb; i++) {
|
||||
list.add(i);
|
||||
}
|
||||
Collections.sort(list, new Comparator<Integer>() {
|
||||
@Override
|
||||
public int compare(Integer i1, Integer i2) {
|
||||
return Integer.bitCount(i1) - Integer.bitCount(i2);
|
||||
}
|
||||
});
|
||||
|
||||
ArrayList<Integer> l = new ArrayList<>();
|
||||
for (int mask : list) {
|
||||
l.addAll(termIndices);
|
||||
int m = mask;
|
||||
for (TableRow aPrimesAvail : primesAvail) {
|
||||
if ((m & 1) > 0) {
|
||||
l.removeAll(aPrimesAvail.getSource());
|
||||
}
|
||||
m >>= 1;
|
||||
}
|
||||
if (l.isEmpty()) {
|
||||
m = mask;
|
||||
for (TableRow aPrime : primesAvail) {
|
||||
if ((m & 1) > 0) {
|
||||
primes.add(aPrime);
|
||||
}
|
||||
m >>= 1;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
l.clear();
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("BruteForce Error!");
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package de.neemann.digital.analyse.quinemc.primeselector;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.quinemc.TableRow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class BruteForceGetAll implements PrimeSelector, PrimeSelectorGetAll {
|
||||
|
||||
private ArrayList<ArrayList<TableRow>> foundSolutions;
|
||||
|
||||
@Override
|
||||
public void select(ArrayList<TableRow> primes, ArrayList<TableRow> primesAvail, TreeSet<Integer> termIndices) {
|
||||
int comb = 1 << primesAvail.size();
|
||||
ArrayList<Integer> list = new ArrayList<>(comb);
|
||||
for (int i = 1; i < comb; i++) {
|
||||
list.add(i);
|
||||
}
|
||||
Collections.sort(list, new Comparator<Integer>() {
|
||||
@Override
|
||||
public int compare(Integer i1, Integer i2) {
|
||||
return Integer.bitCount(i1) - Integer.bitCount(i2);
|
||||
}
|
||||
});
|
||||
|
||||
int primesUsed = 0;
|
||||
|
||||
foundSolutions = new ArrayList<>();
|
||||
|
||||
ArrayList<Integer> indicesOpen = new ArrayList<>();
|
||||
for (int mask : list) {
|
||||
|
||||
if (primesUsed != 0 && Integer.bitCount(mask) > primesUsed)
|
||||
break;
|
||||
|
||||
indicesOpen.clear();
|
||||
indicesOpen.addAll(termIndices);
|
||||
int m = mask;
|
||||
for (TableRow aPrimesAvail : primesAvail) {
|
||||
if ((m & 1) > 0) {
|
||||
indicesOpen.removeAll(aPrimesAvail.getSource());
|
||||
}
|
||||
m >>= 1;
|
||||
}
|
||||
if (indicesOpen.isEmpty()) {
|
||||
primesUsed = Integer.bitCount(mask);
|
||||
|
||||
ArrayList<TableRow> singleSolution = new ArrayList<>(primes);
|
||||
m = mask;
|
||||
for (TableRow aPrime : primesAvail) {
|
||||
if ((m & 1) > 0) {
|
||||
singleSolution.add(aPrime);
|
||||
}
|
||||
m >>= 1;
|
||||
}
|
||||
foundSolutions.add(singleSolution);
|
||||
}
|
||||
}
|
||||
primes.clear();
|
||||
primes.addAll(foundSolutions.get(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<ArrayList<TableRow>> getAllSolutions() {
|
||||
return foundSolutions;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package de.neemann.digital.analyse.quinemc.primeselector;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.quinemc.TableRow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Tries at first the primes containing the most indices
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public class LargestFirst implements PrimeSelector {
|
||||
@Override
|
||||
public void select(ArrayList<TableRow> primes, ArrayList<TableRow> primesAvail, TreeSet<Integer> termIndices) {
|
||||
while (!termIndices.isEmpty()) {
|
||||
TableRow bestRow = null;
|
||||
int maxCount = 0;
|
||||
for (TableRow tr : primesAvail) {
|
||||
int count = 0;
|
||||
for (int i : tr.getSource()) {
|
||||
if (termIndices.contains(i))
|
||||
count++;
|
||||
}
|
||||
if (count > maxCount) {
|
||||
maxCount = count;
|
||||
bestRow = tr;
|
||||
}
|
||||
}
|
||||
primes.add(bestRow);
|
||||
primesAvail.remove(bestRow);
|
||||
termIndices.removeAll(bestRow.getSource());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package de.neemann.digital.analyse.quinemc.primeselector;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.quinemc.TableRow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Represents an algorithm which chooses the final primes
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public interface PrimeSelector {
|
||||
|
||||
/**
|
||||
* The default prime selector
|
||||
*/
|
||||
PrimeSelector DEFAULT = new PrimeSelector() {
|
||||
|
||||
private final PrimeSelector bruteForce = new BruteForceGetAll();
|
||||
private final PrimeSelector largestFirst = new LargestFirst();
|
||||
|
||||
@Override
|
||||
public void select(ArrayList<TableRow> primes, ArrayList<TableRow> primesAvail, TreeSet<Integer> termIndices) {
|
||||
int count = primesAvail.size();
|
||||
|
||||
if (count <= 12) {
|
||||
bruteForce.select(primes, primesAvail, termIndices);
|
||||
} else {
|
||||
largestFirst.select(primes, primesAvail, termIndices);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Selects the primes to use
|
||||
*
|
||||
* @param primes the list to add the primes to
|
||||
* @param primesAvail the available promes
|
||||
* @param termIndices the indices
|
||||
*/
|
||||
void select(ArrayList<TableRow> primes, ArrayList<TableRow> primesAvail, TreeSet<Integer> termIndices);
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package de.neemann.digital.analyse.quinemc.primeselector;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.quinemc.TableRow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Used to create all possible sollutions
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public interface PrimeSelectorGetAll {
|
||||
|
||||
/**
|
||||
* @return all possible solutions
|
||||
*/
|
||||
ArrayList<ArrayList<TableRow>> getAllSolutions();
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Classes used to select the necessary primes
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
package de.neemann.digital.analyse.quinemc.primeselector;
|
@ -0,0 +1,54 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.expression.ExpressionException;
|
||||
import de.neemann.digital.analyse.expression.format.FormatterException;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public abstract class FullVariantDontCareCreator {
|
||||
|
||||
private final int nmax;
|
||||
private final int step;
|
||||
|
||||
public FullVariantDontCareCreator() {
|
||||
this(3, 1);
|
||||
}
|
||||
|
||||
public FullVariantDontCareCreator(int nmax) {
|
||||
this(nmax, 1);
|
||||
}
|
||||
|
||||
public FullVariantDontCareCreator(int nmax, int step) {
|
||||
this.nmax = nmax;
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
public void create() throws ExpressionException, FormatterException {
|
||||
for (int n = 1; n <= nmax; n++) {
|
||||
int tables = 1;
|
||||
int c = 1 << n;
|
||||
for (int i = 0; i < c; i++) tables *= 3;
|
||||
|
||||
int count = 0;
|
||||
int[] tab = new int[1 << n];
|
||||
for (int i = 0; i < tables; i += step) {
|
||||
int value = i;
|
||||
for (int j = 0; j < tab.length; j++) {
|
||||
tab[j] = value % 3;
|
||||
value /= 3;
|
||||
}
|
||||
handleTable(n, tab);
|
||||
|
||||
if (count++ > 10000) {
|
||||
System.out.println(i + "/" + tables);
|
||||
count = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void handleTable(int n, int[] tab) throws ExpressionException, FormatterException;
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.expression.*;
|
||||
import de.neemann.digital.analyse.expression.format.FormatToExpression;
|
||||
import de.neemann.digital.analyse.expression.format.FormatToTable;
|
||||
import de.neemann.digital.analyse.expression.format.FormatterException;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static de.neemann.digital.analyse.expression.Variable.vars;
|
||||
import static de.neemann.digital.analyse.expression.format.FormatToExpression.FORMATTER_UNICODE;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class QuineMcCluskyDontCareTest extends TestCase {
|
||||
|
||||
public void testDontCare() throws Exception, FormatterException {
|
||||
ArrayList<Variable> v = vars("A", "B", "C");
|
||||
Expression e = new QuineMcClusky(v)
|
||||
.fillTableWith(new BoolTableIntArray(new int[]{1, 1, 0, 0, 1, 2, 2, 0}))
|
||||
.simplify()
|
||||
.getExpression();
|
||||
|
||||
System.out.println(new FormatToTable().format("y", e));
|
||||
assertEquals("!B", FormatToExpression.FORMATTER_JAVA.format(e));
|
||||
}
|
||||
|
||||
/**
|
||||
* up to 3 variables we can calculate all tables possible!
|
||||
*
|
||||
* @throws ExpressionException
|
||||
*/
|
||||
public void testFull() throws ExpressionException, FormatterException {
|
||||
new FullVariantDontCareCreator() {
|
||||
@Override
|
||||
public void handleTable(int n, int[] tab) throws ExpressionException {
|
||||
performTestCalculation(n, tab);
|
||||
}
|
||||
}.create();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* for more the 3 variables we only test some random tables
|
||||
*
|
||||
* @throws ExpressionException
|
||||
*/
|
||||
public void testRegression() throws ExpressionException {
|
||||
for (int n = 4; n < 8; n++) {
|
||||
for (int i = 0; i < 200; i++) {
|
||||
performTestCalculationRandom(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static private void performTestCalculationRandom(int n) throws ExpressionException {
|
||||
int[] tab = new int[1 << n];
|
||||
for (int i = 0; i < tab.length; i++)
|
||||
tab[i] = (int) Math.round(Math.random() * 3); // half of the values are don't care
|
||||
|
||||
performTestCalculation(n, tab);
|
||||
}
|
||||
|
||||
static private void performTestCalculation(int n, int[] tab) throws ExpressionException {
|
||||
ArrayList<Variable> v = vars(n);
|
||||
Expression e = new QuineMcClusky(v)
|
||||
.fillTableWith(new BoolTableIntArray(tab))
|
||||
.simplify()
|
||||
.getExpression();
|
||||
|
||||
assertNotNull(e);
|
||||
|
||||
ContextFiller context = new ContextFiller(v);
|
||||
for (int i = 0; i < tab.length; i++) {
|
||||
if (tab[i] <= 1)
|
||||
assertEquals(tab[i] == 1, e.calculate(context.setContextTo(i)));
|
||||
}
|
||||
}
|
||||
|
||||
public void testComplexity() throws Exception, FormatterException {
|
||||
new FullVariantDontCareCreator() {
|
||||
@Override
|
||||
public void handleTable(int n, int[] tab) throws ExpressionException, FormatterException {
|
||||
Expression e = createExpression(n, tab);
|
||||
|
||||
int[] tabZero = Arrays.copyOf(tab, tab.length);
|
||||
for (int i = 0; i < tabZero.length; i++)
|
||||
if (tabZero[i] > 1) tabZero[i] = 0;
|
||||
Expression eZero = createExpression(n, tabZero);
|
||||
|
||||
int[] tabOne = Arrays.copyOf(tab, tab.length);
|
||||
for (int i = 0; i < tabOne.length; i++)
|
||||
if (tabOne[i] > 1) tabOne[i] = 1;
|
||||
|
||||
Expression eOne = createExpression(n, tabOne);
|
||||
|
||||
int c = e.traverse(new ComplexityVisitor()).getComplexity();
|
||||
int cOne = eOne.traverse(new ComplexityVisitor()).getComplexity();
|
||||
int cZero = eZero.traverse(new ComplexityVisitor()).getComplexity();
|
||||
|
||||
boolean ok = (c <= cOne) && (c <= cZero);
|
||||
if (!ok) {
|
||||
System.out.println("\nX: " + FORMATTER_UNICODE.format(e) + ", " + c);
|
||||
System.out.println("0: " + FORMATTER_UNICODE.format(eZero) + ", " + cZero);
|
||||
System.out.println("1: " + FORMATTER_UNICODE.format(eOne) + ", " + cOne);
|
||||
|
||||
assertTrue(false);
|
||||
}
|
||||
}
|
||||
}.create();
|
||||
}
|
||||
|
||||
private Expression createExpression(int n, int[] tab) throws ExpressionException {
|
||||
ArrayList<Variable> v = vars(n);
|
||||
return new QuineMcClusky(v)
|
||||
.fillTableWith(new BoolTableIntArray(tab))
|
||||
.simplify()
|
||||
.getExpression();
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
import de.neemann.digital.analyse.expression.ContextFiller;
|
||||
import de.neemann.digital.analyse.expression.Expression;
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
import de.neemann.digital.analyse.expression.format.FormatToExpression;
|
||||
import de.neemann.digital.analyse.expression.format.FormatterException;
|
||||
import de.neemann.digital.analyse.quinemc.primeselector.PrimeSelector;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import static de.neemann.digital.analyse.expression.Operation.or;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class QuineMcCluskyRegressionTest extends TestCase {
|
||||
|
||||
public void testRegression() throws Exception, FormatterException {
|
||||
testRegression(8, 128);
|
||||
testRegression(8, 16);
|
||||
testRegression(4, 8);
|
||||
testRegression(4, 4);
|
||||
}
|
||||
|
||||
public void testRegression2() throws Exception, FormatterException {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
testRegression(5, 16);
|
||||
testRegression(5, 8);
|
||||
testRegression(5, 4);
|
||||
}
|
||||
}
|
||||
|
||||
public void testRegression3() throws Exception, FormatterException {
|
||||
Variable a = new Variable("A");
|
||||
Variable b = new Variable("B");
|
||||
Variable c = new Variable("C");
|
||||
Variable d = new Variable("D");
|
||||
ArrayList<Variable> vars = new ArrayList<>();
|
||||
vars.add(a);
|
||||
vars.add(b);
|
||||
vars.add(c);
|
||||
vars.add(d);
|
||||
QuineMcClusky t = new QuineMcClusky(vars);
|
||||
|
||||
Expression ex = or(a, c);
|
||||
t.fillTableWith(new BoolTableExpression(ex, new ContextFiller(vars)));
|
||||
|
||||
System.out.println("--");
|
||||
while (!t.isFinished()) {
|
||||
System.out.println(FormatToExpression.FORMATTER_JAVA.format(t.getExpression()));
|
||||
t = t.simplifyStep().removeDuplicates();
|
||||
}
|
||||
t.simplifyPrimes(PrimeSelector.DEFAULT);
|
||||
assertEquals("A || C", FormatToExpression.FORMATTER_JAVA.format(t.getExpression()));
|
||||
System.out.println("--");
|
||||
}
|
||||
|
||||
|
||||
public static void testRegression(int n, int j) throws Exception, FormatterException {
|
||||
int size = 1 << n;
|
||||
boolean[] table = new boolean[size];
|
||||
|
||||
ArrayList<Integer> index = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) index.add(i);
|
||||
Collections.shuffle(index);
|
||||
|
||||
for (int i = 0; i < j; i++)
|
||||
table[index.get(i)] = true;
|
||||
|
||||
ArrayList<Variable> var = Variable.vars(n);
|
||||
|
||||
Expression expression =
|
||||
new QuineMcClusky(var)
|
||||
.fillTableWith(new BoolTableBoolArray(table))
|
||||
.simplify()
|
||||
.getExpression();
|
||||
|
||||
ContextFiller cf = new ContextFiller(var);
|
||||
|
||||
for (int i = 0; i < table.length; i++)
|
||||
assertEquals(table[i], expression.calculate(cf.setContextTo(i)));
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
import de.neemann.digital.analyse.expression.format.FormatToExpression;
|
||||
import de.neemann.digital.analyse.expression.format.FormatterException;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class QuineMcCluskyRowTest extends TestCase {
|
||||
|
||||
public void testSimple() throws FormatterException {
|
||||
ArrayList<Variable> vars = Variable.vars("A", "B", "C", "D");
|
||||
|
||||
TableRow tr = new TableRow(4, 15, 0, false);
|
||||
assertEquals("A && B && C && D", FormatToExpression.FORMATTER_JAVA.format(tr.getExpression(vars)));
|
||||
|
||||
tr = new TableRow(4, 5, 0, false);
|
||||
assertEquals("!A && B && !C && D", FormatToExpression.FORMATTER_JAVA.format(tr.getExpression(vars)));
|
||||
tr = new TableRow(4, 10, 0, false);
|
||||
assertEquals("A && !B && C && !D", FormatToExpression.FORMATTER_JAVA.format(tr.getExpression(vars)));
|
||||
tr = new TableRow(4, 10, 0, false);
|
||||
tr.setToOptimized(2);
|
||||
assertEquals("A && !B && !D", FormatToExpression.FORMATTER_JAVA.format(tr.getExpression(vars)));
|
||||
tr = new TableRow(4, 10, 0, false);
|
||||
tr.setToOptimized(0);
|
||||
assertEquals("!B && C && !D", FormatToExpression.FORMATTER_JAVA.format(tr.getExpression(vars)));
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,161 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.expression.Constant;
|
||||
import de.neemann.digital.analyse.expression.Expression;
|
||||
import de.neemann.digital.analyse.expression.ExpressionException;
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
import de.neemann.digital.analyse.expression.format.FormatToExpression;
|
||||
import de.neemann.digital.analyse.expression.format.FormatterException;
|
||||
import de.neemann.digital.analyse.quinemc.primeselector.PrimeSelector;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static de.neemann.digital.analyse.expression.Not.not;
|
||||
import static de.neemann.digital.analyse.expression.Operation.and;
|
||||
import static de.neemann.digital.analyse.expression.Operation.or;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class QuineMcCluskyTest extends TestCase {
|
||||
|
||||
|
||||
public void testGenerator() throws ExpressionException {
|
||||
Variable a = new Variable("A");// Vorlesung
|
||||
Variable b = new Variable("B");
|
||||
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)));
|
||||
QuineMcClusky t = new QuineMcClusky(e);
|
||||
|
||||
assertEquals("0000,1\n" +
|
||||
"0010,2\n" +
|
||||
"0100,4\n" +
|
||||
"1000,5\n" +
|
||||
"0011,3\n" +
|
||||
"1010,6\n" +
|
||||
"1100,8\n" +
|
||||
"1011,7\n" +
|
||||
"1111,9\n", t.toString());
|
||||
|
||||
}
|
||||
|
||||
public void testSimplify() throws ExpressionException, FormatterException {
|
||||
Variable a = new Variable("A");// Vorlesung
|
||||
Variable b = new Variable("B");
|
||||
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)));
|
||||
QuineMcClusky t = new QuineMcClusky(e).simplifyStep();
|
||||
assertFalse(t.isFinished());
|
||||
|
||||
assertEquals("00-0,1,2\n" +
|
||||
"0-00,1,4\n" +
|
||||
"-000,1,5\n" +
|
||||
"001-,2,3\n" +
|
||||
"-010,2,6\n" +
|
||||
"-100,4,8\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());
|
||||
|
||||
t = t.simplifyStep();
|
||||
assertFalse(t.isFinished());
|
||||
|
||||
assertEquals("-0-0,1,2,5,6\n" +
|
||||
"--00,1,4,5,8\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());
|
||||
|
||||
ArrayList<TableRow> primes = t.getPrimes();
|
||||
assertEquals(1, primes.size());
|
||||
assertEquals("1-11,7,9", primes.get(0).toString());
|
||||
|
||||
t = t.removeDuplicates();
|
||||
assertFalse(t.isFinished());
|
||||
|
||||
assertEquals("-0-0,1,2,5,6\n" +
|
||||
"--00,1,4,5,8\n" +
|
||||
"-01-,2,3,6,7\n", t.toString());
|
||||
|
||||
t = t.simplifyStep();
|
||||
assertTrue(t.isFinished());
|
||||
|
||||
assertEquals("", t.toString());
|
||||
|
||||
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("-01-,2,3,6,7", primes.get(3).toString());
|
||||
|
||||
Expression exp = t.getExpression();
|
||||
assertEquals("(A && C && D) || (!B && !D) || (!B && C) || (!C && !D)", FormatToExpression.FORMATTER_JAVA.format(exp));
|
||||
|
||||
t.simplifyPrimes(PrimeSelector.DEFAULT);
|
||||
|
||||
exp = t.getExpression();
|
||||
assertEquals("(A && C && D) || (!B && C) || (!C && !D)", FormatToExpression.FORMATTER_JAVA.format(exp));
|
||||
}
|
||||
|
||||
public void testSimplify2() throws ExpressionException, FormatterException {
|
||||
QuineMcClusky t = new QuineMcClusky(Variable.vars("A", "B", "C", "D"));
|
||||
t.fillTableWith(new BoolTableIntArray(new int[]{1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1}));
|
||||
t = t.simplify();
|
||||
|
||||
assertEquals("(!A && !C) || (B && D) || (B && !C)", FormatToExpression.FORMATTER_JAVA.format(t.getExpression()));
|
||||
}
|
||||
|
||||
public void testZero() throws Exception {
|
||||
QuineMcClusky t = new QuineMcClusky(Variable.vars("A", "B", "C"));
|
||||
t.fillTableWith(new BoolTableIntArray(new int[]{0, 0, 0, 0, 0, 0, 0, 0}));
|
||||
t = t.simplify();
|
||||
Expression e = t.getExpression();
|
||||
assertNotNull(e);
|
||||
|
||||
assertTrue(e instanceof Constant);
|
||||
assertFalse(((Constant) e).getValue());
|
||||
}
|
||||
|
||||
public void testZero2() throws Exception {
|
||||
QuineMcClusky t = new QuineMcClusky(Variable.vars("A", "B", "C"));
|
||||
t.fillTableWith(new BoolTableIntArray(new int[]{0, 0, 0, 0, 0, 0, 2, 2}));
|
||||
t = t.simplify();
|
||||
Expression e = t.getExpression();
|
||||
assertNotNull(e);
|
||||
|
||||
assertTrue(e instanceof Constant);
|
||||
assertFalse(((Constant) e).getValue());
|
||||
}
|
||||
|
||||
public void testOne() throws Exception {
|
||||
QuineMcClusky t = new QuineMcClusky(Variable.vars("A", "B", "C"));
|
||||
t.fillTableWith(new BoolTableIntArray(new int[]{1, 1, 1, 1, 1, 1, 1, 1}));
|
||||
t = t.simplify();
|
||||
Expression e = t.getExpression();
|
||||
assertNotNull(e);
|
||||
|
||||
assertTrue(e instanceof Constant);
|
||||
assertTrue(((Constant) e).getValue());
|
||||
}
|
||||
|
||||
public void testOne2() throws Exception {
|
||||
QuineMcClusky t = new QuineMcClusky(Variable.vars("A", "B", "C"));
|
||||
t.fillTableWith(new BoolTableIntArray(new int[]{1, 1, 1, 1, 1, 1, 2, 2}));
|
||||
t = t.simplify();
|
||||
Expression e = t.getExpression();
|
||||
assertNotNull(e);
|
||||
|
||||
assertTrue(e instanceof Constant);
|
||||
assertTrue(((Constant) e).getValue());
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.expression.Expression;
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
import de.neemann.digital.analyse.expression.format.FormatToExpression;
|
||||
import de.neemann.digital.analyse.expression.format.FormatterException;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import static de.neemann.digital.analyse.expression.Operation.and;
|
||||
import static de.neemann.digital.analyse.expression.Operation.or;
|
||||
import static de.neemann.digital.analyse.expression.Variable.v;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class SimplifyTest extends TestCase {
|
||||
|
||||
public void testSimplify() throws Exception, FormatterException {
|
||||
Variable a = v("a");
|
||||
Variable b = v("b");
|
||||
Expression e = or(and(a, b), a);
|
||||
Expression s = QuineMcClusky.simplify(e);
|
||||
|
||||
assertEquals("a", FormatToExpression.FORMATTER_UNICODE.format(s));
|
||||
}
|
||||
|
||||
public void testSimplify2() throws Exception, FormatterException {
|
||||
Variable a = v("a");
|
||||
Variable b = v("b");
|
||||
Expression e = and(or(a, b), a);
|
||||
Expression s = QuineMcClusky.simplify(e);
|
||||
|
||||
assertEquals("a", FormatToExpression.FORMATTER_UNICODE.format(s));
|
||||
}
|
||||
|
||||
public void testSimplify3() throws Exception {
|
||||
Variable a = v("a");
|
||||
Variable b = v("b");
|
||||
Variable c = v("c");
|
||||
Expression e = and(or(a, b), c);
|
||||
Expression s = QuineMcClusky.simplify(e);
|
||||
|
||||
assertNull(s);
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package de.neemann.digital.analyse.quinemc.primeselector;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.expression.ContextFiller;
|
||||
import de.neemann.digital.analyse.expression.Expression;
|
||||
import de.neemann.digital.analyse.expression.ExpressionException;
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
import de.neemann.digital.analyse.expression.format.FormatterException;
|
||||
import de.neemann.digital.analyse.quinemc.BoolTableIntArray;
|
||||
import de.neemann.digital.analyse.quinemc.FullVariantDontCareCreator;
|
||||
import de.neemann.digital.analyse.quinemc.QuineMcClusky;
|
||||
import de.neemann.digital.analyse.quinemc.TableRow;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static de.neemann.digital.analyse.expression.Variable.vars;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class BruteForceGetAllTest extends TestCase {
|
||||
|
||||
/**
|
||||
* up to 3 variables we can calculate all tables possible!
|
||||
*
|
||||
* @throws ExpressionException
|
||||
*/
|
||||
public void testFullRegression() throws ExpressionException, FormatterException {
|
||||
new FullVariantDontCareCreator() {
|
||||
@Override
|
||||
public void handleTable(int n, int[] tab) throws ExpressionException {
|
||||
performTestCalculation(n, tab);
|
||||
}
|
||||
}.create();
|
||||
new FullVariantDontCareCreator(4, 241) {
|
||||
@Override
|
||||
public void handleTable(int n, int[] tab) throws ExpressionException {
|
||||
performTestCalculation(n, tab);
|
||||
}
|
||||
}.create();
|
||||
}
|
||||
|
||||
/*
|
||||
public void testFull() throws ExpressionException, FormatterException {
|
||||
new FullVariantDontCareCreator(4) {
|
||||
@Override
|
||||
public void handleTable(int n, int[] tab) throws ExpressionException {
|
||||
performTestCalculation(n, tab);
|
||||
}
|
||||
}.create();
|
||||
} /**/
|
||||
|
||||
static private void performTestCalculation(int n, int[] tab) throws ExpressionException {
|
||||
|
||||
BruteForceGetAll ps = new BruteForceGetAll();
|
||||
|
||||
ArrayList<Variable> v = vars(n);
|
||||
new QuineMcClusky(v)
|
||||
.fillTableWith(new BoolTableIntArray(tab))
|
||||
.simplify(ps);
|
||||
|
||||
ArrayList<ArrayList<TableRow>> solutions = ps.getAllSolutions();
|
||||
if (solutions != null) {
|
||||
|
||||
for (ArrayList<TableRow> sol : solutions) {
|
||||
Expression e = QuineMcClusky.addAnd(null, sol, v);
|
||||
ContextFiller context = new ContextFiller(v);
|
||||
for (int i = 0; i < tab.length; i++) {
|
||||
if (tab[i] <= 1) {
|
||||
assertEquals(tab[i] == 1, e.calculate(context.setContextTo(i)));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user