mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-27 15:03:21 -04:00
Introduced a MinimizerInterface to abstract a minimizer algorithm.
This commit is contained in:
parent
7877c2de4f
commit
bf4b8c3976
@ -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<Variable> vars, BoolTable boolTable, String resultName, ExpressionListener listener) throws ExpressionException, FormatterException;
|
||||
|
||||
}
|
@ -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<Variable> 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<TableRow> 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<Variable> vars) {
|
||||
return new QuineMcCluskey(vars);
|
||||
}
|
||||
}
|
@ -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<Variable> vars) {
|
||||
return new QuineMcCluskeyExam(vars);
|
||||
}
|
||||
}
|
@ -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<Variable> variables;
|
||||
private final ArrayList<TableRow> 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<TableRow> np = new ArrayList<TableRow>();
|
||||
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<TableRow> newList = new ArrayList<TableRow>();
|
||||
ArrayList<TableRow> 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<Variable> 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<Integer> 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<TableRow> primes) {
|
||||
|
@ -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.
|
||||
* <p>
|
||||
* 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<Variable> variables) {
|
||||
super(variables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplify the primes
|
||||
*
|
||||
* @param primeSelector the prime selector to use
|
||||
*/
|
||||
@Override
|
||||
public void simplifyPrimes(PrimeSelector primeSelector) {
|
||||
ArrayList<TableRow> primes = getPrimes();
|
||||
ArrayList<TableRow> primesAvail = new ArrayList<>(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());
|
||||
}
|
||||
|
||||
LOGGER.debug("residual primes " + primesAvail.size());
|
||||
|
||||
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);
|
||||
}
|
||||
LOGGER.debug("final primes " + primes.size());
|
||||
}
|
||||
|
||||
}
|
@ -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<TableRow> 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 {
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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<Variable> 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)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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<Variable> 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<Variable> 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<Variable> v = vars(n);
|
||||
return new QuineMcCluskey(v)
|
||||
.fillTableWith(new BoolTableByteArray(tab))
|
||||
.simplify()
|
||||
.getExpression();
|
||||
}
|
||||
}
|
@ -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<TableRow> pri = qmc.getPrimes();
|
||||
assertEquals(2, pri.size());
|
||||
|
@ -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()));
|
||||
|
@ -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<Variable> 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<Variable> v = vars(n);
|
||||
return new QuineMcCluskey(v)
|
||||
.fillTableWith(new BoolTableByteArray(tab))
|
||||
.simplify()
|
||||
.getExpression();
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user