mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-19 09:54:49 -04:00
added expressions
This commit is contained in:
parent
b1d1b672a7
commit
5aeb8525a0
@ -0,0 +1,43 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
/**
|
||||
* Used to fill a table.
|
||||
* The first section of input values is set by the {@link BitSetter}
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public abstract class BitSetter {
|
||||
|
||||
private final int bitCount;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param bitCount th number of bits
|
||||
*/
|
||||
public BitSetter(int bitCount) {
|
||||
this.bitCount = bitCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the row value
|
||||
*
|
||||
* @param row the row
|
||||
*/
|
||||
public void fill(int row) {
|
||||
int mask = 1 << (bitCount - 1);
|
||||
for (int bit = 0; bit < bitCount; bit++) {
|
||||
setBit(row, bit, (row & mask) > 0);
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to fill the row
|
||||
*
|
||||
* @param row the row number
|
||||
* @param bit the bit to set, refers to the variable number
|
||||
* @param value the value
|
||||
*/
|
||||
public abstract void setBit(int row, int bit, boolean value);
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
/**
|
||||
* A constant
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public final class Constant implements Expression {
|
||||
private final boolean value;
|
||||
|
||||
/**
|
||||
* The constant true or one
|
||||
*/
|
||||
public static final Constant ONE = new Constant(true);
|
||||
|
||||
/**
|
||||
* The constant false or zero
|
||||
*/
|
||||
public static final Constant ZERO = new Constant(false);
|
||||
|
||||
private Constant(boolean value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean calculate(Context context) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V extends ExpressionVisitor> V traverse(V v) {
|
||||
v.visit(this);
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOrderString() {
|
||||
return Boolean.toString(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retorns the constants value
|
||||
*
|
||||
* @return the value
|
||||
*/
|
||||
public boolean getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
/**
|
||||
* The context used to evaluate an expression
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public interface Context {
|
||||
/**
|
||||
* Returns the value of the given variable
|
||||
*
|
||||
* @param variable the variable
|
||||
* @return the variables value
|
||||
* @throws ExpressionException ExpressionException
|
||||
*/
|
||||
boolean get(Variable variable) throws ExpressionException;
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class ContextFiller extends ContextMap implements Iterable<Variable> {
|
||||
|
||||
private final ArrayList<Variable> vars;
|
||||
private final int rowCount;
|
||||
private final BitSetter bitSetter;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* The needed variables are taken from the expression
|
||||
*
|
||||
* @param expression the expression to extravt the variables
|
||||
*/
|
||||
public ContextFiller(Expression expression) {
|
||||
this(new ArrayList<>(expression.traverse(new VariableVisitor()).getVariables()));
|
||||
Collections.sort(vars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param variables the variables to use
|
||||
*/
|
||||
public ContextFiller(ArrayList<Variable> variables) {
|
||||
vars = variables;
|
||||
rowCount = 1 << vars.size();
|
||||
bitSetter = new BitSetter(vars.size()) {
|
||||
@Override
|
||||
public void setBit(int row, int i, boolean value) {
|
||||
set(vars.get(i), value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Variable> iterator() {
|
||||
return vars.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the variable with the given index
|
||||
*
|
||||
* @param index the index
|
||||
* @return the variable
|
||||
*/
|
||||
public Variable getVar(int index) {
|
||||
return vars.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of variables
|
||||
*/
|
||||
public int getVarCount() {
|
||||
return vars.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of tablerows to describe all variable combinations
|
||||
*/
|
||||
public int getRowCount() {
|
||||
return rowCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the context with the given rows bit value
|
||||
*
|
||||
* @param bitValue the bit value, in most cases the tables row
|
||||
* @return this for call chaining
|
||||
*/
|
||||
public ContextFiller setContextTo(int bitValue) {
|
||||
bitSetter.fill(bitValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the variables to use
|
||||
*/
|
||||
public ArrayList<Variable> getVariables() {
|
||||
return vars;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Simple {@link Context} based on a HashMap
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public class ContextMap implements Context {
|
||||
private HashMap<Variable, Boolean> map;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public ContextMap() {
|
||||
map = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean get(Variable variable) throws ExpressionException {
|
||||
Boolean aBoolean = map.get(variable);
|
||||
if (aBoolean == null)
|
||||
throw new ExpressionException(variable + " not defined");
|
||||
return aBoolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a value
|
||||
*
|
||||
* @param v the variable
|
||||
* @param b the variables value
|
||||
* @return this for call chaining
|
||||
*/
|
||||
public ContextMap set(Variable v, boolean b) {
|
||||
map.put(v, b);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
/**
|
||||
* An expression which can be evaluated to a boolean value
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public interface Expression {
|
||||
|
||||
/**
|
||||
* Evaluates the expression and returns the bool value
|
||||
*
|
||||
* @param context the expressions context
|
||||
* @return the bool value
|
||||
* @throws ExpressionException ExpressionException
|
||||
*/
|
||||
boolean calculate(Context context) throws ExpressionException;
|
||||
|
||||
/**
|
||||
* Traverses the expression
|
||||
*
|
||||
* @param visitor the visitor
|
||||
* @param <V> the visitors type
|
||||
* @return the visitor
|
||||
*/
|
||||
<V extends ExpressionVisitor> V traverse(V visitor);
|
||||
|
||||
/**
|
||||
* String used to order expressions
|
||||
*
|
||||
* @return the ordering string
|
||||
*/
|
||||
String getOrderString();
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
/**
|
||||
* Error thrown during evaluation of an expression
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public class ExpressionException extends Exception {
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param message the message
|
||||
*/
|
||||
public ExpressionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
/**
|
||||
* Visitor used the visit all sub expressions of the expression tree
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public interface ExpressionVisitor {
|
||||
|
||||
/**
|
||||
* if true is returned the visitor goes down the tree.
|
||||
*
|
||||
* @param expression the expression to visit
|
||||
* @return if true operation goes down
|
||||
*/
|
||||
boolean visit(Expression expression);
|
||||
}
|
56
src/main/java/de/neemann/digital/analyse/expression/Not.java
Normal file
56
src/main/java/de/neemann/digital/analyse/expression/Not.java
Normal file
@ -0,0 +1,56 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public final class Not implements Expression {
|
||||
|
||||
private final Expression expression;
|
||||
|
||||
/**
|
||||
* Creates a not expression
|
||||
*
|
||||
* @param a the child expression to invert
|
||||
* @return the inverted expression
|
||||
*/
|
||||
public static Expression not(Expression a) {
|
||||
if (a == Constant.ONE)
|
||||
return Constant.ZERO;
|
||||
if (a == Constant.ZERO)
|
||||
return Constant.ONE;
|
||||
|
||||
if (a instanceof Not) {
|
||||
return ((Not) a).expression;
|
||||
} else
|
||||
return new Not(a);
|
||||
}
|
||||
|
||||
private Not(Expression expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean calculate(Context context) throws ExpressionException {
|
||||
return !expression.calculate(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V extends ExpressionVisitor> V traverse(V v) {
|
||||
if (v.visit(this)) {
|
||||
expression.traverse(v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOrderString() {
|
||||
return expression.getOrderString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the negated expression
|
||||
*/
|
||||
public Expression getExpression() {
|
||||
return expression;
|
||||
}
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* A operation
|
||||
* There are only two implementations: The AND and the OR operation
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public abstract class Operation implements Expression {
|
||||
private static final Comparator<Expression> EXPRESSION_COMPARATOR
|
||||
= (a, b) -> a.getOrderString().compareTo(b.getOrderString());
|
||||
|
||||
private final ArrayList<Expression> expr;
|
||||
|
||||
/**
|
||||
* Creates a new OR expression
|
||||
*
|
||||
* @param exp the expressions to OR
|
||||
* @return the created expression
|
||||
*/
|
||||
public static Expression or(Iterable<Expression> exp) {
|
||||
return simplify(new Or(exp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new OR expression
|
||||
*
|
||||
* @param exp the expressions to OR
|
||||
* @return the created expression
|
||||
*/
|
||||
public static Expression or(Expression... exp) {
|
||||
return simplify(new Or(Arrays.asList(exp)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AND expression
|
||||
*
|
||||
* @param exp the expressions to AND
|
||||
* @return the created expression
|
||||
*/
|
||||
public static Expression and(Iterable<Expression> exp) {
|
||||
return simplify(new And(exp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AND expression
|
||||
*
|
||||
* @param exp the expressions to AND
|
||||
* @return the created expression
|
||||
*/
|
||||
public static Expression and(Expression... exp) {
|
||||
return simplify(new And(Arrays.asList(exp)));
|
||||
}
|
||||
|
||||
private static Expression simplify(Operation operation) {
|
||||
int size = operation.getExpressions().size();
|
||||
switch (size) {
|
||||
case 0:
|
||||
return null;
|
||||
case 1:
|
||||
return operation.getExpressions().get(0);
|
||||
default:
|
||||
Collections.sort(operation.getExpressions(), EXPRESSION_COMPARATOR);
|
||||
return operation;
|
||||
}
|
||||
}
|
||||
|
||||
private Operation(Iterable<Expression> exp) {
|
||||
expr = new ArrayList<>();
|
||||
for (Expression e : exp)
|
||||
if (e != null)
|
||||
merge(e);
|
||||
}
|
||||
|
||||
private void merge(Expression e) {
|
||||
if (e.getClass() == getClass()) {
|
||||
expr.addAll(((Operation) e).getExpressions());
|
||||
} else
|
||||
expr.add(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean calculate(Context context) throws ExpressionException {
|
||||
boolean result = getNeutral();
|
||||
for (Expression e : expr)
|
||||
result = calc(result, e.calculate(context));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V extends ExpressionVisitor> V traverse(V v) {
|
||||
if (v.visit(this)) {
|
||||
for (Expression e : expr)
|
||||
e.traverse(v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the sub expressions
|
||||
*/
|
||||
public ArrayList<Expression> getExpressions() {
|
||||
return expr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOrderString() {
|
||||
return expr.get(0).getOrderString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the neutral element of this operation
|
||||
*/
|
||||
protected abstract boolean getNeutral();
|
||||
|
||||
/**
|
||||
* Performs the calculation
|
||||
*
|
||||
* @param a value a
|
||||
* @param b value b
|
||||
* @return result
|
||||
*/
|
||||
protected abstract boolean calc(boolean a, boolean b);
|
||||
|
||||
/**
|
||||
* The AND expression
|
||||
*/
|
||||
public static final class And extends Operation {
|
||||
|
||||
private And(Iterable<Expression> exp) {
|
||||
super(exp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean getNeutral() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean calc(boolean a, boolean b) {
|
||||
return a && b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The OR expression
|
||||
*/
|
||||
public static final class Or extends Operation {
|
||||
|
||||
private Or(Iterable<Expression> exp) {
|
||||
super(exp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean getNeutral() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean calc(boolean a, boolean b) {
|
||||
return a || b;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class Variable implements Comparable<Variable>, Expression {
|
||||
|
||||
private String identifier;
|
||||
|
||||
public static Variable v(String name) {
|
||||
return new Variable(name);
|
||||
}
|
||||
|
||||
public static ArrayList<Variable> vars(int n) {
|
||||
ArrayList<Variable> v = new ArrayList<Variable>();
|
||||
for (int i = 0; i < n; i++)
|
||||
v.add(new Variable("" + (char) ('A' + i)));
|
||||
return v;
|
||||
}
|
||||
|
||||
public static ArrayList<Variable> vars(String... names) {
|
||||
ArrayList<Variable> v = new ArrayList<Variable>();
|
||||
for (String n : names)
|
||||
v.add(new Variable(n));
|
||||
return v;
|
||||
}
|
||||
|
||||
public Variable(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public boolean calculate(Context context) throws ExpressionException {
|
||||
return context.get(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V extends ExpressionVisitor> V traverse(V v) {
|
||||
v.visit(this);
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOrderString() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Variable that = (Variable) o;
|
||||
|
||||
return identifier.equals(that.identifier);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return identifier.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Variable o) {
|
||||
return identifier.compareTo(o.identifier);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* Visitor to collect all used variables in an expression
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public class VariableVisitor implements ExpressionVisitor {
|
||||
|
||||
private final HashSet<Variable> variables;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
public VariableVisitor() {
|
||||
variables = new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(Expression expression) {
|
||||
if (expression instanceof Variable) {
|
||||
variables.add((Variable) expression);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rerurns all used variables
|
||||
*
|
||||
* @return used variables
|
||||
*/
|
||||
public Collection<Variable> getVariables() {
|
||||
return variables;
|
||||
}
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
package de.neemann.digital.analyse.expression.format;
|
||||
|
||||
import de.neemann.digital.analyse.expression.*;
|
||||
|
||||
/**
|
||||
* Used to format an expression to a simple string
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public class FormatToExpression implements Formatter {
|
||||
|
||||
/**
|
||||
* Creates a string compatible to Java
|
||||
*/
|
||||
public static final FormatToExpression FORMATTER_JAVA = new FormatToExpression("||", "&&", "!", "false", "true");
|
||||
/**
|
||||
* Creates a string compatible to Derive
|
||||
*/
|
||||
public static final FormatToExpression FORMATTER_DERIVE = new FormatToExpression("OR", "AND", "NOT ", "false", "true");
|
||||
/**
|
||||
* Creates a string compatible to Logisim
|
||||
*/
|
||||
public static final FormatToExpression FORMATTER_LOGISIM = new FormatToExpression("+", "", "~", "false", "true");
|
||||
/**
|
||||
* Creates a unicode string
|
||||
*/
|
||||
public static final FormatToExpression FORMATTER_UNICODE = new FormatToExpression("\u2228", "\u2227", "\u00AC", "0", "1");
|
||||
/**
|
||||
* Creates a LaTeX representation
|
||||
*/
|
||||
public static final FormatToExpression FORMATTER_LATEX = new FormatterLatex();
|
||||
|
||||
private final String orString;
|
||||
private final String andString;
|
||||
private final String falseString;
|
||||
private final String trueString;
|
||||
private final String notString;
|
||||
|
||||
private FormatToExpression(String orString, String andString, String notString, String falseString, String trueString) {
|
||||
this.orString = orString;
|
||||
this.andString = andString;
|
||||
this.notString = notString;
|
||||
this.falseString = falseString;
|
||||
this.trueString = trueString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(String name, Expression expression) throws FormatterException {
|
||||
return identifier(name) + "=" + format(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given expression
|
||||
*
|
||||
* @param expression the expression
|
||||
* @return the formated string
|
||||
* @throws FormatterException FormatterException
|
||||
*/
|
||||
public String format(Expression expression) throws FormatterException {
|
||||
if (expression instanceof Variable) {
|
||||
return identifier(((Variable) expression).getIdentifier());
|
||||
} else if (expression instanceof Constant) {
|
||||
return constant(((Constant) expression).getValue());
|
||||
} else if (expression instanceof Not) {
|
||||
return formatNot((Not) expression);
|
||||
} else if (expression instanceof Operation.And) {
|
||||
return formatAnd((Operation.And) expression);
|
||||
} else if (expression instanceof Operation.Or) {
|
||||
return formatOr((Operation.Or) expression);
|
||||
} else throw new FormatterException("unknown type " + expression.getClass().getSimpleName());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a not expression
|
||||
*
|
||||
* @param expression the nor expression
|
||||
* @return the formatted string
|
||||
* @throws FormatterException FormatterException
|
||||
*/
|
||||
public String formatNot(Not expression) throws FormatterException {
|
||||
if (expression.getExpression() instanceof Operation)
|
||||
return notString + "(" + format(expression.getExpression()) + ")";
|
||||
else
|
||||
return notString + format(expression.getExpression());
|
||||
}
|
||||
|
||||
private String formatAnd(Operation.And expression) throws FormatterException {
|
||||
return formatOp(expression.getExpressions(), andString);
|
||||
}
|
||||
|
||||
private String formatOr(Operation.Or expression) throws FormatterException {
|
||||
return formatOp(expression.getExpressions(), orString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an operation
|
||||
*
|
||||
* @param expressions the expressions
|
||||
* @param opString the string representation of the operation
|
||||
* @return the formated string
|
||||
* @throws FormatterException FormatterException
|
||||
*/
|
||||
public String formatOp(Iterable<Expression> expressions, String opString) throws FormatterException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Expression e : expressions) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(" ").append(opString).append(" ");
|
||||
}
|
||||
if (e instanceof Operation)
|
||||
sb.append("(").append(format(e)).append(")");
|
||||
else
|
||||
sb.append(format(e));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given constant
|
||||
*
|
||||
* @param value th constant
|
||||
* @return the string representation
|
||||
*/
|
||||
public String constant(boolean value) {
|
||||
if (value) return trueString;
|
||||
else return falseString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given identifier
|
||||
*
|
||||
* @param identifier the identifier
|
||||
* @return the string representation of the identifier
|
||||
*/
|
||||
public String identifier(String identifier) {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
private static class FormatterLatex extends FormatToExpression {
|
||||
FormatterLatex() {
|
||||
super("\\oder", "\\und", null, "0", "1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatNot(Not expression) throws FormatterException {
|
||||
return "\\nicht{" + format(expression.getExpression()) + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String identifier(String identifier) {
|
||||
return FormatToTableLatex.formatIdentifier(identifier);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package de.neemann.digital.analyse.expression.format;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Creates a table representation of the given expression
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public class FormatToTable implements Formatter {
|
||||
|
||||
@Override
|
||||
public String format(String name, Expression expression) throws FormatterException, ExpressionException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
ContextFiller cf = new ContextFiller(expression);
|
||||
formatHead(sb, cf.getVarCount());
|
||||
for (Variable v : cf)
|
||||
sb.append(formatVariable(v));
|
||||
sb.append(formatResultVariable());
|
||||
sb.append("\n");
|
||||
formatTableStart(sb);
|
||||
|
||||
for (int i = 0; i < cf.getRowCount(); i++) {
|
||||
cf.setContextTo(i);
|
||||
for (Variable v : cf)
|
||||
sb.append(formatValue(cf.get(v)));
|
||||
sb.append(formatResult(expression.calculate(cf)));
|
||||
sb.append("\n");
|
||||
}
|
||||
formatEnd(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the table head
|
||||
*
|
||||
* @param sb the string builder to add the text to
|
||||
* @param varCount the number of variables
|
||||
*/
|
||||
protected void formatHead(StringBuilder sb, int varCount) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the table start
|
||||
*
|
||||
* @param sb the string builder to add the text to
|
||||
*/
|
||||
protected void formatTableStart(StringBuilder sb) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the table end
|
||||
*
|
||||
* @param sb the string builder to add the text to
|
||||
*/
|
||||
protected void formatEnd(StringBuilder sb) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a variable
|
||||
*
|
||||
* @param v the variable
|
||||
* @return the formatted text
|
||||
*/
|
||||
protected String formatVariable(Variable v) {
|
||||
return v.getIdentifier();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* formats the result variable
|
||||
*
|
||||
* @return the formatted text
|
||||
*/
|
||||
protected String formatResultVariable() {
|
||||
return "|Y";
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a result value
|
||||
*
|
||||
* @param value the value to format
|
||||
* @return the formatted text
|
||||
*/
|
||||
protected String formatResult(boolean value) {
|
||||
return "|" + formatValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a value
|
||||
*
|
||||
* @param val the value
|
||||
* @return the formatted text
|
||||
*/
|
||||
protected String formatValue(boolean val) {
|
||||
if (val) return "1";
|
||||
else return "0";
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package de.neemann.digital.analyse.expression.format;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.expression.Variable;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class FormatToTableLatex extends FormatToTable {
|
||||
|
||||
@Override
|
||||
protected void formatHead(StringBuilder sb, int varCount) {
|
||||
sb.append("\\begin{tabular}{");
|
||||
for (int i = 0; i < varCount; i++)
|
||||
sb.append("c");
|
||||
sb.append("|c}\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String formatVariable(Variable v) {
|
||||
return "$" + formatIdentifier(super.formatVariable(v)) + "$&";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String formatResultVariable() {
|
||||
return "$Y$\\\\";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void formatTableStart(StringBuilder sb) {
|
||||
sb.append("\\hline\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String formatValue(boolean val) {
|
||||
return super.formatValue(val) + "&";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String formatResult(boolean value) {
|
||||
return super.formatValue(value) + "\\\\";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void formatEnd(StringBuilder sb) {
|
||||
sb.append("\\end{tabular}\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given identifier
|
||||
*
|
||||
* @param identifier the identifier
|
||||
* @return the formatted text
|
||||
*/
|
||||
protected static String formatIdentifier(String identifier) {
|
||||
if (identifier.length() <= 1)
|
||||
return identifier;
|
||||
else
|
||||
return identifier.charAt(0) + "_{" + identifier.substring(1) + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package de.neemann.digital.analyse.expression.format;
|
||||
|
||||
|
||||
import de.neemann.digital.analyse.expression.Expression;
|
||||
import de.neemann.digital.analyse.expression.ExpressionException;
|
||||
|
||||
/**
|
||||
* Used to format an expression
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public interface Formatter {
|
||||
|
||||
/**
|
||||
* Formats an expression
|
||||
*
|
||||
* @param name name of the expression
|
||||
* @param expression the expression
|
||||
* @return the formated expression
|
||||
* @throws FormatterException FormatterException
|
||||
* @throws ExpressionException ExpressionException
|
||||
*/
|
||||
String format(String name, Expression expression) throws FormatterException, ExpressionException;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package de.neemann.digital.analyse.expression.format;
|
||||
|
||||
/**
|
||||
* Error thrown if there is an formatting error
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public class FormatterException extends Throwable {
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param message the error message
|
||||
*/
|
||||
public FormatterException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Classes used to format an expression
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
package de.neemann.digital.analyse.expression.format;
|
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Used to describe an expression which can be evaluated to a boolean value
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
package de.neemann.digital.analyse.expression;
|
@ -0,0 +1,63 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class ExpressionTest extends TestCase {
|
||||
|
||||
public void testCalculate() throws Exception {
|
||||
Variable a = new Variable("A");
|
||||
Variable b = new Variable("B");
|
||||
Expression e = and(not(or(not(a), not(b))), not(and(not(a), not(b))));
|
||||
|
||||
ContextFiller fc = new ContextFiller(e);
|
||||
assertEquals(false, e.calculate(fc.setContextTo(0)));
|
||||
assertEquals(false, e.calculate(fc.setContextTo(1)));
|
||||
assertEquals(false, e.calculate(fc.setContextTo(2)));
|
||||
assertEquals(true, e.calculate(fc.setContextTo(3)));
|
||||
}
|
||||
|
||||
/**
|
||||
* public void test2() throws FormatterException, ExpressionException {
|
||||
* Variable a = new Variable("A");// Vorlesung
|
||||
* Variable b = new Variable("B");
|
||||
* Variable c = new Variable("C");
|
||||
* Variable d = new Variable("D");
|
||||
* <p>
|
||||
* Expression e = or(and(a, and(c, d)), or(and(not(c), not(d)), and(not(b), c)));
|
||||
* String out = FormatToExpression.FORMATTER_LATEX.format(e);
|
||||
* assertEquals("(A \\und C \\und D) \\oder (\\nicht{B} \\und C) \\oder (\\nicht{C} \\und \\nicht{D})", out);
|
||||
* <p>
|
||||
* ContextFiller fc = new ContextFiller(e);
|
||||
* <p>
|
||||
* int[] vector = new int[]{1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1};
|
||||
* for (int i = 0; i < vector.length; i++)
|
||||
* assertEquals(vector[i] == 1, e.calculate(fc.setContextTo(i)));
|
||||
* }
|
||||
*/
|
||||
|
||||
public void testConstant() throws ExpressionException {
|
||||
Variable a = new Variable("A");
|
||||
Expression e = or(a, Constant.ONE);
|
||||
|
||||
ContextMap c = new ContextMap();
|
||||
assertTrue(e.calculate(c.set(a, true)));
|
||||
assertTrue(e.calculate(c.set(a, false)));
|
||||
|
||||
e = and(a, Constant.ONE);
|
||||
assertTrue(e.calculate(c.set(a, true)));
|
||||
assertFalse(e.calculate(c.set(a, false)));
|
||||
|
||||
e = or(a, Constant.ZERO);
|
||||
assertTrue(e.calculate(c.set(a, true)));
|
||||
assertFalse(e.calculate(c.set(a, false)));
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import static de.neemann.digital.analyse.expression.Not.not;
|
||||
import static de.neemann.digital.analyse.expression.Variable.v;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class NotTest extends TestCase {
|
||||
|
||||
public void testNot() throws Exception {
|
||||
assertEquals(Constant.ONE, not(Constant.ZERO));
|
||||
assertEquals(Constant.ZERO, not(Constant.ONE));
|
||||
|
||||
Variable a = v("a");
|
||||
assertEquals(a, not(not(a)));
|
||||
|
||||
//assertEquals("¬a", not(a).toString());
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
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 OperationTest extends TestCase {
|
||||
|
||||
public void testOr() throws Exception {
|
||||
Variable a = v("a");
|
||||
Variable b = v("b");
|
||||
Variable c = v("c");
|
||||
|
||||
Expression i = or(a);
|
||||
assertTrue(i instanceof Variable);
|
||||
i = or(a, b);
|
||||
assertTrue(i instanceof Operation.Or);
|
||||
assertEquals(2, ((Operation.Or) i).getExpressions().size());
|
||||
i = or(c, i);
|
||||
assertEquals(3, ((Operation.Or) i).getExpressions().size());
|
||||
|
||||
i = or(and(a, b), c);
|
||||
assertTrue(i instanceof Operation.Or);
|
||||
assertEquals(2, ((Operation.Or) i).getExpressions().size());
|
||||
|
||||
i = or(not(a));
|
||||
assertTrue(i instanceof Not);
|
||||
}
|
||||
|
||||
public void testAnd() throws Exception {
|
||||
Variable a = v("a");
|
||||
Variable b = v("b");
|
||||
Variable c = v("c");
|
||||
|
||||
assertTrue(and(a) instanceof Variable);
|
||||
Expression i = and(a, b);
|
||||
assertTrue(i instanceof Operation.And);
|
||||
assertEquals(2, ((Operation.And) i).getExpressions().size());
|
||||
i = and(c, i);
|
||||
assertEquals(3, ((Operation.And) i).getExpressions().size());
|
||||
|
||||
i = and(or(a, b), c);
|
||||
assertTrue(i instanceof Operation.And);
|
||||
assertEquals(2, ((Operation.And) i).getExpressions().size());
|
||||
|
||||
i = and(not(a));
|
||||
assertTrue(i instanceof Not);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package de.neemann.digital.analyse.expression;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static de.neemann.digital.analyse.expression.Variable.vars;
|
||||
|
||||
/**
|
||||
* @author hneemann
|
||||
*/
|
||||
public class VariableTest extends TestCase {
|
||||
|
||||
public void testVars() throws Exception {
|
||||
ArrayList<Variable> v = vars(5);
|
||||
assertEquals(5, v.size());
|
||||
assertEquals("A", v.get(0).getIdentifier());
|
||||
assertEquals("B", v.get(1).getIdentifier());
|
||||
assertEquals("C", v.get(2).getIdentifier());
|
||||
assertEquals("D", v.get(3).getIdentifier());
|
||||
assertEquals("E", v.get(4).getIdentifier());
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package de.neemann.digital.analyse.expression.format;
|
||||
|
||||
|
||||
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.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 FormatterTest extends TestCase {
|
||||
|
||||
public void testFormatExp() throws Exception, FormatterException {
|
||||
Variable a = v("A");
|
||||
Variable b = v("B");
|
||||
Expression e = and(not(or(not(a), not(b))), not(and(not(a), not(b))));
|
||||
|
||||
assertEquals("!(!A || !B) && !(!A && !B)", FormatToExpression.FORMATTER_JAVA.format(e));
|
||||
assertEquals("\\nicht{\\nicht{A} \\oder \\nicht{B}} \\und \\nicht{\\nicht{A} \\und \\nicht{B}}", FormatToExpression.FORMATTER_LATEX.format(e));
|
||||
assertEquals("NOT (NOT A OR NOT B) AND NOT (NOT A AND NOT B)", FormatToExpression.FORMATTER_DERIVE.format(e));
|
||||
assertEquals("~(~A + ~B) ~(~A ~B)", FormatToExpression.FORMATTER_LOGISIM.format(e));
|
||||
assertEquals("¬(¬A ∨ ¬B) ∧ ¬(¬A ∧ ¬B)", FormatToExpression.FORMATTER_UNICODE.format(e));
|
||||
}
|
||||
|
||||
public void testFormatExpNot() throws Exception, FormatterException {
|
||||
Variable a = new Variable("A");
|
||||
Expression e = not(a);
|
||||
|
||||
assertEquals("¬A", FormatToExpression.FORMATTER_UNICODE.format(e));
|
||||
}
|
||||
|
||||
public void testFormatExpNot2() throws Exception, FormatterException {
|
||||
Variable a = v("A");
|
||||
Variable b = v("B");
|
||||
Variable c = v("C");
|
||||
Expression e = or(and(a, b), not(c));
|
||||
|
||||
assertEquals("(A ∧ B) ∨ ¬C", FormatToExpression.FORMATTER_UNICODE.format(e));
|
||||
}
|
||||
|
||||
|
||||
public void testFormatExpLaTeX() throws Exception, FormatterException {
|
||||
Variable a = new Variable("An");
|
||||
Variable b = new Variable("Bn");
|
||||
Expression e = and(a, not(b));
|
||||
assertEquals("Y_{n+1}=A_{n} \\und \\nicht{B_{n}}", FormatToExpression.FORMATTER_LATEX.format("Yn+1", e));
|
||||
}
|
||||
|
||||
|
||||
public void testFormatTable() throws Exception, FormatterException {
|
||||
Variable a = new Variable("A");
|
||||
Variable b = new Variable("B");
|
||||
Expression e = and(not(or(not(a), not(b))), not(and(not(a), not(b))));
|
||||
|
||||
assertEquals("AB|Y\n" +
|
||||
"00|0\n" +
|
||||
"01|0\n" +
|
||||
"10|0\n" +
|
||||
"11|1\n", new FormatToTable().format("", e));
|
||||
|
||||
}
|
||||
|
||||
public void testFormatLatex() throws Exception, FormatterException {
|
||||
Variable a = new Variable("A");
|
||||
Variable b = new Variable("B");
|
||||
Expression e = and(not(or(not(a), not(b))), not(and(not(a), not(b))));
|
||||
|
||||
assertEquals("\\begin{tabular}{cc|c}\n" +
|
||||
"$A$&$B$&$Y$\\\\\n" +
|
||||
"\\hline\n" +
|
||||
"0&0&0\\\\\n" +
|
||||
"0&1&0\\\\\n" +
|
||||
"1&0&0\\\\\n" +
|
||||
"1&1&1\\\\\n" +
|
||||
"\\end{tabular}\n", new FormatToTableLatex().format("", e));
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user