diff --git a/src/main/java/de/neemann/digital/analyse/MinimizerInterface.java b/src/main/java/de/neemann/digital/analyse/MinimizerInterface.java new file mode 100644 index 000000000..bc8632694 --- /dev/null +++ b/src/main/java/de/neemann/digital/analyse/MinimizerInterface.java @@ -0,0 +1,29 @@ +package de.neemann.digital.analyse; + +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.BoolTable; +import de.neemann.digital.gui.components.table.ExpressionListener; + +import java.util.List; + +/** + * Interface to abstract a minimizer algorithm. + * Created by hneemann on 13.03.17. + */ +public interface MinimizerInterface { + + /** + * Called to minimize a bool table + * + * @param vars the variables used + * @param boolTable the bool table + * @param resultName name of the result + * @param listener the listener to report the result to + * @throws ExpressionException ExpressionException + * @throws FormatterException FormatterException + */ + void minimize(List vars, BoolTable boolTable, String resultName, ExpressionListener listener) throws ExpressionException, FormatterException; + +} diff --git a/src/main/java/de/neemann/digital/analyse/MinimizerQuineMcCluskey.java b/src/main/java/de/neemann/digital/analyse/MinimizerQuineMcCluskey.java new file mode 100644 index 000000000..65fc608da --- /dev/null +++ b/src/main/java/de/neemann/digital/analyse/MinimizerQuineMcCluskey.java @@ -0,0 +1,48 @@ +package de.neemann.digital.analyse; + +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.BoolTable; +import de.neemann.digital.analyse.quinemc.QuineMcCluskey; +import de.neemann.digital.analyse.quinemc.TableRow; +import de.neemann.digital.analyse.quinemc.primeselector.PrimeSelector; +import de.neemann.digital.analyse.quinemc.primeselector.PrimeSelectorDefault; +import de.neemann.digital.gui.components.table.ExpressionListener; + +import java.util.ArrayList; +import java.util.List; + +/** + * The normal QMC minimizer. + * Created by hneemann on 13.03.17. + */ +public class MinimizerQuineMcCluskey implements MinimizerInterface { + @Override + public void minimize(List vars, BoolTable boolTable, String resultName, ExpressionListener listener) throws ExpressionException, FormatterException { + QuineMcCluskey qmc = createQuineMcCluskey(vars) + .fillTableWith(boolTable); + PrimeSelector ps = new PrimeSelectorDefault(); + Expression e = qmc.simplify(ps).getExpression(); + + if (ps.getAllSolutions() != null) { + for (ArrayList i : ps.getAllSolutions()) { + listener.resultFound(resultName, QuineMcCluskey.addAnd(null, i, vars)); + } + } else { + listener.resultFound(resultName, e); + } + + } + + /** + * Creates a specific QMC algorithm + * + * @param vars the variables to use + * @return the QMC instance + */ + protected QuineMcCluskey createQuineMcCluskey(List vars) { + return new QuineMcCluskey(vars); + } +} diff --git a/src/main/java/de/neemann/digital/analyse/MinimizerQuineMcCluskeyExam.java b/src/main/java/de/neemann/digital/analyse/MinimizerQuineMcCluskeyExam.java new file mode 100644 index 000000000..57c7727ea --- /dev/null +++ b/src/main/java/de/neemann/digital/analyse/MinimizerQuineMcCluskeyExam.java @@ -0,0 +1,19 @@ +package de.neemann.digital.analyse; + +import de.neemann.digital.analyse.expression.Variable; +import de.neemann.digital.analyse.quinemc.QuineMcCluskey; +import de.neemann.digital.analyse.quinemc.QuineMcCluskeyExam; + +import java.util.List; + +/** + * The QMC-Minimizer used for exam correction. + * Should only be used if there are not more then 4 variables. + * Created by hneemann on 13.03.17. + */ +public class MinimizerQuineMcCluskeyExam extends MinimizerQuineMcCluskey { + @Override + protected QuineMcCluskey createQuineMcCluskey(List vars) { + return new QuineMcCluskeyExam(vars); + } +} 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 819772642..cd637eaf9 100644 --- a/src/main/java/de/neemann/digital/analyse/quinemc/QuineMcCluskey.java +++ b/src/main/java/de/neemann/digital/analyse/quinemc/QuineMcCluskey.java @@ -20,9 +20,9 @@ import static de.neemann.digital.analyse.expression.Operation.or; public class QuineMcCluskey { private static final Logger LOGGER = LoggerFactory.getLogger(QuineMcCluskey.class); - private final TableRows rows; private final List variables; private final ArrayList primes; + private TableRows rows; /** * Creates a new instance @@ -120,16 +120,17 @@ public class QuineMcCluskey { * @return the simplified QMC instance */ public QuineMcCluskey simplify(PrimeSelector ps) { - QuineMcCluskey t = this; - while (!t.isFinished()) { - LOGGER.debug("QMC rows " + t.rows.size()); - t = t.simplifyStep(); + while (!isFinished()) { + LOGGER.debug("QMC rows " + rows.size()); + simplifyStep(); } - return t.simplifyPrimes(ps); + simplifyPrimes(ps); + + return this; } - QuineMcCluskey simplifyStep() { + void simplifyStep() { TableRows newRows = new TableRows(); for (TableRows.InnerList list : rows.listIterable()) @@ -154,13 +155,11 @@ public class QuineMcCluskey { } } - ArrayList np = new ArrayList(); - np.addAll(primes); for (TableRow row : rows) if (!row.isUsed() && row.getSource().size() > 0) - np.add(row); + primes.add(row); - return new QuineMcCluskey(variables, newRows, np); + rows=newRows; } /** @@ -173,7 +172,7 @@ public class QuineMcCluskey { @Override public String toString() { StringBuilder sb = new StringBuilder(); - ArrayList newList = new ArrayList(); + ArrayList newList = new ArrayList<>(); for (TableRow r : rows) { newList.add(r); } @@ -192,6 +191,13 @@ public class QuineMcCluskey { return primes; } + /** + * @return the variables used + */ + public List getVariables() { + return variables; + } + /** * @return the simplified expression which represent this table */ @@ -226,9 +232,8 @@ public class QuineMcCluskey { * Simplify the primes * * @param primeSelector the prime selector to use - * @return this for call chaining */ - public QuineMcCluskey simplifyPrimes(PrimeSelector primeSelector) { + public void simplifyPrimes(PrimeSelector primeSelector) { TreeSet columns = new TreeSet<>(); for (TableRow r : primes) @@ -276,8 +281,6 @@ public class QuineMcCluskey { primeSelector.select(primes, availPrimes, columns); LOGGER.debug("final primes " + primes.size()); } - - return this; } private boolean smaller(int c1, int c2, ArrayList primes) { diff --git a/src/main/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyExam.java b/src/main/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyExam.java new file mode 100644 index 000000000..9fa697229 --- /dev/null +++ b/src/main/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyExam.java @@ -0,0 +1,102 @@ +package de.neemann.digital.analyse.quinemc; + +import de.neemann.digital.analyse.expression.Variable; +import de.neemann.digital.analyse.quinemc.primeselector.PrimeSelector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.TreeSet; + +/** + * Not as efficient as {@link QuineMcCluskey} but it shows all possible solutions. + * Needed for exam correction. + * It does not throw away all primes which are not necessary but tries to find the primes + * which are necessary. So is is possible to find all possible solutions. + * Works only if there are not more then 4 variables. + *

+ * Created by hneemann on 13.03.17. + */ +public class QuineMcCluskeyExam extends QuineMcCluskey { + private static final Logger LOGGER = LoggerFactory.getLogger(QuineMcCluskeyExam.class); + + /** + * Creates a new instance + * + * @param variables the variables to use + */ + public QuineMcCluskeyExam(List variables) { + super(variables); + } + + /** + * Simplify the primes + * + * @param primeSelector the prime selector to use + */ + @Override + public void simplifyPrimes(PrimeSelector primeSelector) { + ArrayList primes = getPrimes(); + ArrayList primesAvail = new ArrayList<>(primes); + primes.clear(); + + TreeSet 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()); + } + + LOGGER.debug("residual primes " + primesAvail.size()); + + if (!termIndices.isEmpty()) { + + //Die noch übrigen Terme durchsuchen ob sie schon komplett dabei sind; + Iterator 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); + } + LOGGER.debug("final primes " + primes.size()); + } + +} diff --git a/src/main/java/de/neemann/digital/gui/components/table/ExpressionCreator.java b/src/main/java/de/neemann/digital/gui/components/table/ExpressionCreator.java index 674dd0a84..fef93c067 100644 --- a/src/main/java/de/neemann/digital/gui/components/table/ExpressionCreator.java +++ b/src/main/java/de/neemann/digital/gui/components/table/ExpressionCreator.java @@ -1,23 +1,19 @@ package de.neemann.digital.gui.components.table; import de.neemann.digital.analyse.AnalyseException; +import de.neemann.digital.analyse.MinimizerInterface; import de.neemann.digital.analyse.TruthTable; 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.BoolTable; -import de.neemann.digital.analyse.quinemc.QuineMcCluskey; import de.neemann.digital.analyse.quinemc.TableReducer; -import de.neemann.digital.analyse.quinemc.TableRow; -import de.neemann.digital.analyse.quinemc.primeselector.PrimeSelector; -import de.neemann.digital.analyse.quinemc.primeselector.PrimeSelectorDefault; import de.neemann.digital.gui.Main; import de.neemann.digital.lang.Lang; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutorService; @@ -34,14 +30,17 @@ public class ExpressionCreator { private static final int MAX_INPUTS_ALLOWED = 12; private final TruthTable theTable; + private final MinimizerInterface minimizer; /** * Creates a new instance * - * @param theTable the table to use + * @param theTable the table to use + * @param minimizer the minimizer to use */ - public ExpressionCreator(TruthTable theTable) { + public ExpressionCreator(TruthTable theTable, MinimizerInterface minimizer) { this.theTable = theTable; + this.minimizer = minimizer; } /** @@ -94,18 +93,7 @@ public class ExpressionCreator { if (!Main.enableExperimental() && localVars.size() > MAX_INPUTS_ALLOWED) throw new AnalyseException(Lang.get("err_toManyInputsIn_N0_max_N1_is_N2", resultName, MAX_INPUTS_ALLOWED, localVars.size())); - QuineMcCluskey qmc = new QuineMcCluskey(localVars) - .fillTableWith(boolTable); - PrimeSelector ps = new PrimeSelectorDefault(); - Expression e = qmc.simplify(ps).getExpression(); - - if (ps.getAllSolutions() != null) { - for (ArrayList i : ps.getAllSolutions()) { - listener.resultFound(resultName, QuineMcCluskey.addAnd(null, i, localVars)); - } - } else { - listener.resultFound(resultName, e); - } + minimizer.minimize(localVars, boolTable, resultName, listener); } private final static class ThreadSaveExpressionListener implements ExpressionListener { diff --git a/src/main/java/de/neemann/digital/gui/components/table/ExpressionListenerStore.java b/src/main/java/de/neemann/digital/gui/components/table/ExpressionListenerStore.java index 369aba80d..b02cf6137 100644 --- a/src/main/java/de/neemann/digital/gui/components/table/ExpressionListenerStore.java +++ b/src/main/java/de/neemann/digital/gui/components/table/ExpressionListenerStore.java @@ -58,6 +58,13 @@ public class ExpressionListenerStore implements ExpressionListener { listener.close(); } + /** + * @return the first found expression + */ + public Expression getFirst() { + return results.get(0).expression; + } + private static final class Result { private final String name; private final Expression expression; diff --git a/src/main/java/de/neemann/digital/gui/components/table/TableDialog.java b/src/main/java/de/neemann/digital/gui/components/table/TableDialog.java index 44138f774..5c14e7937 100644 --- a/src/main/java/de/neemann/digital/gui/components/table/TableDialog.java +++ b/src/main/java/de/neemann/digital/gui/components/table/TableDialog.java @@ -1,8 +1,6 @@ package de.neemann.digital.gui.components.table; -import de.neemann.digital.analyse.AnalyseException; -import de.neemann.digital.analyse.TruthTable; -import de.neemann.digital.analyse.TruthTableTableModel; +import de.neemann.digital.analyse.*; import de.neemann.digital.analyse.expression.Expression; import de.neemann.digital.analyse.expression.ExpressionException; import de.neemann.digital.analyse.expression.Variable; @@ -72,6 +70,7 @@ public class TableDialog extends JDialog { private AllSolutionsDialog allSolutionsDialog; private PinMap pinMap; private ExpressionListenerStore lastGeneratedExpressions; + private MinimizerInterface minimizer = new MinimizerQuineMcCluskey(); /** * Creates a new instance @@ -596,7 +595,7 @@ public class TableDialog extends JDialog { expressionListener = new ExpressionListenerJK(expressionListener); lastGeneratedExpressions = new ExpressionListenerStore(expressionListener); - new ExpressionCreator(model.getTable()).create(lastGeneratedExpressions); + new ExpressionCreator(model.getTable(), minimizer).create(lastGeneratedExpressions); } catch (ExpressionException | FormatterException | AnalyseException e1) { new ErrorMessage(Lang.get("msg_errorDuringCalculation")).addCause(e1).show(); diff --git a/src/test/java/de/neemann/digital/analyse/quinemc/MinimizerRegressionTest.java b/src/test/java/de/neemann/digital/analyse/quinemc/MinimizerRegressionTest.java new file mode 100644 index 000000000..a379276a5 --- /dev/null +++ b/src/test/java/de/neemann/digital/analyse/quinemc/MinimizerRegressionTest.java @@ -0,0 +1,105 @@ +package de.neemann.digital.analyse.quinemc; + + +import de.neemann.digital.analyse.MinimizerInterface; +import de.neemann.digital.analyse.MinimizerQuineMcCluskey; +import de.neemann.digital.analyse.MinimizerQuineMcCluskeyExam; +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.gui.components.table.ExpressionListenerStore; +import junit.framework.TestCase; + +import java.util.ArrayList; + +import static de.neemann.digital.analyse.expression.Variable.vars; + +/** + * @author hneemann + */ +public class MinimizerRegressionTest extends TestCase { + + public void testQuineMcCluskey() throws ExpressionException, FormatterException { + MinimizerInterface m = new MinimizerQuineMcCluskey(); + performTests(m); + } + + public void testQuineMcCluskeyExam() throws ExpressionException, FormatterException { + MinimizerInterface m = new MinimizerQuineMcCluskeyExam(); + performTests(m); + } + + private void performTests(MinimizerInterface m) throws ExpressionException, FormatterException { + performFull(m); + performRegression(m); + } + + /** + * up to 3 variables we can calculate all tables possible! + * + * @throws ExpressionException + */ + public void performFull(MinimizerInterface minimizer) throws ExpressionException, FormatterException { + new FullVariantDontCareCreator() { + @Override + public void handleTable(int n, byte[] tab) throws ExpressionException, FormatterException { + performTestCalculation(n, tab, minimizer); + } + }.create(); + } + + + /** + * for more then 3 variables we only test some random tables + * + * @throws ExpressionException + */ + public void performRegression(MinimizerInterface minimizer) throws ExpressionException, FormatterException { + int numOfTest = 2048; + for (int n = 4; n <= 8; n++) { + // test some tables with n variables + // System.out.println(n + " vars: " + numOfTest + "tests"); + for (int i = 0; i < numOfTest; i++) { + performTestCalculationRandom(n, minimizer); + } + numOfTest /= 4; + } + } + + static private void performTestCalculationRandom(int n, MinimizerInterface minimizer) throws ExpressionException, FormatterException { + byte[] tab = new byte[1 << n]; + for (int i = 0; i < tab.length; i++) + tab[i] = (byte) Math.round(Math.random() * 3); // half of the values are don't care + + performTestCalculation(n, tab, minimizer); + } + + /** + * 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, byte[] tab, MinimizerInterface minimizer) throws ExpressionException, FormatterException { + ArrayList v = vars(n); + + final ExpressionListenerStore listener = new ExpressionListenerStore(null); + minimizer.minimize(v, new BoolTableByteArray(tab), "Y", listener); + Expression e = listener.getFirst(); + ; + + 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))); + } + } + +} \ No newline at end of file diff --git a/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyDontCareTest.java b/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyDontCareTest.java deleted file mode 100644 index 5c0b70a82..000000000 --- a/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyDontCareTest.java +++ /dev/null @@ -1,135 +0,0 @@ -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.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 QuineMcCluskeyDontCareTest extends TestCase { - - public void testDontCare() throws Exception, FormatterException { - ArrayList v = vars("A", "B", "C"); - Expression e = new QuineMcCluskey(v) - .fillTableWith(new BoolTableByteArray(new byte[]{1, 1, 0, 0, 1, 2, 2, 0})) - .simplify() - .getExpression(); - - 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, byte[] tab) throws ExpressionException { - performTestCalculation(n, tab); - } - }.create(); - } - - - /** - * for more then 3 variables we only test some random tables - * - * @throws ExpressionException - */ - public void testRegression() throws ExpressionException { - int numOfTest = 2048; - for (int n = 4; n <= 8; n++) { - // test some tables with n variables - // System.out.println(n + " vars: " + numOfTest + "tests"); - for (int i = 0; i < numOfTest; i++) { - performTestCalculationRandom(n); - } - numOfTest /= 4; - } - } - - static private void performTestCalculationRandom(int n) throws ExpressionException { - byte[] tab = new byte[1 << n]; - for (int i = 0; i < tab.length; i++) - tab[i] = (byte) Math.round(Math.random() * 3); // half of the values are don't care - - 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, byte[] tab) throws ExpressionException { - ArrayList v = vars(n); - Expression e = new QuineMcCluskey(v) - .fillTableWith(new BoolTableByteArray(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 { - new FullVariantDontCareCreator() { - @Override - public void handleTable(int n, byte[] tab) throws ExpressionException, FormatterException { - Expression e = createExpression(n, tab); - - byte[] 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); - - byte[] 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, byte[] tab) throws ExpressionException { - ArrayList v = vars(n); - return new QuineMcCluskey(v) - .fillTableWith(new BoolTableByteArray(tab)) - .simplify() - .getExpression(); - } -} \ No newline at end of file diff --git a/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyExactCover.java b/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyExactCoverTest.java similarity index 93% rename from src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyExactCover.java rename to src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyExactCoverTest.java index 3708daafe..52148f269 100644 --- a/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyExactCover.java +++ b/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyExactCoverTest.java @@ -9,7 +9,7 @@ import java.util.Collection; /** * Created by hneemann on 09.03.17. */ -public class QuineMcCluskeyExactCover extends TestCase { +public class QuineMcCluskeyExactCoverTest extends TestCase { public void testExactCoverLoop() { @@ -30,7 +30,7 @@ public class QuineMcCluskeyExactCover extends TestCase { QuineMcCluskey qmc = new QuineMcCluskey(vars, null, primes); - qmc=qmc.simplifyPrimes(null); + qmc.simplifyPrimes(null); final ArrayList pri = qmc.getPrimes(); assertEquals(2, pri.size()); diff --git a/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyRegressionTest.java b/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyRegressionTest.java index 1bd851290..dc1076a00 100644 --- a/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyRegressionTest.java +++ b/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyRegressionTest.java @@ -51,7 +51,7 @@ public class QuineMcCluskeyRegressionTest extends TestCase { System.out.println("--"); while (!t.isFinished()) { System.out.println(FormatToExpression.FORMATTER_JAVA.format(t.getExpression())); - t = t.simplifyStep(); + t.simplifyStep(); } t.simplifyPrimes(new PrimeSelectorDefault()); assertEquals("A || C", FormatToExpression.FORMATTER_JAVA.format(t.getExpression())); 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 1e4eaac80..5b1c4e29b 100644 --- a/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyTest.java +++ b/src/test/java/de/neemann/digital/analyse/quinemc/QuineMcCluskeyTest.java @@ -1,26 +1,35 @@ 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.*; import de.neemann.digital.analyse.expression.format.FormatToExpression; import de.neemann.digital.analyse.expression.format.FormatterException; import de.neemann.digital.analyse.quinemc.primeselector.PrimeSelectorDefault; import junit.framework.TestCase; import java.util.ArrayList; +import java.util.Arrays; 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; +import static de.neemann.digital.analyse.expression.Variable.vars; +import static de.neemann.digital.analyse.expression.format.FormatToExpression.FORMATTER_UNICODE; /** * @author hneemann */ public class QuineMcCluskeyTest extends TestCase { + public void testDontCare() throws Exception, FormatterException { + ArrayList v = vars("A", "B", "C"); + Expression e = new QuineMcCluskey(v) + .fillTableWith(new BoolTableByteArray(new byte[]{1, 1, 0, 0, 1, 2, 2, 0})) + .simplify() + .getExpression(); + + assertEquals("!B", FormatToExpression.FORMATTER_JAVA.format(e)); + } public void testGenerator() throws ExpressionException { Variable a = new Variable("A");// Vorlesung @@ -51,7 +60,8 @@ public class QuineMcCluskeyTest extends TestCase { Variable d = new Variable("D"); 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); + t.simplifyStep(); assertFalse(t.isFinished()); assertEquals( @@ -68,7 +78,7 @@ public class QuineMcCluskeyTest extends TestCase { "101-,6,7\n", t.toString()); - t = t.simplifyStep(); + t.simplifyStep(); assertFalse(t.isFinished()); /* @@ -90,9 +100,9 @@ public class QuineMcCluskeyTest extends TestCase { assertEquals( "--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.simplifyStep(); assertTrue(t.isFinished()); assertEquals("", t.toString()); @@ -164,4 +174,55 @@ public class QuineMcCluskeyTest extends TestCase { assertTrue(e instanceof Constant); assertTrue(((Constant) e).getValue()); } + + public void testMultipleResults() throws ExpressionException { + QuineMcCluskeyExam t = new QuineMcCluskeyExam(Variable.vars("A", "B", "C")); + t.fillTableWith(new BoolTableByteArray(new byte[]{0, 1, 1, 0, 0, 1, 1, 1})); + PrimeSelectorDefault ps = new PrimeSelectorDefault(); + t.simplify(ps); + + assertEquals(2, ps.getAllSolutions().size()); + } + + public void testComplexity() throws Exception { + new FullVariantDontCareCreator() { + @Override + public void handleTable(int n, byte[] tab) throws ExpressionException, FormatterException { + Expression e = createExpression(n, tab); + + byte[] 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); + + byte[] 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, byte[] tab) throws ExpressionException { + ArrayList v = vars(n); + return new QuineMcCluskey(v) + .fillTableWith(new BoolTableByteArray(tab)) + .simplify() + .getExpression(); + } + } \ No newline at end of file