mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-17 08:55:05 -04:00
added expression creator which uses the QMC algorithm
This commit is contained in:
parent
d016ddea94
commit
5344d520a4
@ -0,0 +1,152 @@
|
|||||||
|
package de.neemann.digital.analyse;
|
||||||
|
|
||||||
|
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.Operation;
|
||||||
|
import de.neemann.digital.analyse.expression.format.FormatToExpression;
|
||||||
|
import de.neemann.digital.analyse.expression.format.FormatterException;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the expressions to create a JK-FF state machine
|
||||||
|
*
|
||||||
|
* @author hneemann
|
||||||
|
*/
|
||||||
|
public class DetermineJKStateMachine {
|
||||||
|
private Expression j = null;
|
||||||
|
private Expression nk = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance
|
||||||
|
*
|
||||||
|
* @param name the name of the state variable
|
||||||
|
* @param e the expression to split in J and K expression
|
||||||
|
* @throws ExpressionException ExpressionException
|
||||||
|
* @throws FormatterException FormatterException
|
||||||
|
*/
|
||||||
|
public DetermineJKStateMachine(String name, Expression e) throws ExpressionException, FormatterException {
|
||||||
|
String notName = "¬" + name;
|
||||||
|
|
||||||
|
boolean wasK = false;
|
||||||
|
boolean wasJ = false;
|
||||||
|
for (Expression or : getOrs(e)) {
|
||||||
|
|
||||||
|
Expression term = null;
|
||||||
|
boolean belongsToK = false;
|
||||||
|
boolean belongsToJ = false;
|
||||||
|
|
||||||
|
for (Expression a : getAnds(or)) {
|
||||||
|
String str = FormatToExpression.FORMATTER_UNICODE.format(a);
|
||||||
|
if (str.equals(name)) {
|
||||||
|
belongsToK = true;
|
||||||
|
wasK = true;
|
||||||
|
} else if (str.equals(notName)) {
|
||||||
|
belongsToJ = true;
|
||||||
|
wasJ = true;
|
||||||
|
} else {
|
||||||
|
term = and(term, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (belongsToJ && belongsToK) {
|
||||||
|
throw new ExpressionException("contains var and not var");
|
||||||
|
} else {
|
||||||
|
if (belongsToJ) {
|
||||||
|
j = or(term, j);
|
||||||
|
} else if (belongsToK) {
|
||||||
|
nk = or(term, nk);
|
||||||
|
} else {
|
||||||
|
j = or(term, j);
|
||||||
|
nk = or(term, nk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j == null) {
|
||||||
|
if (wasJ) j = Constant.ONE;
|
||||||
|
else j = Constant.ZERO;
|
||||||
|
}
|
||||||
|
if (nk == null) {
|
||||||
|
if (wasK) nk = Constant.ONE;
|
||||||
|
else nk = Constant.ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Iterable<Expression> getOrs(Expression e) {
|
||||||
|
if (e instanceof Operation.Or) {
|
||||||
|
return ((Operation.Or) e).getExpressions();
|
||||||
|
} else
|
||||||
|
return new AsIterable<>(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Iterable<? extends Expression> getAnds(Expression e) {
|
||||||
|
if (e instanceof Operation.And) {
|
||||||
|
return ((Operation.And) e).getExpressions();
|
||||||
|
} else
|
||||||
|
return new AsIterable<>(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the J expression
|
||||||
|
*/
|
||||||
|
public Expression getJ() {
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the not(K) expression
|
||||||
|
*/
|
||||||
|
public Expression getNK() {
|
||||||
|
return nk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the K expression
|
||||||
|
*/
|
||||||
|
public Expression getK() {
|
||||||
|
return not(nk);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class AsIterable<T> implements Iterable<T> {
|
||||||
|
private final T item;
|
||||||
|
|
||||||
|
private AsIterable(T item) {
|
||||||
|
this.item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<T> iterator() {
|
||||||
|
return new SingleItemIterator<>(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class SingleItemIterator<T> implements Iterator<T> {
|
||||||
|
private T item;
|
||||||
|
|
||||||
|
private SingleItemIterator(T item) {
|
||||||
|
this.item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return item != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T next() {
|
||||||
|
T ee = item;
|
||||||
|
item = null;
|
||||||
|
return ee;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
package de.neemann.digital.analyse;
|
package de.neemann.digital.analyse;
|
||||||
|
|
||||||
import de.neemann.digital.analyse.expression.BitSetter;
|
import de.neemann.digital.analyse.expression.BitSetter;
|
||||||
|
import de.neemann.digital.analyse.expression.Context;
|
||||||
|
import de.neemann.digital.analyse.expression.ExpressionException;
|
||||||
import de.neemann.digital.analyse.expression.Variable;
|
import de.neemann.digital.analyse.expression.Variable;
|
||||||
import de.neemann.digital.analyse.quinemc.BoolTable;
|
import de.neemann.digital.analyse.quinemc.BoolTable;
|
||||||
import de.neemann.digital.analyse.quinemc.BoolTableIntArray;
|
import de.neemann.digital.analyse.quinemc.BoolTableIntArray;
|
||||||
@ -44,6 +46,19 @@ public class TruthTable {
|
|||||||
results = new ArrayList<>();
|
results = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance
|
||||||
|
*
|
||||||
|
* @param newVars the variables to use
|
||||||
|
* @param oldTable delivers the column names for the results
|
||||||
|
*/
|
||||||
|
public TruthTable(ArrayList<Variable> newVars, TruthTable oldTable) {
|
||||||
|
this(newVars);
|
||||||
|
for (int i = 0; i < oldTable.getResultCount(); i++) {
|
||||||
|
addResult(oldTable.results.get(i).getName(), new BoolTableIntArray(getRows()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of rows
|
* Returns the number of rows
|
||||||
*
|
*
|
||||||
@ -63,6 +78,17 @@ public class TruthTable {
|
|||||||
results.add(new Result(name, values));
|
results.add(new Result(name, values));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new column
|
||||||
|
*
|
||||||
|
* @return this for call chaining
|
||||||
|
*/
|
||||||
|
public TruthTable addResult() {
|
||||||
|
results.add(new Result("Y", new BoolTableIntArray(getRows())));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a variable
|
* Adds a variable
|
||||||
*
|
*
|
||||||
@ -179,6 +205,92 @@ public class TruthTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the column name
|
||||||
|
*
|
||||||
|
* @param columnIndex the column
|
||||||
|
* @param name the new name
|
||||||
|
*/
|
||||||
|
public void setColumnName(int columnIndex, String name) {
|
||||||
|
if (columnIndex < variables.size())
|
||||||
|
variables.set(columnIndex, new Variable(name));
|
||||||
|
else {
|
||||||
|
results.get(columnIndex - variables.size()).setName(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the used variables
|
||||||
|
*/
|
||||||
|
public ArrayList<Variable> getVars() {
|
||||||
|
return variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value which is determined by the actual context state
|
||||||
|
*
|
||||||
|
* @param result the result index
|
||||||
|
* @param context the context
|
||||||
|
* @return the table value
|
||||||
|
* @throws ExpressionException ExpressionException
|
||||||
|
*/
|
||||||
|
public int getByContext(int result, Context context) throws ExpressionException {
|
||||||
|
return results.get(result).getValues().get(getIndexByContext(context)).asInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value which is determined by the actual context state
|
||||||
|
*
|
||||||
|
* @param result the result index
|
||||||
|
* @param context the context
|
||||||
|
* @param value the new value
|
||||||
|
* @throws ExpressionException ExpressionException
|
||||||
|
*/
|
||||||
|
public void setByContext(int result, Context context, int value) throws ExpressionException {
|
||||||
|
BoolTable v = results.get(result).getValues();
|
||||||
|
if (v instanceof BoolTableIntArray)
|
||||||
|
((BoolTableIntArray) v).set(getIndexByContext(context), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getIndexByContext(Context context) throws ExpressionException {
|
||||||
|
int mask = 1 << (variables.size() - 1);
|
||||||
|
int index = 0;
|
||||||
|
for (int i = 0; i < variables.size(); i++) {
|
||||||
|
if (context.get(variables.get(i))) {
|
||||||
|
index |= mask;
|
||||||
|
}
|
||||||
|
mask >>= 1;
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of results
|
||||||
|
*/
|
||||||
|
public int getResultCount() {
|
||||||
|
return results.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the result with the given index
|
||||||
|
*
|
||||||
|
* @param result the result index
|
||||||
|
* @return the table representing the result
|
||||||
|
*/
|
||||||
|
public BoolTable getResult(int result) {
|
||||||
|
return results.get(result).getValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the results name
|
||||||
|
*
|
||||||
|
* @param result index of result
|
||||||
|
* @return the name
|
||||||
|
*/
|
||||||
|
public String getResultName(int result) {
|
||||||
|
return results.get(result).getName();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A single result column
|
* A single result column
|
||||||
*/
|
*/
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package de.neemann.digital.analyse;
|
package de.neemann.digital.analyse;
|
||||||
|
|
||||||
|
import javax.swing.event.TableModelEvent;
|
||||||
import javax.swing.event.TableModelListener;
|
import javax.swing.event.TableModelListener;
|
||||||
import javax.swing.table.TableModel;
|
import javax.swing.table.TableModel;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to visualize a truthTable instance in a JTable
|
* Used to visualize a truthTable instance in a JTable
|
||||||
@ -9,7 +11,13 @@ import javax.swing.table.TableModel;
|
|||||||
* @author hneemann
|
* @author hneemann
|
||||||
*/
|
*/
|
||||||
public class TruthTableTableModel implements TableModel {
|
public class TruthTableTableModel implements TableModel {
|
||||||
|
/**
|
||||||
|
* String representation of the states
|
||||||
|
*/
|
||||||
|
public static final String[] STATENAMES = new String[]{"0", "1", "x"};
|
||||||
|
|
||||||
private final TruthTable truthTable;
|
private final TruthTable truthTable;
|
||||||
|
private ArrayList<TableModelListener> listeners = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance
|
* Creates a new instance
|
||||||
@ -54,13 +62,36 @@ public class TruthTableTableModel implements TableModel {
|
|||||||
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
||||||
if (aValue instanceof Integer)
|
if (aValue instanceof Integer)
|
||||||
truthTable.setValue(rowIndex, columnIndex, (Integer) aValue);
|
truthTable.setValue(rowIndex, columnIndex, (Integer) aValue);
|
||||||
|
if (aValue instanceof String) {
|
||||||
|
if (aValue.toString().equals("0"))
|
||||||
|
truthTable.setValue(rowIndex, columnIndex, 0);
|
||||||
|
else if (aValue.toString().equals("1"))
|
||||||
|
truthTable.setValue(rowIndex, columnIndex, 1);
|
||||||
|
else
|
||||||
|
truthTable.setValue(rowIndex, columnIndex, 2);
|
||||||
|
}
|
||||||
|
fireModelEvent(rowIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fireModelEvent(int rowIndex) {
|
||||||
|
TableModelEvent e = new TableModelEvent(this, rowIndex);
|
||||||
|
for (TableModelListener l : listeners)
|
||||||
|
l.tableChanged(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addTableModelListener(TableModelListener l) {
|
public void addTableModelListener(TableModelListener l) {
|
||||||
|
listeners.add(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeTableModelListener(TableModelListener l) {
|
public void removeTableModelListener(TableModelListener l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the truth table used by this model
|
||||||
|
*/
|
||||||
|
public TruthTable getTable() {
|
||||||
|
return truthTable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import de.neemann.digital.draw.shapes.ShapeFactory;
|
|||||||
import de.neemann.digital.gui.components.*;
|
import de.neemann.digital.gui.components.*;
|
||||||
import de.neemann.digital.gui.components.data.DataSetDialog;
|
import de.neemann.digital.gui.components.data.DataSetDialog;
|
||||||
import de.neemann.digital.gui.components.listing.ROMListingDialog;
|
import de.neemann.digital.gui.components.listing.ROMListingDialog;
|
||||||
|
import de.neemann.digital.gui.components.table.TableFrame;
|
||||||
import de.neemann.digital.gui.state.State;
|
import de.neemann.digital.gui.state.State;
|
||||||
import de.neemann.digital.gui.state.StateManager;
|
import de.neemann.digital.gui.state.StateManager;
|
||||||
import de.neemann.digital.lang.Lang;
|
import de.neemann.digital.lang.Lang;
|
||||||
@ -401,7 +402,7 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E
|
|||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
try {
|
try {
|
||||||
Model model = new ModelDescription(circuitComponent.getCircuit(), library).createModel(false);
|
Model model = new ModelDescription(circuitComponent.getCircuit(), library).createModel(false);
|
||||||
new TableDialog(Main.this, new ModelAnalyser(model).analyse()).setVisible(true);
|
new TableFrame(Main.this, new ModelAnalyser(model).analyse()).setVisible(true);
|
||||||
elementState.activate();
|
elementState.activate();
|
||||||
} catch (PinException | NodeException | AnalyseException e1) {
|
} catch (PinException | NodeException | AnalyseException e1) {
|
||||||
showErrorAndStopModel(Lang.get("msg_annalyseErr"), e1);
|
showErrorAndStopModel(Lang.get("msg_annalyseErr"), e1);
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
package de.neemann.digital.gui.components.table;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple Dialog to show all possible functions of a truth table
|
||||||
|
*
|
||||||
|
* @author hneemann
|
||||||
|
*/
|
||||||
|
public class AllSolutionsFrame extends JDialog {
|
||||||
|
private final JTextArea textArea;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Frame
|
||||||
|
*
|
||||||
|
* @param owner the owner frame
|
||||||
|
* @param font the font to use
|
||||||
|
*/
|
||||||
|
public AllSolutionsFrame(Frame owner, Font font) {
|
||||||
|
super(owner, "Alle möglichen Lösungen", false);
|
||||||
|
setDefaultCloseOperation(HIDE_ON_CLOSE);
|
||||||
|
|
||||||
|
textArea = new JTextArea(6, 30);
|
||||||
|
textArea.setFont(font);
|
||||||
|
textArea.setEditable(false);
|
||||||
|
textArea.setTabSize(3);
|
||||||
|
|
||||||
|
getContentPane().add(new JScrollPane(textArea));
|
||||||
|
pack();
|
||||||
|
setLocationRelativeTo(owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the gicen text to the frame
|
||||||
|
*
|
||||||
|
* @param text the text
|
||||||
|
* @return this for call chaining
|
||||||
|
*/
|
||||||
|
public AllSolutionsFrame setText(String text) {
|
||||||
|
textArea.setText(text);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
package de.neemann.digital.gui.components.table;
|
||||||
|
|
||||||
|
import de.neemann.digital.analyse.DetermineJKStateMachine;
|
||||||
|
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.QuineMcCluskey;
|
||||||
|
import de.neemann.digital.analyse.quinemc.TableRow;
|
||||||
|
import de.neemann.digital.analyse.quinemc.primeselector.BruteForceGetAll;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to generate the expressions belonging to the given truth table
|
||||||
|
*
|
||||||
|
* @author hneemann
|
||||||
|
*/
|
||||||
|
public abstract class ExpressionCreator {
|
||||||
|
|
||||||
|
private final TruthTable theTable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance
|
||||||
|
*
|
||||||
|
* @param theTable the table to use
|
||||||
|
*/
|
||||||
|
public ExpressionCreator(TruthTable theTable) {
|
||||||
|
this.theTable = theTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the expressions
|
||||||
|
*
|
||||||
|
* @throws ExpressionException ExpressionException
|
||||||
|
* @throws FormatterException FormatterException
|
||||||
|
*/
|
||||||
|
public void create() throws ExpressionException, FormatterException {
|
||||||
|
ArrayList<Variable> vars = theTable.getVars();
|
||||||
|
for (int table = 0; table < theTable.getResultCount(); table++) {
|
||||||
|
BruteForceGetAll ps = new BruteForceGetAll();
|
||||||
|
Expression e = new QuineMcCluskey(vars)
|
||||||
|
.fillTableWith(theTable.getResult(table))
|
||||||
|
.simplify(ps)
|
||||||
|
.getExpression();
|
||||||
|
|
||||||
|
if (ps.getAllSolutions() != null) {
|
||||||
|
for (ArrayList<TableRow> i : ps.getAllSolutions()) {
|
||||||
|
resultFoundInt(theTable.getResultName(table), QuineMcCluskey.addAnd(null, i, vars));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resultFoundInt(theTable.getResultName(table), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void resultFoundInt(String name, Expression expression) throws FormatterException, ExpressionException {
|
||||||
|
resultFound(name, expression);
|
||||||
|
|
||||||
|
if (name.endsWith("n+1")) {
|
||||||
|
String detName = name.substring(0, name.length() - 2);
|
||||||
|
DetermineJKStateMachine jk = new DetermineJKStateMachine(detName, expression);
|
||||||
|
resultFound("J" + detName, jk.getJ());
|
||||||
|
Expression s = QuineMcCluskey.simplify(jk.getJ());
|
||||||
|
if (s != null) {
|
||||||
|
resultFound("", s);
|
||||||
|
}
|
||||||
|
resultFound("K" + detName, jk.getK());
|
||||||
|
s = QuineMcCluskey.simplify(jk.getK());
|
||||||
|
if (s != null) {
|
||||||
|
resultFound("", s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to overload to handle all found solutions
|
||||||
|
*
|
||||||
|
* @param name the results name
|
||||||
|
* @param expression the calculated expressdion
|
||||||
|
* @throws FormatterException FormatterException
|
||||||
|
* @throws ExpressionException ExpressionException
|
||||||
|
*/
|
||||||
|
public abstract void resultFound(String name, Expression expression) throws FormatterException, ExpressionException;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
package de.neemann.digital.gui.components.table;
|
||||||
|
|
||||||
|
import de.neemann.digital.analyse.TruthTable;
|
||||||
|
import de.neemann.digital.analyse.expression.ContextFiller;
|
||||||
|
import de.neemann.digital.analyse.expression.ExpressionException;
|
||||||
|
import de.neemann.digital.analyse.expression.Variable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to reorder the variables
|
||||||
|
*
|
||||||
|
* @author hneemann
|
||||||
|
*/
|
||||||
|
public class Reorder {
|
||||||
|
|
||||||
|
private final TruthTable table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance
|
||||||
|
*
|
||||||
|
* @param table the table to use
|
||||||
|
*/
|
||||||
|
public Reorder(TruthTable table) {
|
||||||
|
this.table = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reorders the variables
|
||||||
|
*
|
||||||
|
* @param swap the ordering
|
||||||
|
* @return the new table
|
||||||
|
* @throws ExpressionException ExpressionException
|
||||||
|
*/
|
||||||
|
public TruthTable reorder(int[] swap) throws ExpressionException {
|
||||||
|
checkSwapTable(swap);
|
||||||
|
|
||||||
|
ArrayList<Variable> newVars = new ArrayList<>();
|
||||||
|
for (int j = 0; j < table.getVars().size(); j++) {
|
||||||
|
newVars.add(table.getVars().get(swap[j]));
|
||||||
|
}
|
||||||
|
|
||||||
|
TruthTable newTable = new TruthTable(newVars, table);
|
||||||
|
|
||||||
|
ContextFiller fc = new ContextFiller(table.getVars());
|
||||||
|
for (int row = 0; row < table.getRows(); row++) {
|
||||||
|
fc.setContextTo(row);
|
||||||
|
for (int t = 0; t < table.getResultCount(); t++)
|
||||||
|
newTable.setByContext(t, fc, table.getByContext(t, fc));
|
||||||
|
}
|
||||||
|
|
||||||
|
return newTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkSwapTable(int[] swap) {
|
||||||
|
int cols = table.getVars().size();
|
||||||
|
if (swap.length != cols)
|
||||||
|
throw new RuntimeException("wrong swap list length!");
|
||||||
|
|
||||||
|
for (int i = 0; i < cols; i++) {
|
||||||
|
if (swap[i] < 0)
|
||||||
|
throw new RuntimeException("swap index<0");
|
||||||
|
if (swap[i] >= cols)
|
||||||
|
throw new RuntimeException("swap index>" + (table.getCols() - 1));
|
||||||
|
for (int j = 0; j < cols; j++) {
|
||||||
|
if ((i != j) && swap[i] == swap[j])
|
||||||
|
throw new RuntimeException("two times the same swap index " + (swap[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,257 @@
|
|||||||
|
package de.neemann.digital.gui.components.table;
|
||||||
|
|
||||||
|
import de.neemann.digital.analyse.TruthTable;
|
||||||
|
import de.neemann.digital.analyse.TruthTableTableModel;
|
||||||
|
import de.neemann.digital.analyse.expression.Expression;
|
||||||
|
import de.neemann.digital.analyse.expression.ExpressionException;
|
||||||
|
import de.neemann.digital.analyse.expression.format.FormatToExpression;
|
||||||
|
import de.neemann.digital.analyse.expression.format.FormatterException;
|
||||||
|
import de.neemann.gui.ErrorMessage;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.border.MatteBorder;
|
||||||
|
import javax.swing.event.TableModelEvent;
|
||||||
|
import javax.swing.event.TableModelListener;
|
||||||
|
import javax.swing.table.DefaultTableCellRenderer;
|
||||||
|
import javax.swing.table.JTableHeader;
|
||||||
|
import javax.swing.table.TableColumn;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.MouseAdapter;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author hneemann
|
||||||
|
*/
|
||||||
|
public class TableFrame extends JFrame {
|
||||||
|
private static final Color MYGRAY = new Color(230, 230, 230);
|
||||||
|
private final JLabel label;
|
||||||
|
private final JTable table;
|
||||||
|
private final JTableHeader header;
|
||||||
|
private final JTextField text;
|
||||||
|
private final JPopupMenu renamePopup;
|
||||||
|
private final Font font;
|
||||||
|
private final JMenu reorderMenu;
|
||||||
|
private TruthTableTableModel model;
|
||||||
|
private TableColumn column;
|
||||||
|
private int columnIndex;
|
||||||
|
private AllSolutionsFrame allSolutionsFrame;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance
|
||||||
|
*
|
||||||
|
* @param parent the parent frame
|
||||||
|
* @param truthTable the table to show
|
||||||
|
*/
|
||||||
|
public TableFrame(JFrame parent, TruthTable truthTable) {
|
||||||
|
super("Table");
|
||||||
|
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||||
|
|
||||||
|
|
||||||
|
label = new JLabel();
|
||||||
|
font = label.getFont().deriveFont(20.0f);
|
||||||
|
label.setFont(font);
|
||||||
|
table = new JTable(model);
|
||||||
|
JComboBox<String> comboBox = new JComboBox<String>(TruthTableTableModel.STATENAMES);
|
||||||
|
table.setDefaultEditor(Integer.class, new DefaultCellEditor(comboBox));
|
||||||
|
table.setDefaultRenderer(Integer.class, new CenterDefaultTableCellRenderer(true));
|
||||||
|
table.setRowHeight(25);
|
||||||
|
|
||||||
|
allSolutionsFrame = new AllSolutionsFrame(this, font);
|
||||||
|
|
||||||
|
header = table.getTableHeader();
|
||||||
|
header.addMouseListener(new MouseAdapter() {
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(MouseEvent event) {
|
||||||
|
if (event.getClickCount() == 2) {
|
||||||
|
editColumnAt(event.getPoint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
text = new JTextField();
|
||||||
|
text.setBorder(null);
|
||||||
|
text.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
column.setHeaderValue(text.getText());
|
||||||
|
renamePopup.setVisible(false);
|
||||||
|
header.repaint();
|
||||||
|
model.getTable().setColumnName(columnIndex, text.getText());
|
||||||
|
calculateExpressions();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
renamePopup = new JPopupMenu();
|
||||||
|
renamePopup.setBorder(new MatteBorder(0, 1, 1, 1, Color.DARK_GRAY));
|
||||||
|
renamePopup.add(text);
|
||||||
|
|
||||||
|
JMenuBar bar = new JMenuBar();
|
||||||
|
|
||||||
|
JMenu sizeMenu = new JMenu("Size");
|
||||||
|
for (int i = 2; i <= 8; i++)
|
||||||
|
sizeMenu.add(new JMenuItem(new SizeAction(i)));
|
||||||
|
bar.add(sizeMenu);
|
||||||
|
|
||||||
|
reorderMenu = new JMenu("Reorder");
|
||||||
|
bar.add(reorderMenu);
|
||||||
|
|
||||||
|
JMenu colsMenu = new JMenu("Columns");
|
||||||
|
colsMenu.add(new JMenuItem(new AbstractAction("add column") {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent actionEvent) {
|
||||||
|
TruthTable t = model.getTable();
|
||||||
|
t.addResult();
|
||||||
|
setModel(new TruthTableTableModel(t));
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
bar.add(colsMenu);
|
||||||
|
|
||||||
|
setJMenuBar(bar);
|
||||||
|
|
||||||
|
setModel(new TruthTableTableModel(truthTable));
|
||||||
|
|
||||||
|
getContentPane().add(new JScrollPane(table));
|
||||||
|
getContentPane().add(label, BorderLayout.SOUTH);
|
||||||
|
pack();
|
||||||
|
setLocationRelativeTo(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void editColumnAt(Point p) {
|
||||||
|
columnIndex = header.columnAtPoint(p);
|
||||||
|
|
||||||
|
if (columnIndex != -1) {
|
||||||
|
column = header.getColumnModel().getColumn(columnIndex);
|
||||||
|
Rectangle columnRectangle = header.getHeaderRect(columnIndex);
|
||||||
|
|
||||||
|
text.setText(column.getHeaderValue().toString());
|
||||||
|
renamePopup.setPreferredSize(
|
||||||
|
new Dimension(columnRectangle.width, columnRectangle.height - 1));
|
||||||
|
renamePopup.show(header, columnRectangle.x, 0);
|
||||||
|
|
||||||
|
text.requestFocusInWindow();
|
||||||
|
text.selectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setInputVariables(int n) {
|
||||||
|
setModel(new TruthTableTableModel(new TruthTable(n).addResult()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setModel(TruthTableTableModel model) {
|
||||||
|
this.model = model;
|
||||||
|
model.addTableModelListener(new CalculationTableModelListener());
|
||||||
|
table.setModel(model);
|
||||||
|
reorderMenu.removeAll();
|
||||||
|
int cols = model.getTable().getVars().size();
|
||||||
|
reorderMenu.add(new JMenuItem(new ReorderAction(cols)));
|
||||||
|
for (int i = 0; i < cols - 1; i++) {
|
||||||
|
reorderMenu.add(new JMenuItem(new ReorderAction(cols, i)));
|
||||||
|
}
|
||||||
|
calculateExpressions();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class CalculationTableModelListener implements TableModelListener {
|
||||||
|
@Override
|
||||||
|
public void tableChanged(TableModelEvent tableModelEvent) {
|
||||||
|
calculateExpressions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateExpressions() {
|
||||||
|
try {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
new ExpressionCreator(model.getTable()) {
|
||||||
|
private int count = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resultFound(String name, Expression expression) throws FormatterException {
|
||||||
|
String expr = name + "\t=" + FormatToExpression.FORMATTER_UNICODE.format(expression);
|
||||||
|
if (count == 0)
|
||||||
|
label.setText(expr);
|
||||||
|
if (sb.length() > 0) sb.append('\n');
|
||||||
|
sb.append(expr);
|
||||||
|
count++;
|
||||||
|
if (count == 2)
|
||||||
|
allSolutionsFrame.setVisible(true);
|
||||||
|
}
|
||||||
|
}.create();
|
||||||
|
|
||||||
|
if (sb.length() == 0)
|
||||||
|
label.setText("");
|
||||||
|
|
||||||
|
allSolutionsFrame.setText(sb.toString());
|
||||||
|
} catch (ExpressionException | FormatterException e1) {
|
||||||
|
new ErrorMessage("error during calculation").addCause(e1).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class SizeAction extends AbstractAction {
|
||||||
|
|
||||||
|
private int n;
|
||||||
|
|
||||||
|
private SizeAction(int n) {
|
||||||
|
super(n + " Vars");
|
||||||
|
this.n = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent actionEvent) {
|
||||||
|
setInputVariables(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class CenterDefaultTableCellRenderer extends DefaultTableCellRenderer {
|
||||||
|
private final boolean gray;
|
||||||
|
|
||||||
|
private CenterDefaultTableCellRenderer(boolean gray) {
|
||||||
|
this.gray = gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
||||||
|
JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
||||||
|
label.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
|
label.setFont(font);
|
||||||
|
if (gray)
|
||||||
|
label.setBackground(MYGRAY);
|
||||||
|
else
|
||||||
|
label.setBackground(Color.WHITE);
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class ReorderAction extends AbstractAction {
|
||||||
|
|
||||||
|
private final int[] swap;
|
||||||
|
|
||||||
|
private ReorderAction(int cols) {
|
||||||
|
super("reverse");
|
||||||
|
swap = new int[cols];
|
||||||
|
for (int i = 0; i < cols; i++)
|
||||||
|
swap[cols - i - 1] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReorderAction(int cols, int swapIndex) {
|
||||||
|
super("swap " + swapIndex + " and " + (swapIndex + 1));
|
||||||
|
swap = new int[cols];
|
||||||
|
for (int i = 0; i < cols; i++)
|
||||||
|
swap[i] = i;
|
||||||
|
|
||||||
|
int z = swap[swapIndex];
|
||||||
|
swap[swapIndex] = swap[swapIndex + 1];
|
||||||
|
swap[swapIndex + 1] = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent actionEvent) {
|
||||||
|
try {
|
||||||
|
setModel(new TruthTableTableModel(new Reorder(model.getTable()).reorder(swap)));
|
||||||
|
} catch (ExpressionException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Classes to visualize a truth table
|
||||||
|
*
|
||||||
|
* @author hneemann
|
||||||
|
*/
|
||||||
|
package de.neemann.digital.gui.components.table;
|
@ -0,0 +1,76 @@
|
|||||||
|
package de.neemann.digital.analyse;
|
||||||
|
|
||||||
|
|
||||||
|
import de.neemann.digital.analyse.expression.Expression;
|
||||||
|
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.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.v;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author hneemann
|
||||||
|
*/
|
||||||
|
public class DetermineJKStateMachineTest extends TestCase {
|
||||||
|
|
||||||
|
private Expression a;
|
||||||
|
private Expression nota;
|
||||||
|
private Expression b;
|
||||||
|
private Expression notb;
|
||||||
|
private Expression c;
|
||||||
|
private Expression notc;
|
||||||
|
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
a = v("a");
|
||||||
|
nota = not(a);
|
||||||
|
b = v("b");
|
||||||
|
notb = not(b);
|
||||||
|
c = v("c");
|
||||||
|
notc = not(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
|
||||||
|
Expression e = or(and(a, c), and(nota, notb));
|
||||||
|
|
||||||
|
DetermineJKStateMachine jk = new DetermineJKStateMachine("a", e);
|
||||||
|
assertEquals(toStr(notb), toStr(jk.getJ()));
|
||||||
|
assertEquals(toStr(notc), toStr(jk.getK()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toStr(Expression expression) throws FormatterException {
|
||||||
|
return FormatToExpression.FORMATTER_UNICODE.format(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSimple2() throws Exception {
|
||||||
|
|
||||||
|
Expression e = or(and(a, c), and(nota, notb), and(b, c));
|
||||||
|
|
||||||
|
DetermineJKStateMachine jk = new DetermineJKStateMachine("a", e);
|
||||||
|
assertEquals("(b ∧ c) ∨ ¬b", toStr(jk.getJ()));
|
||||||
|
assertEquals("¬((b ∧ c) ∨ c)", toStr(jk.getK()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSimple3() throws Exception {
|
||||||
|
Expression e = or(nota);
|
||||||
|
|
||||||
|
DetermineJKStateMachine jk = new DetermineJKStateMachine("a", e);
|
||||||
|
assertEquals("1", toStr(jk.getJ()));
|
||||||
|
assertEquals("1", toStr(jk.getK()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSimple4() throws Exception {
|
||||||
|
Expression e = or(a);
|
||||||
|
|
||||||
|
DetermineJKStateMachine jk = new DetermineJKStateMachine("a", e);
|
||||||
|
assertEquals("0", toStr(jk.getJ()));
|
||||||
|
assertEquals("0", toStr(jk.getK()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,12 @@
|
|||||||
package de.neemann.digital.analyse;
|
package de.neemann.digital.analyse;
|
||||||
|
|
||||||
|
import de.neemann.digital.analyse.expression.ContextFiller;
|
||||||
|
import de.neemann.digital.analyse.expression.Variable;
|
||||||
|
import de.neemann.digital.analyse.quinemc.BoolTableIntArray;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author hneemann
|
* @author hneemann
|
||||||
*/
|
*/
|
||||||
@ -13,4 +18,18 @@ public class TruthTableTest extends TestCase {
|
|||||||
assertEquals(8, t.getRows());
|
assertEquals(8, t.getRows());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testGetByContext() throws Exception {
|
||||||
|
ArrayList<Variable> vars = Variable.vars(5);
|
||||||
|
TruthTable t = new TruthTable(vars).addResult();
|
||||||
|
BoolTableIntArray result = (BoolTableIntArray) t.getResult(0);
|
||||||
|
for (int i = 0; i < t.getRows(); i++) {
|
||||||
|
result.set(i, i % 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextFiller fc = new ContextFiller(vars);
|
||||||
|
for (int i = 0; i < t.getRows(); i++) {
|
||||||
|
fc.setContextTo(i);
|
||||||
|
assertEquals(i % 3, t.getByContext(0, fc));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package de.neemann.digital.gui.components.table;
|
||||||
|
|
||||||
|
import de.neemann.digital.analyse.TruthTable;
|
||||||
|
import de.neemann.digital.analyse.expression.ContextFiller;
|
||||||
|
import de.neemann.digital.analyse.quinemc.BoolTableIntArray;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author hneemann
|
||||||
|
*/
|
||||||
|
public class ReorderTest extends TestCase {
|
||||||
|
|
||||||
|
public void testReorder() throws Exception {
|
||||||
|
TruthTable t = new TruthTable(5).addResult();
|
||||||
|
BoolTableIntArray col = (BoolTableIntArray) t.getResult(0);
|
||||||
|
for (int i = 0; i < t.getRows(); i++)
|
||||||
|
col.set(i, i + 1);
|
||||||
|
|
||||||
|
|
||||||
|
int[] swap = new int[]{4, 3, 2, 0, 1};
|
||||||
|
TruthTable newTable = new Reorder(t).reorder(swap);
|
||||||
|
|
||||||
|
|
||||||
|
ContextFiller cf = new ContextFiller(t.getVars());
|
||||||
|
for (int i = 0; i < t.getRows(); i++) {
|
||||||
|
cf.setContextTo(i);
|
||||||
|
assertEquals(newTable.getByContext(0, cf), t.getByContext(0, cf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user