mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-27 15:03:21 -04:00
Added a table reducer to remove variables from tables which are not used at all.
So the QMC algorithm has to deal with a reduced number of variables.
This commit is contained in:
parent
0b44a0129f
commit
d7cb8e1497
@ -23,7 +23,7 @@ import java.util.List;
|
||||
* @author hneemann
|
||||
*/
|
||||
public class ModelAnalyser {
|
||||
private static final int MAX_INPUTS_ALLOWED = 12;
|
||||
private static final int MAX_INPUTS_ALLOWED = 24;
|
||||
|
||||
private final Model model;
|
||||
private final ArrayList<Signal> inputs;
|
||||
@ -109,7 +109,8 @@ public class ModelAnalyser {
|
||||
* @throws NodeException NodeException
|
||||
*/
|
||||
public TruthTable analyse() throws NodeException {
|
||||
|
||||
System.out.print("start to analyse the model");
|
||||
long time = System.currentTimeMillis();
|
||||
BitSetter bitsetter = new BitSetter(inputs.size()) {
|
||||
@Override
|
||||
public void setBit(int row, int bit, boolean value) {
|
||||
@ -128,7 +129,6 @@ public class ModelAnalyser {
|
||||
tt.addResult(s.getName(), e);
|
||||
}
|
||||
|
||||
|
||||
model.init();
|
||||
for (int row = 0; row < rows; row++) {
|
||||
bitsetter.fill(row);
|
||||
@ -137,6 +137,8 @@ public class ModelAnalyser {
|
||||
data.get(i).set(row, outputs.get(i).getValue().getBool());
|
||||
}
|
||||
}
|
||||
time = System.currentTimeMillis() - time;
|
||||
System.out.println(": " + time / 1000.0 + " sec");
|
||||
return tt;
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,13 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class ContextFiller extends ContextMap implements Iterable<Variable> {
|
||||
|
||||
private final ArrayList<Variable> vars;
|
||||
private final List<Variable> vars;
|
||||
private final int rowCount;
|
||||
private final BitSetter bitSetter;
|
||||
|
||||
@ -29,7 +27,16 @@ public class ContextFiller extends ContextMap implements Iterable<Variable> {
|
||||
*
|
||||
* @param variables the variables to use
|
||||
*/
|
||||
public ContextFiller(ArrayList<Variable> variables) {
|
||||
public ContextFiller(Variable... variables) {
|
||||
this(Arrays.asList(variables));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param variables the variables to use
|
||||
*/
|
||||
public ContextFiller(List<Variable> variables) {
|
||||
vars = variables;
|
||||
rowCount = 1 << vars.size();
|
||||
bitSetter = new BitSetter(vars.size()) {
|
||||
@ -83,7 +90,7 @@ public class ContextFiller extends ContextMap implements Iterable<Variable> {
|
||||
/**
|
||||
* @return the variables to use
|
||||
*/
|
||||
public ArrayList<Variable> getVariables() {
|
||||
public List<Variable> getVariables() {
|
||||
return vars;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,110 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
/**
|
||||
* Checks if a bool table is independent from a certain variable
|
||||
* Created by hneemann on 12.03.17.
|
||||
*/
|
||||
public final class IndependentChecker {
|
||||
|
||||
private final BoolTable boolTable;
|
||||
private final int vars;
|
||||
private final int checkSize;
|
||||
|
||||
/**
|
||||
* Creates a new BoolTable
|
||||
*
|
||||
* @param boolTable the table to investigate
|
||||
*/
|
||||
public IndependentChecker(BoolTable boolTable) {
|
||||
this.boolTable = boolTable;
|
||||
|
||||
int v = 0;
|
||||
int s = boolTable.size();
|
||||
while (s > 1) {
|
||||
s = s / 2;
|
||||
v++;
|
||||
}
|
||||
vars = v;
|
||||
checkSize = boolTable.size() / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of variables
|
||||
*/
|
||||
public int getVars() {
|
||||
return vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if the given bool table is dependent on the given variable
|
||||
*
|
||||
* @param varNum the variable to check
|
||||
* @return true if table is independent
|
||||
*/
|
||||
public boolean isIndependentFrom(int varNum) {
|
||||
int bitMask = 1 << (vars - varNum - 1);
|
||||
int lowMask = bitMask - 1;
|
||||
int highMask = ~lowMask;
|
||||
|
||||
for (int n = 0; n < checkSize; n++) {
|
||||
int i1 = (n & lowMask) | ((n & highMask) << 1);
|
||||
int i2 = i1 | bitMask;
|
||||
|
||||
ThreeStateValue v1 = boolTable.get(i1);
|
||||
ThreeStateValue v2 = boolTable.get(i2);
|
||||
|
||||
if (v1.equals(v2))
|
||||
continue;
|
||||
|
||||
if (v1.equals(ThreeStateValue.dontCare) || v2.equals(ThreeStateValue.dontCare))
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a table with the given variable removed
|
||||
*
|
||||
* @param varNum the variable to remove
|
||||
* @return the reduced BoolTable
|
||||
*/
|
||||
public BoolTable removeVar(int varNum) {
|
||||
if (varNum >= vars || varNum < 0)
|
||||
throw new RuntimeException("variable does not exist");
|
||||
return new BoolTableRemoveVar(boolTable, vars, varNum);
|
||||
}
|
||||
|
||||
private static final class BoolTableRemoveVar implements BoolTable {
|
||||
private final BoolTable boolTable;
|
||||
private final int bitMask;
|
||||
private final int lowMask;
|
||||
private final int highMask;
|
||||
private final int size;
|
||||
|
||||
private BoolTableRemoveVar(BoolTable boolTable, int vars, int varNum) {
|
||||
this.boolTable = boolTable;
|
||||
bitMask = 1 << (vars - varNum - 1);
|
||||
lowMask = bitMask - 1;
|
||||
highMask = ~lowMask;
|
||||
size = 1 << (vars - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreeStateValue get(int n) {
|
||||
int i = (n & lowMask) | ((n & highMask) << 1);
|
||||
ThreeStateValue v = boolTable.get(i);
|
||||
if (v.equals(ThreeStateValue.dontCare))
|
||||
return boolTable.get(i | bitMask);
|
||||
else
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package de.neemann.digital.analyse.quinemc;
|
||||
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* If the result does not depend on a certain variable, this variable is removed.
|
||||
* <p>
|
||||
* Created by hneemann on 12.03.17.
|
||||
*/
|
||||
public class TableReducer {
|
||||
|
||||
private List<Variable> vars;
|
||||
private BoolTable table;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param vars the variable
|
||||
* @param table the bool table
|
||||
*/
|
||||
public TableReducer(List<Variable> vars, BoolTable table) {
|
||||
this.vars = new ArrayList<>();
|
||||
this.vars.addAll(vars);
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there are reduce variables
|
||||
*
|
||||
* @return true is reduction was possible
|
||||
*/
|
||||
public boolean canReduce() {
|
||||
boolean isReduced = false;
|
||||
Iterator<Variable> it = vars.iterator();
|
||||
int var = 0;
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
IndependentChecker ic = new IndependentChecker(table);
|
||||
if (ic.isIndependentFrom(var)) {
|
||||
it.remove();
|
||||
table = ic.removeVar(var);
|
||||
isReduced = true;
|
||||
} else {
|
||||
var++;
|
||||
}
|
||||
}
|
||||
return isReduced;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the remaining variables
|
||||
*/
|
||||
public List<Variable> getVars() {
|
||||
return vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the reduced table
|
||||
*/
|
||||
public BoolTable getTable() {
|
||||
return table;
|
||||
}
|
||||
}
|
@ -1,14 +1,18 @@
|
||||
package de.neemann.digital.gui.components.table;
|
||||
|
||||
import de.neemann.digital.analyse.AnalyseException;
|
||||
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.lang.Lang;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -24,6 +28,8 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
public class ExpressionCreator {
|
||||
|
||||
private static final int MAX_INPUTS_ALLOWED = 12;
|
||||
|
||||
private final TruthTable theTable;
|
||||
|
||||
/**
|
||||
@ -40,24 +46,22 @@ public class ExpressionCreator {
|
||||
*
|
||||
* @throws ExpressionException ExpressionException
|
||||
* @throws FormatterException FormatterException
|
||||
* @throws AnalyseException AnalyseException
|
||||
*/
|
||||
public void create(ExpressionListener listener) throws ExpressionException, FormatterException {
|
||||
public void create(ExpressionListener listener) throws ExpressionException, FormatterException, AnalyseException {
|
||||
final List<Variable> vars = Collections.unmodifiableList(theTable.getVars());
|
||||
long time = System.currentTimeMillis();
|
||||
if (theTable.getResultCount() > 100) {
|
||||
ExecutorService ex = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() / 2);
|
||||
ExecutorService ex = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
||||
ThreadSaveExpressionListener threadListener = new ThreadSaveExpressionListener(listener);
|
||||
for (int table = 0; table < theTable.getResultCount(); table++) {
|
||||
final QuineMcCluskey qmc = new QuineMcCluskey(vars)
|
||||
.fillTableWith(theTable.getResult(table));
|
||||
final String resultName = theTable.getResultName(table);
|
||||
final int t = table;
|
||||
ex.submit(() -> {
|
||||
try {
|
||||
System.out.println("start " + t);
|
||||
calcColumn(threadListener, qmc, resultName, vars);
|
||||
simplify(listener, vars, theTable.getResultName(t), theTable.getResult(t));
|
||||
System.out.println("end " + t);
|
||||
} catch (ExpressionException | FormatterException e) {
|
||||
} catch (ExpressionException | FormatterException | AnalyseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
@ -70,17 +74,30 @@ public class ExpressionCreator {
|
||||
}
|
||||
threadListener.close();
|
||||
} else {
|
||||
for (int table = 0; table < theTable.getResultCount(); table++) {
|
||||
QuineMcCluskey qmc = new QuineMcCluskey(vars)
|
||||
.fillTableWith(theTable.getResult(table));
|
||||
calcColumn(listener, qmc, theTable.getResultName(table), vars);
|
||||
}
|
||||
for (int table = 0; table < theTable.getResultCount(); table++)
|
||||
simplify(listener, vars, theTable.getResultName(table), theTable.getResult(table));
|
||||
listener.close();
|
||||
}
|
||||
time = System.currentTimeMillis() - time;
|
||||
System.out.println("time: " + time / 1000.0 + " sec");
|
||||
}
|
||||
|
||||
private void simplify(ExpressionListener listener, List<Variable> vars, String resultName, BoolTable boolTable) throws AnalyseException, ExpressionException, FormatterException {
|
||||
TableReducer tr = new TableReducer(vars, boolTable);
|
||||
List<Variable> localVars = vars;
|
||||
if (tr.canReduce()) {
|
||||
System.out.println(resultName + " reduced from " + vars.size() + " to " + tr.getVars().size() + " variables");
|
||||
boolTable = tr.getTable();
|
||||
localVars = tr.getVars();
|
||||
}
|
||||
if (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);
|
||||
calcColumn(listener, qmc, resultName, localVars);
|
||||
}
|
||||
|
||||
private static void calcColumn(ExpressionListener listener, QuineMcCluskey qmc, String name, List<Variable> vars) throws ExpressionException, FormatterException {
|
||||
PrimeSelector ps = new PrimeSelectorDefault();
|
||||
Expression e = qmc.simplify(ps).getExpression();
|
||||
|
@ -1,5 +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.expression.Expression;
|
||||
@ -579,7 +580,7 @@ public class TableDialog extends JDialog {
|
||||
lastGeneratedExpressions = new ExpressionListenerStore(expressionListener);
|
||||
new ExpressionCreator(model.getTable()).create(lastGeneratedExpressions);
|
||||
|
||||
} catch (ExpressionException | FormatterException e1) {
|
||||
} catch (ExpressionException | FormatterException | AnalyseException e1) {
|
||||
new ErrorMessage(Lang.get("msg_errorDuringCalculation")).addCause(e1).show();
|
||||
}
|
||||
}
|
||||
|
@ -423,6 +423,8 @@ Zur Analyse können Sie die Schaltung im Gatterschrittmodus ausführen.</string>
|
||||
<string name="err_splitterBitsMismatch">Die Bitzahl am Spiltter passt nicht</string>
|
||||
<string name="err_tableBecomesToSmall">Es sind mindestens zwei Eingänge erforderlich!</string>
|
||||
<string name="err_toManyInputs_max_N0_is_N1">Zu viele Eingänge. Es sind nur {0} Eingänge erlaubt, es wurden aber {1} gefunden.</string>
|
||||
<string name="err_toManyInputsIn_N0_max_N1_is_N2">Zu viele Variablen bei der Vereinfachung von {0}.
|
||||
Es sind nur {1} Variablen erlaubt, es wurden aber {2} gefunden.</string>
|
||||
<string name="err_varNotAllowedInCUPL_N">In CUPL ist die Variable {0} nicht erlaubt!</string>
|
||||
<string name="err_varNotDefined_N">Variable {0} ist nicht definiert.</string>
|
||||
<string name="err_parserUnexpectedToken_N">Unerwartetes Zeichen {0}</string>
|
||||
|
@ -410,6 +410,8 @@ To analyse you can run the circuit in single gate step mode.</string>
|
||||
<string name="err_splitterBitsMismatch">Bit count of splitter is not matching</string>
|
||||
<string name="err_tableBecomesToSmall">Two inputs are required!</string>
|
||||
<string name="err_toManyInputs_max_N0_is_N1">To many inputs, allowed are {0} but {1} are found.</string>
|
||||
<string name="err_toManyInputsIn_N0_max_N1_is_N2">To many variables used in {0},
|
||||
allowed are {1} variables but {2} are found.</string>
|
||||
<string name="err_varNotAllowedInCUPL_N">Variable {0} is not allowed in CUPL source!</string>
|
||||
<string name="err_varNotDefined_N">Variable {0} not defined</string>
|
||||
<string name="err_parserUnexpectedToken_N">Unexpected Token {0}</string>
|
||||
|
@ -0,0 +1,76 @@
|
||||
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 junit.framework.TestCase;
|
||||
|
||||
import static de.neemann.digital.analyse.expression.Operation.and;
|
||||
|
||||
/**
|
||||
* Created by hneemann on 12.03.17.
|
||||
*/
|
||||
public class IndependentCheckerTest extends TestCase {
|
||||
private Variable a = new Variable("A");
|
||||
private Variable b = new Variable("B");
|
||||
private Variable c = new Variable("C");
|
||||
private Variable d = new Variable("D");
|
||||
|
||||
public void testSimple() {
|
||||
Expression ex = and(a, b, c);
|
||||
|
||||
ContextFiller cf = new ContextFiller(a, b, c, d);
|
||||
|
||||
BoolTableExpression bte = new BoolTableExpression(ex, cf);
|
||||
|
||||
IndependentChecker ic = new IndependentChecker(bte);
|
||||
assertEquals(4, ic.getVars());
|
||||
|
||||
assertFalse(ic.isIndependentFrom(0));
|
||||
assertFalse(ic.isIndependentFrom(1));
|
||||
assertFalse(ic.isIndependentFrom(2));
|
||||
assertTrue(ic.isIndependentFrom(3));
|
||||
}
|
||||
|
||||
public void testSimple2() {
|
||||
Expression ex = and(a, c, d);
|
||||
|
||||
ContextFiller cf = new ContextFiller(a, b, c, d);
|
||||
|
||||
BoolTableExpression bte = new BoolTableExpression(ex, cf);
|
||||
|
||||
IndependentChecker ic = new IndependentChecker(bte);
|
||||
assertEquals(4, ic.getVars());
|
||||
|
||||
assertFalse(ic.isIndependentFrom(0));
|
||||
assertTrue(ic.isIndependentFrom(1));
|
||||
assertFalse(ic.isIndependentFrom(2));
|
||||
assertFalse(ic.isIndependentFrom(3));
|
||||
}
|
||||
|
||||
|
||||
public void testRemoveVar() {
|
||||
Expression ex = and(a, b, c);
|
||||
ContextFiller cf = new ContextFiller(a, b, c, d);
|
||||
BoolTableExpression bte = new BoolTableExpression(ex, cf);
|
||||
IndependentChecker ic = new IndependentChecker(bte);
|
||||
BoolTable btr = ic.removeVar(3);
|
||||
assertEquals(8, btr.size());
|
||||
for (int i = 0; i < 7; i++)
|
||||
assertEquals(ThreeStateValue.zero, btr.get(i));
|
||||
assertEquals(ThreeStateValue.one, btr.get(7));
|
||||
}
|
||||
|
||||
public void testRemoveVar2() {
|
||||
Expression ex = and(a, c, d);
|
||||
ContextFiller cf = new ContextFiller(a, b, c, d);
|
||||
BoolTableExpression bte = new BoolTableExpression(ex, cf);
|
||||
IndependentChecker ic = new IndependentChecker(bte);
|
||||
BoolTable btr = ic.removeVar(1);
|
||||
assertEquals(8, btr.size());
|
||||
for (int i = 0; i < 7; i++)
|
||||
assertEquals(ThreeStateValue.zero, btr.get(i));
|
||||
assertEquals(ThreeStateValue.one, btr.get(7));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
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 junit.framework.TestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static de.neemann.digital.analyse.expression.Operation.and;
|
||||
|
||||
/**
|
||||
* Created by hneemann on 12.03.17.
|
||||
*/
|
||||
public class TableReducerTest extends TestCase {
|
||||
private Variable a = new Variable("A");
|
||||
private Variable b = new Variable("B");
|
||||
private Variable c = new Variable("C");
|
||||
private Variable d = new Variable("D");
|
||||
|
||||
|
||||
public void testReduce() {
|
||||
List<Variable> vars=new ArrayList<>();
|
||||
vars.add(a);
|
||||
vars.add(b);
|
||||
vars.add(c);
|
||||
vars.add(d);
|
||||
Expression ex = and(a, b, c);
|
||||
ContextFiller cf = new ContextFiller(vars);
|
||||
BoolTableExpression bte = new BoolTableExpression(ex, cf);
|
||||
TableReducer tr = new TableReducer(vars, bte);
|
||||
|
||||
assertTrue(tr.canReduce());
|
||||
|
||||
vars = tr.getVars();
|
||||
assertEquals(3, vars.size());
|
||||
assertEquals(a, vars.get(0));
|
||||
assertEquals(b, vars.get(1));
|
||||
assertEquals(c, vars.get(2));
|
||||
}
|
||||
|
||||
public void testReduce2() {
|
||||
List<Variable> vars=new ArrayList<>();
|
||||
vars.add(a);
|
||||
vars.add(b);
|
||||
vars.add(c);
|
||||
vars.add(d);
|
||||
Expression ex = and(a, c, d);
|
||||
ContextFiller cf = new ContextFiller(vars);
|
||||
BoolTableExpression bte = new BoolTableExpression(ex, cf);
|
||||
TableReducer tr = new TableReducer(vars, bte);
|
||||
|
||||
assertTrue(tr.canReduce());
|
||||
|
||||
vars = tr.getVars();
|
||||
assertEquals(3, vars.size());
|
||||
assertEquals(a, vars.get(0));
|
||||
assertEquals(c, vars.get(1));
|
||||
assertEquals(d, vars.get(2));
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user