diff --git a/btypes_primitives/src/main/python_magicstack_immutable/btypes/BRelation.py b/btypes_primitives/src/main/python_magicstack_immutable/btypes/BRelation.py index 92f791a052941ca7304d6195014ace814741dee5..1b894ec5604443d733959122d6b12e3884461814 100644 --- a/btypes_primitives/src/main/python_magicstack_immutable/btypes/BRelation.py +++ b/btypes_primitives/src/main/python_magicstack_immutable/btypes/BRelation.py @@ -8,6 +8,9 @@ import immutables from functools import reduce import random +from z3 import Solver +from z3 import sat +from z3 import And class BRelation: @@ -719,3 +722,16 @@ class BRelation: i = i + 1 sb += "}" return sb + + @staticmethod + def fromSolver(solver: 'Solver', listOfVariables) -> 'BRelation': + currentSet = [] + + while solver.check() == sat: + currentTuple = reduce(lambda a, b: BTuple(solver.model()[a], solver.model()[b]), listOfVariables) + currentSet.append(currentTuple) + firstCondition = Or(listOfVariables[0] != solver.model()[listOfVariables[0]], + listOfVariables[1] != solver.model()[listOfVariables[1]]) + solver.add(reduce(lambda a, b: Or(a, b != solver.model()[b]), listOfVariables[2:], firstCondition)) + + return BRelation(*currentSet) diff --git a/btypes_primitives/src/main/python_magicstack_immutable/btypes/BSet.py b/btypes_primitives/src/main/python_magicstack_immutable/btypes/BSet.py index cd0ed7551a87b507d3c3f9b79b4c2aec4cd2bd1b..66a7ec48c36e3e884b7bd32d7ea038ae472a00b7 100644 --- a/btypes_primitives/src/main/python_magicstack_immutable/btypes/BSet.py +++ b/btypes_primitives/src/main/python_magicstack_immutable/btypes/BSet.py @@ -5,7 +5,8 @@ from btypes.BStruct import * import immutables from functools import reduce - +from z3 import Solver +from z3 import sat class BSet: @@ -255,5 +256,15 @@ class BSet: def __iter__(self): return iter(self.__set) + @staticmethod + def fromSolver(solver: 'Solver', listOfVariables) -> 'BSet': + currentSet = [] + key = [x for x in listOfVariables][0] + while solver.check() == sat: + currentSet.append(solver.model()[key]) + solver.add(key != solver.model()[key]) + + return BSet(*currentSet) + # Import is at the bottom due to cyclic dependencies from btypes.BRelation import * diff --git a/btypes_primitives/src/main/python_magicstack_immutable/btypes/BZ3.py b/btypes_primitives/src/main/python_magicstack_immutable/btypes/BZ3.py new file mode 100644 index 0000000000000000000000000000000000000000..3e31f7532eaa896d69f18104f0eecac2de553d2b --- /dev/null +++ b/btypes_primitives/src/main/python_magicstack_immutable/btypes/BZ3.py @@ -0,0 +1,26 @@ +from z3 import Int +from z3 import ArithRef +from z3 import BoolRef +from z3 import And + + +def greater(self, other): + return self > other + + +def less(self, other): + return self < other + + +def equal(self, other): + return self == other + + +def __and(self, other): + return And(self, other) + + +setattr(ArithRef, 'greater', greater) +setattr(ArithRef, 'less', less) +setattr(ArithRef, 'equal', equal) +setattr(BoolRef, '_and', __and) diff --git a/constraint_solver.adoc b/constraint_solver.adoc new file mode 100644 index 0000000000000000000000000000000000000000..478f44cdf3848ddc5fa14978242c230d2228b1ac --- /dev/null +++ b/constraint_solver.adoc @@ -0,0 +1,171 @@ +# Entscheidungen bzgl. Constraint Solver + +Der Codegenerator b2program unterstützt zur Zeit nur einen Teil der in ProB implementierten Set-Comprehensions. +Um diese Funktion zu erweitern haben wir den Einsatz eines Constraint-Solvers in Betracht gezogen. +Constraint-Solver sind Programme, denen man ein Problem beschreibt und die dann eine / alle mögliche(n) Lösung(en) berechnen. + +Zuletzt haben wir b2program um die Programmiersprache Python erweitert. +Daher haben wir uns entschieden auch mit der Erweiterung um einen Constraint-Solver für Python zu beginnen. + +In einer Recherche sind wir auf die folgenden Constraint-Solver gestoßen: + +* https://choco-solver.org/[Choco-Solver] +* https://github.com/xoolive/facile[facile] +* https://labix.org/python-constraint[python-constraint] +* https://developers.google.com/optimization/cp/cp_solver[CP-SAT Solver] +* https://docs.sympy.org/latest/modules/solvers/solvers.html[SymPy] + +Im folgenden werden wir Vor- und Nachteile, sowie unsere Vorgehensweise und Probleme mit den einzelnen Constraint-Solvern erläutern. + +## Choco-Solver +Der Choco-Solver ist eine mit IntelliJ IDEA entwickelte Open-Source Bibliothek. +In der Ursprünglichen Recherche ist der Solver auf Grund vielfältiger Datentypen positiv aufgefallen. +Nach oberflächlicher Betrachtung ist allerdings aufgefallen, dass nur die Programmiersprache Java unterstützt wird. +Daher ist der Choco-Solver für Python nicht geeignet. +Allerdings ist für die Implementierung in Java zu empfehlen diesen genauer zu betrachten. + +## facile +Facile ist einer der ersten Constraint-Solver auf den wir gestoßen sind. +Er unterstützt laut Dokumentation Gleichungen, Ungleichungen, sowie Funktionen. +Allerdings gab es bei der Installation Probleme. + +Die empfohlene Installation ist die Installation mit pip. +Diese warf folgende Fehlermeldung: + + ERROR: Could not find a version that satisfies the requirement facile + ERROR: No matching distribution found for facile + +Nach etwas mehr Recherche stellte sich heraus, dass keine passende Version der Software für mein System bei pip hinterlegt ist. + +Die nächste Installationsvariante war die Installation mit easy_install. +Dabei gab es Probleme, da die setuptools-Bibliothek nicht gefunden wurde. +Der Import der Bibliothek mit Python funktionierte allerdings. +Im Verdacht waren fehlende PATH Variablen, falsch installierte Python-Versionen, sowie Probleme mit Nutzerrechten. +Allerdings konnte ich für dieses Problem leider keine Lösung finden. + +Der nächste Ansatz zur Installation war die Installation mit opam. +Dafür musste zunächst opam istalliert werden. +Danach konnte mit opam install facile die Bibliothek installiert werden. +Allerdings habe ich dann erst festgestellt, dass facile nur für python2 geeignet ist. +Da die in der API verwendete Syntax Python3 kompatibel ist, ist mir dies nicht vorher aufgefalen. +Daher ist facile für unsere Zwecke nicht geeignet, da b2program Python3 verwendet und auf weitere externe Bibliotheken angewiesen ist. + +## python-constraint +Python-constraint ist der Constraint-Solver, der von PyB, einem B-Interpreter unseres Lehrstuhls, verwendet wird. +Die Installation mit pip verlief hier problemlos. + +Um mit python-constraint eine Problem zu lösen, legt man erst das Problem an. +Dann fügt dann die Variablen mit einem gegebenen Definitionsbereich pro Variable hinzu. +Zuletzt fügt man die Bedingungen hinzu und kann sich dann die Lösungen ausgeben lassen. +Die Syntax dafür sieht wie folgt aus: + +.... +from constraint import * + +problem = Problem() + +problem.addVariable("x", range(-50,50)) +problem.addVariable("y", range(-50,50)) + +problem.addConstraint(lambda x,y: 0<x and x<y and y<10, ["x", "y"]) + +problem.getSolutions() +.... + +Mit dieser Definition berechnet man die Set-Comprehensions {x,y | 0<x & x<y & y<10} (unter der Einschränkung, dass x und y im Intervall von -50 bis 50 liegen). +b2program kann solche Set-Comprehensions bisher noch nicht lösen, da alle Variablen am Beginn des Prädikates gebunden werden müssen. +Die Einschränkung des Definitionsbereichs der Variablen lässt sich über den Typ vornehmen, der bei den entsprechenden DeclarationNodes des ASTs hinterlegt ist + +Der Definitionsbereich der Variablen lässt sich als Liste beliebiger Werte angeben. +Daher lassen sich auch andere Typen als Integer, wie z.B. Boolean definieren. + +Allerdings kann der angegebene Definitionsbereich nicht unendlich groß werden. +Möchte man beispielsweise den Integer-Bereich von -2147483648 bis 2147483647 (Standard Integer Bereich von b2program), so gibt python-constraint nur einen *"MemoryError"* aus. + +Betrachtet man also Probleme mit großen Zahlen, so ist python-constraint nicht geeignet. +Für kleinere Probleme sollte es allerdings gut funktionieren. + +## CP-SAT Solver +Der CP-SAT Solver ist ein Constraint-Solver von Google zur Lösung von Integer Constraints. +Dieser Solver unterstützt nur Probleme, die durch Integer ausgedrückt werden können. +Allerdings kann man z.B. Booleans durch 0 und 1 ausdrücken und ggf. auch andere Problemstellungen umformulieren. +Die Installation erfolgt hier ebenfalls über pip. + +Das Anlegen und Lösen eines Problems erfolgt hier ähnlich zu python-constraint. +Allerdings werden die Variablen hier als separate Variablen deklariert und nicht nur im Problem gespeichert. +Die Syntax sieht wie folgt aus: + +.... +from ortools.sat.python import cp_model + +model = cp_model.CpModel() + +x = model.NewIntVar(-50, 50, 'x') +y = model.NewIntVar(-50, 50, 'y') + +model.Add(0<x) +model.Add(x<y) +model.Add(y<10) + +solver = cp_model.CpSolver() +status = solver.Solve(model) + +print("Wert für x: ", solver.Value(x)) +print("Wert für y: ", solver.Value(y)) +.... + +Dies gibt allerdings nur eine mögliche Lösung aus. +Wenn man alle Lösungen ausgeben möchte, muss man eine zusätzliche Klasse definieren, die während des Lösungsprozesses alle Lösungen sammelt und dann am Ende ausgeben kann. +Außerdem müssen die (Un-)Gleichungen jeweils separat hinzugefügt werden und können nicht gesammelt übergeben werden. + +Für diesen Solver spricht allerdings, dass er auch mit großen Zahlen arbeiten kann und alle möglichen Lösungen berechnet. + +## SymPy +SymPy ist eine Bibliothek, die symbolischen Umgang mit verschiedenen Typen von Gleichungen ermöglicht. +Das heißt, dass Gleichungen nach Möglichkeit nicht ausgerechnet, sondern vereinfacht werden. +Die Ergebnisse werden dann symbolisch dargestellt und können so verwendet werden. + +Die Syntax dafür sieht wie folgt aus: +.... +from sympy import symbols +from sympy.solvers.inequalities import reduce_rational_inequalities +x=symbols('x') +reduce_rational_inequalities([[0<x]], x) +.... + +Mit SymPy ist es allerdings schwierig Gleichungen und Ungleichungen, oder mehrere Gleichungen zu kombinieren. +Daher ist es für unsere Zwecke wahrscheinlich nicht geeignet. + +## Fazit +Von den betrachteten Solvern sind wahrscheinlich python-constraint und CP-SAT Solver die beiden passendsten für unser Problem. +python-constraint liefert viel Funktionalität, dank der Constraints über lambda-Funktionen, schränkt dafür aber den Zahlenraum stark ein. +CP-SAT Solver hingegen liefert einen großen Zahlenraum, dafür ist es komplizierter die Constraints zu definieren. + +## Nachtrag: Z3 Solver +Der Z3 Solver stellt viele Funktionen für das Constraint Solving zur Verfügung. +Darunter fallen Datentypen wie Int, Bool, String und mehr. +Des weiteren ist es möglich Prädikate wie Exists und ForAll abzufragen. +Wie auch bei den anderen Constaint Solvern ist es auch hier möglich die Lösungsmenge zu extrahieren. +Allerdings muss dafür jede Lösung einzeln gesammelt und dann von den möglichen Lösungen ausgeschlossen werden. +Der Code dafür sieht wie folgt aus: + +.... +solutionSet = [] + while solver.check() == sat: + currentTuple = reduce(lambda a, b: BTuple(solver.model()[a], solver.model()[b]), listOfVariables) + solutionSet.append(currentTuple) + firstCondition = + Or(listOfVariables[0] != solver.model()[listOfVariables[0]], + listOfVariables[1] != solver.model()[listOfVariables[1]]) + solver.add(reduce(lambda a, b: Or(a, b != solver.model()[b]), + listOfVariables[2:], firstCondition)) + +.... + +Dabei müssen die Variablen nachgehalten werden und jeweils einzeln ausgeschlossen werden. + +Mit dem Funktionsumfang ist der z3 Solver wahrscheinlich das geeignetste Mittel für unseren Zweck. +Aus Zeitgründen wurde eine vollständige Implementierung allerdings nicht durchgeführt. +Um den Solver zu implementieren müssen die B-Predikate zu Z3 Predikaten umgeschrieben werden. +Wahrscheinlich sollte dafür ein neuer PredicateGenerator geschrieben werden, der dann die entsprechenden Predikate generiert. +Dies ist allerdings zeitaufwändig. diff --git a/src/main/java/de/hhu/stups/codegenerator/generators/MachineGenerator.java b/src/main/java/de/hhu/stups/codegenerator/generators/MachineGenerator.java index 9ee3f00a4adf99b48d96e0e61c04491bb60bdc03..116a92dc46b77b58fd2e1ee10e6ba8a0fae93861 100644 --- a/src/main/java/de/hhu/stups/codegenerator/generators/MachineGenerator.java +++ b/src/main/java/de/hhu/stups/codegenerator/generators/MachineGenerator.java @@ -4,6 +4,7 @@ import de.hhu.stups.codegenerator.CodeGeneratorUtils; import de.hhu.stups.codegenerator.GeneratorMode; import de.hhu.stups.codegenerator.analyzers.DeferredSetAnalyzer; import de.hhu.stups.codegenerator.analyzers.RecordStructAnalyzer; +import de.hhu.stups.codegenerator.generators.iteration.ConstraintSolverPredicateGenerator; import de.hhu.stups.codegenerator.handlers.IterationConstructHandler; import de.hhu.stups.codegenerator.handlers.NameHandler; import de.hhu.stups.codegenerator.handlers.ParallelConstructHandler; @@ -87,6 +88,8 @@ public class MachineGenerator implements AbstractVisitor<String, Void> { private final PredicateGenerator predicateGenerator; + private final ConstraintSolverPredicateGenerator constraintSolverPredicateGenerator; + private final LambdaFunctionGenerator lambdaFunctionGenerator; private final SubstitutionGenerator substitutionGenerator; @@ -153,7 +156,8 @@ public class MachineGenerator implements AbstractVisitor<String, Void> { expressionGenerator, predicateGenerator, identifierGenerator, iterationConstructHandler, parallelConstructHandler, recordStructGenerator, declarationGenerator, lambdaFunctionGenerator, infiniteSetGenerator); - this.operatorGenerator = new OperatorGenerator(predicateGenerator, expressionGenerator); + this.constraintSolverPredicateGenerator = new ConstraintSolverPredicateGenerator(this, iterationConstructHandler); + this.operatorGenerator = new OperatorGenerator(predicateGenerator, expressionGenerator, constraintSolverPredicateGenerator); this.operationGenerator = new OperationGenerator(currentGroup, this, substitutionGenerator, declarationGenerator, identifierGenerator, nameHandler, typeGenerator, recordStructGenerator); diff --git a/src/main/java/de/hhu/stups/codegenerator/generators/OperatorGenerator.java b/src/main/java/de/hhu/stups/codegenerator/generators/OperatorGenerator.java index c002f2acc6d31977f080f2d1147bce6223034d6d..e74c32b6703f335c1f9bc469706a82a56c5c42e5 100644 --- a/src/main/java/de/hhu/stups/codegenerator/generators/OperatorGenerator.java +++ b/src/main/java/de/hhu/stups/codegenerator/generators/OperatorGenerator.java @@ -1,6 +1,7 @@ package de.hhu.stups.codegenerator.generators; +import de.hhu.stups.codegenerator.generators.iteration.ConstraintSolverPredicateGenerator; import de.hhu.stups.codegenerator.handlers.TemplateHandler; import de.prob.parser.ast.nodes.expression.ExpressionOperatorNode; import de.prob.parser.ast.nodes.predicate.PredicateOperatorNode; @@ -36,11 +37,13 @@ public class OperatorGenerator { private final ExpressionGenerator expressionGenerator; - public OperatorGenerator(final PredicateGenerator predicateGenerator, final ExpressionGenerator expressionGenerator) { + public OperatorGenerator(final PredicateGenerator predicateGenerator, final ExpressionGenerator expressionGenerator, + final ConstraintSolverPredicateGenerator constraintSolverPredicateGenerator) { this.predicateGenerator = predicateGenerator; this.predicateGenerator.setOperatorGenerator(this); this.expressionGenerator = expressionGenerator; this.expressionGenerator.setOperatorGenerator(this); + constraintSolverPredicateGenerator.setOperatorGenerator(this); } /* @@ -63,7 +66,7 @@ public class OperatorGenerator { } return template.render(); }); - return result.isPresent() ? result.get() : ""; + return result.orElse(""); } /* diff --git a/src/main/java/de/hhu/stups/codegenerator/generators/iteration/ConstraintSolverPredicateGenerator.java b/src/main/java/de/hhu/stups/codegenerator/generators/iteration/ConstraintSolverPredicateGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..345ae5b789bd1e6a0dd5d194f14ac46015a9a182 --- /dev/null +++ b/src/main/java/de/hhu/stups/codegenerator/generators/iteration/ConstraintSolverPredicateGenerator.java @@ -0,0 +1,105 @@ +package de.hhu.stups.codegenerator.generators.iteration; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import de.hhu.stups.codegenerator.generators.MachineGenerator; +import de.hhu.stups.codegenerator.generators.OperatorGenerator; +import de.hhu.stups.codegenerator.handlers.IterationConstructHandler; +import de.prob.parser.ast.nodes.expression.ExpressionOperatorNode; +import de.prob.parser.ast.nodes.predicate.IdentifierPredicateNode; +import de.prob.parser.ast.nodes.predicate.IfPredicateNode; +import de.prob.parser.ast.nodes.predicate.LetPredicateNode; +import de.prob.parser.ast.nodes.predicate.PredicateOperatorNode; +import de.prob.parser.ast.nodes.predicate.PredicateOperatorWithExprArgsNode; +import de.prob.parser.ast.nodes.predicate.QuantifiedPredicateNode; +import de.prob.parser.ast.visitors.generic.ParametrisedPredicateVisitor; + +public class ConstraintSolverPredicateGenerator implements ParametrisedPredicateVisitor<String, Void> { + + /* + * Hard-coded lists for identifying the type of the operators for predicates + */ + private static final List<PredicateOperatorNode.PredicateOperator> BINARY_PREDICATE_OPERATORS = + Arrays.asList(PredicateOperatorNode.PredicateOperator.AND, PredicateOperatorNode.PredicateOperator.OR, + PredicateOperatorNode.PredicateOperator.IMPLIES, PredicateOperatorNode.PredicateOperator.EQUIVALENCE); + + private static final List<PredicateOperatorNode.PredicateOperator> UNARY_PREDICATE_OPERATORS = + Collections.singletonList(PredicateOperatorNode.PredicateOperator.NOT); + + private static final List<PredicateOperatorNode.PredicateOperator> PREDICATE_BOOLEANS = + Arrays.asList(PredicateOperatorNode.PredicateOperator.TRUE, PredicateOperatorNode.PredicateOperator.FALSE); + + private static final List<ExpressionOperatorNode.ExpressionOperator> POWER_SET_EXPRESSIONS = + Arrays.asList(ExpressionOperatorNode.ExpressionOperator.POW, ExpressionOperatorNode.ExpressionOperator.POW1, ExpressionOperatorNode.ExpressionOperator.FIN, ExpressionOperatorNode.ExpressionOperator.FIN1); + + + + private final MachineGenerator machineGenerator; + private OperatorGenerator operatorGenerator; + + public ConstraintSolverPredicateGenerator(MachineGenerator machineGenerator, + IterationConstructHandler iterationConstructHandler) { + this.machineGenerator = machineGenerator; + iterationConstructHandler.setConstraintSolverPredicateGenerator(this); + } + + @Override + public String visitIdentifierPredicateNode(IdentifierPredicateNode node, Void expected) { + throw new RuntimeException("Given node is not implemented: " + node.getClass()); + } + + @Override + public String visitPredicateOperatorNode(PredicateOperatorNode node, Void expected) { + List<String> expressionList = node.getPredicateArguments().stream() + .map(expr -> machineGenerator.visitPredicateNode(expr, null)) + .collect(Collectors.toList()); + return generatePredicate(node, expressionList); + } + + @Override + public String visitPredicateOperatorWithExprArgs(PredicateOperatorWithExprArgsNode node, Void expected) { + List<String> expressionList = node.getExpressionNodes().stream() + .map(expr -> machineGenerator.visitExprNode(expr, null)) + .collect(Collectors.toList()); + return operatorGenerator.generateBinary(node::getOperator, expressionList); + } + + @Override + public String visitQuantifiedPredicateNode(QuantifiedPredicateNode node, Void expected) { + //TODO + throw new RuntimeException("Given node is not implemented: " + node.getClass()); + } + + @Override + public String visitLetPredicateNode(LetPredicateNode node, Void expected) { + //TODO + throw new RuntimeException("Given node is not implemented: " + node.getClass()); + } + + @Override + public String visitIfPredicateNode(IfPredicateNode node, Void expected) { + //TODO + throw new RuntimeException("Given node is not implemented: " + node.getClass()); + } + + /* + * This function generates code for a predicate with the given AST node and the list of expressions within the predicate. + */ + public String generatePredicate(PredicateOperatorNode node, List<String> expressionList) { + PredicateOperatorNode.PredicateOperator operator = node.getOperator(); + if(BINARY_PREDICATE_OPERATORS.contains(operator)) { + return operatorGenerator.generateBinary(() -> operator, expressionList); + } else if(UNARY_PREDICATE_OPERATORS.contains(operator)) { + return "";//generateUnaryPredicate(operator, expressionList); + } else if(PREDICATE_BOOLEANS.contains(operator)) { + return "";//generateBoolean(operator); + } + throw new RuntimeException("Given operator is not implemented: " + node.getOperator()); + } + + public void setOperatorGenerator(OperatorGenerator operatorGenerator) { + this.operatorGenerator = operatorGenerator; + } +} diff --git a/src/main/java/de/hhu/stups/codegenerator/generators/iteration/IterationConstructGenerator.java b/src/main/java/de/hhu/stups/codegenerator/generators/iteration/IterationConstructGenerator.java index 508fc28ff40a6656287a3d588cc4c987f3a16ce4..36b87c7f3a7c65ec889ba2b9dd70e3e5d1718b0a 100644 --- a/src/main/java/de/hhu/stups/codegenerator/generators/iteration/IterationConstructGenerator.java +++ b/src/main/java/de/hhu/stups/codegenerator/generators/iteration/IterationConstructGenerator.java @@ -91,10 +91,11 @@ public class IterationConstructGenerator implements AbstractVisitor<Void, Void> public IterationConstructGenerator(final IterationConstructHandler iterationConstructHandler, final MachineGenerator machineGenerator, final NameHandler nameHandler, final STGroup group, final TypeGenerator typeGenerator, final ImportGenerator importGenerator, final ExpressionGenerator expressionGenerator, - final PredicateGenerator predicateGenerator, final boolean useConstraintSolving) { + final PredicateGenerator predicateGenerator, final boolean useConstraintSolving, + final ConstraintSolverPredicateGenerator constraintSolverPredicateGenerator) { this.iterationConstructHandler = iterationConstructHandler; this.iterationPredicateGenerator = new IterationPredicateGenerator(group, machineGenerator, typeGenerator, iterationConstructHandler); - this.setComprehensionGenerator = new SetComprehensionGenerator(group, machineGenerator, this, iterationConstructHandler, iterationPredicateGenerator, typeGenerator, expressionGenerator, predicateGenerator); + this.setComprehensionGenerator = new SetComprehensionGenerator(group, machineGenerator, this, iterationConstructHandler, iterationPredicateGenerator, typeGenerator, expressionGenerator, predicateGenerator, constraintSolverPredicateGenerator); this.lambdaGenerator = new LambdaGenerator(group, machineGenerator, this, iterationConstructHandler, iterationPredicateGenerator, typeGenerator); this.quantifiedPredicateGenerator = new QuantifiedPredicateGenerator(group, machineGenerator, this, iterationConstructHandler, iterationPredicateGenerator); this.quantifiedExpressionGenerator = new QuantifiedExpressionGenerator(group, machineGenerator, nameHandler, typeGenerator, this, iterationConstructHandler, iterationPredicateGenerator); diff --git a/src/main/java/de/hhu/stups/codegenerator/generators/iteration/SetComprehensionGenerator.java b/src/main/java/de/hhu/stups/codegenerator/generators/iteration/SetComprehensionGenerator.java index cd35e520b5ef541b32512e8d1a41e94632cd318b..fc0dfd3038023d49dd66d87c5bedf9f2ee3b2008 100644 --- a/src/main/java/de/hhu/stups/codegenerator/generators/iteration/SetComprehensionGenerator.java +++ b/src/main/java/de/hhu/stups/codegenerator/generators/iteration/SetComprehensionGenerator.java @@ -42,9 +42,12 @@ public class SetComprehensionGenerator { private final ExpressionGenerator expressionGenerator; + private final ConstraintSolverPredicateGenerator constraintSolverPredicateGenerator; + public SetComprehensionGenerator(final STGroup group, final MachineGenerator machineGenerator, final IterationConstructGenerator iterationConstructGenerator, final IterationConstructHandler iterationConstructHandler, final IterationPredicateGenerator iterationPredicateGenerator, - final TypeGenerator typeGenerator, final ExpressionGenerator expressionGenerator, final PredicateGenerator predicateGenerator) { + final TypeGenerator typeGenerator, final ExpressionGenerator expressionGenerator, final PredicateGenerator predicateGenerator, + final ConstraintSolverPredicateGenerator constraintSolverPredicateGenerator) { this.group = group; this.machineGenerator = machineGenerator; this.iterationConstructGenerator = iterationConstructGenerator; @@ -53,6 +56,7 @@ public class SetComprehensionGenerator { this.typeGenerator = typeGenerator; this.predicateGenerator = predicateGenerator; this.expressionGenerator = expressionGenerator; + this.constraintSolverPredicateGenerator = constraintSolverPredicateGenerator; } /* @@ -99,14 +103,14 @@ public class SetComprehensionGenerator { int iterationConstructCounter = iterationConstructHandler.getIterationConstructCounter(); String identifier = "_cs_set_" + iterationConstructCounter; - String problemIdentifier = "_cs_problem_" + iterationConstructCounter; + String solverIdentifier = "_cs_solver_" + iterationConstructCounter; boolean isRelation = node.getDeclarationList().size() > 1; //generateBody(template, enumerationTemplates, otherConstructs, identifier, isRelation, predicate, declarations, type); template.add("identifier", identifier); template.add("isRelation", isRelation); - template.add("problemIdentifier", problemIdentifier); + template.add("solverIdentifier", solverIdentifier); template.add("variableDeclarations", declarationTemplates); template.add("constraint", generateConstraint((PredicateOperatorNode) node.getPredicateNode(), declarations)); @@ -122,8 +126,6 @@ public class SetComprehensionGenerator { switch (declaration.getType().toString()){ case "INTEGER": range.add("isInteger", true); - range.add("minInt", expressionGenerator.generateMinInt()); - range.add("maxInt", expressionGenerator.generateMaxInt()); break; case "BOOL": range.add("isBoolean", true); @@ -133,12 +135,11 @@ public class SetComprehensionGenerator { } int iterationConstructCounter = iterationConstructHandler.getIterationConstructCounter(); - String problemIdentifier = "_cs_problem_" + iterationConstructCounter; + String solverIdentifier = "_cs_solver_" + iterationConstructCounter; ST template = group.getInstanceOf("constraint_variable_declaration"); template.add("identifier", declaration.getName()); - template.add("range", range.render()); - template.add("problemIdentifier", problemIdentifier); + template.add("type", range.render()); return template; } @@ -146,11 +147,9 @@ public class SetComprehensionGenerator { ST constraint = group.getInstanceOf("constraint"); int iterationConstructCounter = iterationConstructHandler.getIterationConstructCounter(); - String problemIdentifier = "_cs_problem_" + iterationConstructCounter; + String solverIdentifier = "_cs_solver_" + iterationConstructCounter; - constraint.add("problemIdentifier", problemIdentifier); - constraint.add("var1", declarations.get(0).getName()); - constraint.add("var2",declarations.subList(1,declarations.size()).stream().map(DeclarationNode::getName).collect(Collectors.toList())); + constraint.add("solverIdentifier", solverIdentifier); constraint.add("constraintFunction", predicateGenerator.visitPredicateOperatorNode(predicate)); return constraint.render(); diff --git a/src/main/java/de/hhu/stups/codegenerator/handlers/IterationConstructHandler.java b/src/main/java/de/hhu/stups/codegenerator/handlers/IterationConstructHandler.java index 7ea631b876bf4b28174c96e6be1ddaa4ffe28fe4..a6468c20c0af6bf9bbb8f51508511636d91accd6 100644 --- a/src/main/java/de/hhu/stups/codegenerator/handlers/IterationConstructHandler.java +++ b/src/main/java/de/hhu/stups/codegenerator/handlers/IterationConstructHandler.java @@ -3,6 +3,7 @@ package de.hhu.stups.codegenerator.handlers; import de.hhu.stups.codegenerator.generators.ExpressionGenerator; import de.hhu.stups.codegenerator.generators.ImportGenerator; import de.hhu.stups.codegenerator.generators.PredicateGenerator; +import de.hhu.stups.codegenerator.generators.iteration.ConstraintSolverPredicateGenerator; import de.hhu.stups.codegenerator.generators.iteration.IterationConstructGenerator; import de.hhu.stups.codegenerator.generators.MachineGenerator; import de.hhu.stups.codegenerator.generators.TypeGenerator; @@ -37,9 +38,11 @@ public class IterationConstructHandler { private ExpressionGenerator expressionGenerator; private PredicateGenerator predicateGenerator; + private ConstraintSolverPredicateGenerator constraintSolverPredicateGenerator; public IterationConstructHandler(final STGroup group, final MachineGenerator machineGenerator, final NameHandler nameHandler, - final TypeGenerator typeGenerator, final ImportGenerator importGenerator, final boolean useConstraintSolving) { + final TypeGenerator typeGenerator, final ImportGenerator importGenerator, + final boolean useConstraintSolving) { this.currentIterationConstructGenerator = null; this.iterationConstructCounter = 0; this.machineGenerator = machineGenerator; @@ -69,7 +72,7 @@ public class IterationConstructHandler { * This function returns a new IterationConstructGenerator */ public IterationConstructGenerator getNewIterationConstructGenerator() { - return new IterationConstructGenerator(this, machineGenerator, nameHandler, group, typeGenerator, importGenerator, expressionGenerator, predicateGenerator, useConstraintSolving); + return new IterationConstructGenerator(this, machineGenerator, nameHandler, group, typeGenerator, importGenerator, expressionGenerator, predicateGenerator, useConstraintSolving, constraintSolverPredicateGenerator); } /* @@ -162,11 +165,16 @@ public class IterationConstructHandler { return currentIterationConstructGenerator; } - public void setExpressionGenerator(ExpressionGenerator expressionGenerator) { + public void setExpressionGenerator(ExpressionGenerator expressionGenerator) { this.expressionGenerator = expressionGenerator; - } + } public void setPredicateGenerator(PredicateGenerator predicateGenerator) { this.predicateGenerator = predicateGenerator; } + + public void setConstraintSolverPredicateGenerator(ConstraintSolverPredicateGenerator constraintSolverPredicateGenerator) { + this.constraintSolverPredicateGenerator = constraintSolverPredicateGenerator; + } + } diff --git a/src/main/resources/de/hhu/stups/codegenerator/PythonTemplate.stg b/src/main/resources/de/hhu/stups/codegenerator/PythonTemplate.stg index 6b3a772cdc5e2b44b0f80a9d9fad698776a3af24..201ccb81752af449a799e5a98087df4493a13b55 100644 --- a/src/main/resources/de/hhu/stups/codegenerator/PythonTemplate.stg +++ b/src/main/resources/de/hhu/stups/codegenerator/PythonTemplate.stg @@ -192,41 +192,38 @@ set_comprehension_predicate(otherIterationConstructs, set, element, emptyPredica <if(emptyPredicate)> <set> = <set>.union(<if(isRelation)>BRelation<else>BSet<endif>(<element>)) <else> -if(<predicate>).booleanValue(): +if (<predicate>).booleanValue(): <set> = <set>.union(<if(isRelation)>BRelation<else>BSet<endif>(<element>)) <endif> >> -constraint_solving(identifier, problemIdentifier, variableDeclarations, constraint, isRelation) ::= << -from constraint import Problem +constraint_solving(identifier, solverIdentifier, variableDeclarations, constraint, isRelation) ::= << +from z3 import Solver +from btypes.BZ3 import Int +from z3 import Bool from functools import reduce from btypes.BSet import BSet from btypes.BUtils import BUtils -<problemIdentifier> = Problem() +<solverIdentifier> = Solver() +listOfVariables = [] <variableDeclarations; separator="\n"> <constraint> -<identifier> = <problemIdentifier>.getSolutions() -<if(isRelation)><identifier> = reduce(lambda a,e: a.union(BRelation(reduce(lambda b,f: BTuple(b,f), - list(e.values())[2:], - BTuple(list(e.values())[0],list(e.values())[1])))), - <identifier>, - BRelation()) -<else><identifier> = reduce(lambda a,e: a.union(BSet(e.values())), - <identifier>, - BSet()) +<if(isRelation)><identifier> = BRelation.fromSolver(<solverIdentifier>, listOfVariables) +<else> <identifier> = BSet.fromSolver(<solverIdentifier>, listOfVariables) <endif> >> -constraint_variable_declaration(identifier, problemIdentifier, range) ::= << -<identifier> = <problemIdentifier>.addVariable("<identifier>", <range>) +constraint_variable_declaration(identifier, type) ::= << +<identifier> = <type>('<identifier>') +listOfVariables.append(<identifier>) >> -constraint_type(isInteger, minInt, maxInt, isBoolean, isSet) ::= << -<if(isInteger)>BSet.interval(<minInt>, <maxInt>).getSet()<elseif(isBoolean)>BUtils.BOOL.getSet()<endif> +constraint_type(isInteger, isBoolean, isSet) ::= << +<if(isInteger)>Int<elseif(isBoolean)>Bool<endif> >> -constraint(problemIdentifier, var1, var2, constraintFunction) ::= << -<problemIdentifier>.addConstraint(lambda <var1><var2 : {var |, <var>}>: <constraintFunction>, ("<var1>"<var2 : {var |, "<var>"}>)) +constraint(solverIdentifier, constraintFunction) ::= << +<solverIdentifier>.add(<constraintFunction>) >> lambda(type, identifier, lambda, leftType, rightType) ::= << @@ -441,7 +438,7 @@ or(arg1, arg2) ::= << >> and(arg1, arg2) ::= << -(<arg1> and <arg2>) +(<arg1>._and(<arg2>)) >> implies(arg1, arg2) ::= <<