diff --git a/src/main/java/de/neemann/digital/analyse/expression/Constant.java b/src/main/java/de/neemann/digital/analyse/expression/Constant.java index d3079dc8a..dc1a1684a 100644 --- a/src/main/java/de/neemann/digital/analyse/expression/Constant.java +++ b/src/main/java/de/neemann/digital/analyse/expression/Constant.java @@ -51,4 +51,9 @@ public final class Constant implements Expression { public String toString() { return Boolean.toString(value); } + + @Override + public Expression copy() { + return new Constant(value); + } } diff --git a/src/main/java/de/neemann/digital/analyse/expression/Expression.java b/src/main/java/de/neemann/digital/analyse/expression/Expression.java index 76bc9eed1..941d95f8c 100644 --- a/src/main/java/de/neemann/digital/analyse/expression/Expression.java +++ b/src/main/java/de/neemann/digital/analyse/expression/Expression.java @@ -43,4 +43,9 @@ public interface Expression { * @return the ordering string */ String getOrderString(); + + /** + * @return a deep copy of this expression + */ + Expression copy(); } diff --git a/src/main/java/de/neemann/digital/analyse/expression/NamedExpression.java b/src/main/java/de/neemann/digital/analyse/expression/NamedExpression.java index e63b909c2..c889ce624 100644 --- a/src/main/java/de/neemann/digital/analyse/expression/NamedExpression.java +++ b/src/main/java/de/neemann/digital/analyse/expression/NamedExpression.java @@ -49,6 +49,11 @@ public class NamedExpression implements Expression { return exp.getOrderString(); } + @Override + public Expression copy() { + return new NamedExpression(name, exp.copy()); + } + @Override public String toString() { return name+"="+exp.toString(); diff --git a/src/main/java/de/neemann/digital/analyse/expression/Not.java b/src/main/java/de/neemann/digital/analyse/expression/Not.java index 7a11b2ea5..d4e016a66 100644 --- a/src/main/java/de/neemann/digital/analyse/expression/Not.java +++ b/src/main/java/de/neemann/digital/analyse/expression/Not.java @@ -82,6 +82,11 @@ public final class Not implements Expression { return expression.getOrderString(); } + @Override + public Expression copy() { + return new Not(expression.copy()); + } + /** * @return the negated expression */ diff --git a/src/main/java/de/neemann/digital/analyse/expression/Operation.java b/src/main/java/de/neemann/digital/analyse/expression/Operation.java index 88f82521b..073e0c315 100644 --- a/src/main/java/de/neemann/digital/analyse/expression/Operation.java +++ b/src/main/java/de/neemann/digital/analyse/expression/Operation.java @@ -4,7 +4,6 @@ import de.neemann.digital.analyse.expression.modify.ExpressionModifier; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Comparator; /** @@ -15,7 +14,7 @@ import java.util.Comparator; */ public abstract class Operation implements Expression { private static final Comparator EXPRESSION_COMPARATOR - = (a, b) -> a.getOrderString().compareTo(b.getOrderString()); + = Comparator.comparing(Expression::getOrderString); private final ArrayList expr; @@ -99,7 +98,7 @@ public abstract class Operation implements Expression { case 1: return operation.getExpressions().get(0); default: - Collections.sort(operation.getExpressions(), EXPRESSION_COMPARATOR); + operation.getExpressions().sort(EXPRESSION_COMPARATOR); return operation; } } @@ -114,6 +113,13 @@ public abstract class Operation implements Expression { expr.add(e); } + private Operation(Iterable expToCopy) { + expr = new ArrayList<>(); + for (Expression e : expToCopy) + if (e != null) + expr.add(e.copy()); + } + private void merge(Expression e) { if (e.getClass() == getClass()) { expr.addAll(((Operation) e).getExpressions()); @@ -194,6 +200,10 @@ public abstract class Operation implements Expression { super(exp, merge); } + private And(Iterable expToCopy) { + super(expToCopy); + } + @Override protected boolean getNeutral() { return true; @@ -208,6 +218,11 @@ public abstract class Operation implements Expression { public String toString() { return "and" + super.toString(); } + + @Override + public Expression copy() { + return new And(getExpressions()); + } } /** @@ -219,6 +234,10 @@ public abstract class Operation implements Expression { super(exp, merge); } + private Or(Iterable expToCopy) { + super(expToCopy); + } + @Override protected boolean getNeutral() { return false; @@ -233,6 +252,11 @@ public abstract class Operation implements Expression { public String toString() { return "or" + super.toString(); } + + @Override + public Expression copy() { + return new Or(getExpressions()); + } } /** @@ -244,6 +268,10 @@ public abstract class Operation implements Expression { super(Arrays.asList(a, b), false); } + private XOr(Iterable expToCopy) { + super(expToCopy); + } + @Override protected boolean getNeutral() { return false; @@ -258,6 +286,11 @@ public abstract class Operation implements Expression { public String toString() { return "xor" + super.toString(); } + + @Override + public Expression copy() { + return new XOr(getExpressions()); + } } } diff --git a/src/main/java/de/neemann/digital/analyse/expression/Variable.java b/src/main/java/de/neemann/digital/analyse/expression/Variable.java index 394d393ce..eecb6840c 100644 --- a/src/main/java/de/neemann/digital/analyse/expression/Variable.java +++ b/src/main/java/de/neemann/digital/analyse/expression/Variable.java @@ -70,6 +70,11 @@ public class Variable implements Comparable, Expression { return identifier; } + @Override + public Expression copy() { + return new Variable(identifier); + } + /** * @return the variables name */ diff --git a/src/main/java/de/neemann/digital/gui/components/table/BuilderExpressionCreator.java b/src/main/java/de/neemann/digital/gui/components/table/BuilderExpressionCreator.java new file mode 100644 index 000000000..dd28a549b --- /dev/null +++ b/src/main/java/de/neemann/digital/gui/components/table/BuilderExpressionCreator.java @@ -0,0 +1,85 @@ +package de.neemann.digital.gui.components.table; + +import de.neemann.digital.analyse.expression.Expression; +import de.neemann.digital.analyse.expression.ExpressionException; +import de.neemann.digital.analyse.expression.format.FormatterException; +import de.neemann.digital.analyse.expression.modify.ExpressionModifier; +import de.neemann.digital.builder.BuilderException; +import de.neemann.digital.builder.BuilderInterface; +import de.neemann.digital.lang.Lang; + +import java.util.HashSet; + +/** + * Helper to fill the a {@link BuilderInterface} with pre calculated expressions + * stored in {@link ExpressionListenerStore} instance. + *

+ * Created by hneemann on 02.04.17. + */ +public class BuilderExpressionCreator { + private final HashSet contained; + private final BuilderInterface builder; + private final ExpressionModifier[] modifier; + private boolean useJKOptimizer = false; + + /** + * Create a new instance + * + * @param builder the builder + * @param modifier the modifier tp modify the expression + */ + public BuilderExpressionCreator(BuilderInterface builder, ExpressionModifier... modifier) { + contained = new HashSet<>(); + this.builder = builder; + this.modifier = modifier; + } + + /** + * Fills the builder + * + * @param expressions the expressions to use + * @throws ExpressionException ExpressionException + * @throws FormatterException FormatterException + */ + public void create(ExpressionListenerStore expressions) throws ExpressionException, FormatterException { + if (expressions == null) + throw new ExpressionException(Lang.get("err_noExpressionsAvailable")); + + ExpressionListener el = new ExpressionListener() { + @Override + public void resultFound(String name, Expression expression) throws FormatterException, ExpressionException { + if (!contained.contains(name)) { + contained.add(name); + try { + if (name.endsWith("n+1")) { + name = name.substring(0, name.length() - 2); + builder.addSequential(name, ExpressionModifier.modifyExpression(expression, modifier)); + } else + builder.addCombinatorial(name, ExpressionModifier.modifyExpression(expression, modifier)); + } catch (BuilderException e) { + throw new RuntimeException(e); + } + } + } + + @Override + public void close() { + } + }; + if (useJKOptimizer) + el = new ExpressionListenerOptimizeJK(el); + + expressions.replayTo(el); + } + + /** + * Enables the usage of JK-Flipflops instead of D-Flipflops + * + * @param useJKOptimizer true if use JK flipflops + * @return this for chained calls + */ + public BuilderExpressionCreator setUseJKOptimizer(boolean useJKOptimizer) { + this.useJKOptimizer = useJKOptimizer; + return this; + } +} diff --git a/src/main/java/de/neemann/digital/gui/components/table/ExpressionListenerStore.java b/src/main/java/de/neemann/digital/gui/components/table/ExpressionListenerStore.java index b02cf6137..48a3c92ab 100644 --- a/src/main/java/de/neemann/digital/gui/components/table/ExpressionListenerStore.java +++ b/src/main/java/de/neemann/digital/gui/components/table/ExpressionListenerStore.java @@ -54,7 +54,7 @@ public class ExpressionListenerStore implements ExpressionListener { throw new ExpressionException("ExpressionListenerStore not closed"); for (Result r : results) - listener.resultFound(r.name, r.expression); + listener.resultFound(r.name, r.expression.copy()); listener.close(); } @@ -62,7 +62,7 @@ public class ExpressionListenerStore implements ExpressionListener { * @return the first found expression */ public Expression getFirst() { - return results.get(0).expression; + return results.get(0).expression.copy(); } private static final class Result { diff --git a/src/main/java/de/neemann/digital/gui/components/table/TableDialog.java b/src/main/java/de/neemann/digital/gui/components/table/TableDialog.java index 0b31de8b8..fc3570185 100644 --- a/src/main/java/de/neemann/digital/gui/components/table/TableDialog.java +++ b/src/main/java/de/neemann/digital/gui/components/table/TableDialog.java @@ -16,8 +16,6 @@ import de.neemann.digital.analyse.expression.modify.TwoInputs; import de.neemann.digital.analyse.format.TruthTableFormatterLaTeX; import de.neemann.digital.analyse.quinemc.BoolTableByteArray; import de.neemann.digital.builder.ATF1502.*; -import de.neemann.digital.builder.BuilderException; -import de.neemann.digital.builder.BuilderInterface; import de.neemann.digital.builder.ExpressionToFileExporter; import de.neemann.digital.builder.Gal16v8.CuplExporter; import de.neemann.digital.builder.Gal16v8.Gal16v8JEDECExporter; @@ -55,7 +53,6 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.TreeMap; @@ -660,55 +657,6 @@ public class TableDialog extends JDialog { } } - private static class BuilderExpressionCreator { - private final HashSet contained; - private final BuilderInterface builder; - private final ExpressionModifier[] modifier; - private boolean useJKOptimizer = false; - - BuilderExpressionCreator(BuilderInterface builder, ExpressionModifier... modifier) { - contained = new HashSet<>(); - this.builder = builder; - this.modifier = modifier; - } - - public void create(ExpressionListenerStore expressions) throws ExpressionException, FormatterException { - if (expressions == null) - throw new ExpressionException(Lang.get("err_noExpressionsAvailable")); - - ExpressionListener el = new ExpressionListener() { - @Override - public void resultFound(String name, Expression expression) throws FormatterException, ExpressionException { - if (!contained.contains(name)) { - contained.add(name); - try { - if (name.endsWith("n+1")) { - name = name.substring(0, name.length() - 2); - builder.addSequential(name, ExpressionModifier.modifyExpression(expression, modifier)); - } else - builder.addCombinatorial(name, ExpressionModifier.modifyExpression(expression, modifier)); - } catch (BuilderException e) { - throw new RuntimeException(e); - } - } - } - - @Override - public void close() { - } - }; - if (useJKOptimizer) - el = new ExpressionListenerOptimizeJK(el); - - expressions.replayTo(el); - } - - BuilderExpressionCreator setUseJKOptimizer(boolean useJKOptimizer) { - this.useJKOptimizer = useJKOptimizer; - return this; - } - } - private final class HTMLExpressionListener implements ExpressionListener { private FormatToExpression htmlFormatter = new HTMLFormatter(FormatToExpression.getDefaultFormat()); private final StringBuilder html; diff --git a/src/test/java/de/neemann/digital/analyse/expression/CopyTest.java b/src/test/java/de/neemann/digital/analyse/expression/CopyTest.java new file mode 100644 index 000000000..992bbfd90 --- /dev/null +++ b/src/test/java/de/neemann/digital/analyse/expression/CopyTest.java @@ -0,0 +1,28 @@ +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; + +/** + * Created by hneemann on 02.04.17. + */ +public class CopyTest extends TestCase { + + public void testIntegral() throws ExpressionException { + Variable a = new Variable("A"); + Variable b = new Variable("B"); + Variable c = new Variable("C"); + Expression e1 = and(not(or(not(a), not(b), c)), not(and(not(a), not(b)))); + Expression e2 = e1.copy(); + + ContextFiller fc = new ContextFiller(e1); + + for (int i = 0; i < fc.getRowCount(); i++) { + fc.setContextTo(i); + assertEquals(e1.calculate(fc), e2.calculate(fc)); + } + } +} diff --git a/src/test/java/de/neemann/digital/gui/components/table/BuilderExpressionCreatorTest.java b/src/test/java/de/neemann/digital/gui/components/table/BuilderExpressionCreatorTest.java new file mode 100644 index 000000000..9eb3ed749 --- /dev/null +++ b/src/test/java/de/neemann/digital/gui/components/table/BuilderExpressionCreatorTest.java @@ -0,0 +1,83 @@ +package de.neemann.digital.gui.components.table; + + +import de.neemann.digital.analyse.AnalyseException; +import de.neemann.digital.analyse.ModelAnalyser; +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.expression.modify.ExpressionModifier; +import de.neemann.digital.analyse.quinemc.BoolTable; +import de.neemann.digital.analyse.quinemc.ThreeStateValue; +import de.neemann.digital.builder.circuit.CircuitBuilder; +import de.neemann.digital.core.Model; +import de.neemann.digital.core.NodeException; +import de.neemann.digital.core.basic.*; +import de.neemann.digital.draw.elements.PinException; +import de.neemann.digital.draw.library.ElementLibrary; +import de.neemann.digital.draw.library.ElementNotFoundException; +import de.neemann.digital.draw.model.ModelCreator; +import de.neemann.digital.draw.shapes.ShapeFactory; +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; + +/** + * Created by hneemann on 02.04.17. + */ +public class BuilderExpressionCreatorTest extends TestCase { + private ElementLibrary libary = new ElementLibrary(); + private ShapeFactory shapeFactory = new ShapeFactory(libary); + + public void testSimple() throws FormatterException, ExpressionException, ElementNotFoundException, PinException, NodeException, AnalyseException { + Variable a = v("A"); + Variable b = v("B"); + Expression xor = or(and(a, not(b)), and(not(a), b)); + + ExpressionListenerStore els = new ExpressionListenerStore(null); + els.resultFound("xor", xor); + els.close(); + + Model m = create(els, ExpressionModifier.IDENTITY); + assertEquals(5, m.size()); + assertEquals(2, m.findNode(And.class).size()); + assertEquals(1, m.findNode(Or.class).size()); + assertEquals(2, m.findNode(Not.class).size()); + check(m); + + m = create(els, new de.neemann.digital.analyse.expression.modify.NAnd()); + assertEquals(5, m.size()); + assertEquals(2, m.findNode(Not.class).size()); + assertEquals(3, m.findNode(NAnd.class).size()); + check(m); + + m = create(els, new de.neemann.digital.analyse.expression.modify.NOr()); + assertEquals(6, m.size()); + assertEquals(3, m.findNode(Not.class).size()); + assertEquals(3, m.findNode(NOr.class).size()); + check(m); + } + + private void check(Model m) throws AnalyseException, NodeException { + TruthTable tt = new ModelAnalyser(m).analyse(); + assertEquals(1,tt.getResultCount()); + BoolTable r = tt.getResult(0); + assertEquals(4, r.size()); + assertEquals(ThreeStateValue.zero ,r.get(0)); + assertEquals(ThreeStateValue.one ,r.get(1)); + assertEquals(ThreeStateValue.one ,r.get(2)); + assertEquals(ThreeStateValue.zero ,r.get(3)); + } + + private Model create(ExpressionListenerStore els, ExpressionModifier modifier) throws ExpressionException, FormatterException, ElementNotFoundException, PinException, NodeException { + CircuitBuilder circuitBuilder = new CircuitBuilder(shapeFactory, false); + new BuilderExpressionCreator(circuitBuilder, modifier).create(els); + return new ModelCreator(circuitBuilder.createCircuit(), libary).createModel(false); + } + +} \ No newline at end of file