aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/language-semantics/src
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2024-01-31 02:00:09 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2024-01-31 18:45:13 +0100
commitc63126d2f1ce5f571c316b37e00fb43d2da7c7d3 (patch)
tree16e9dd04624565f7c9ccedd17749a9f264e89cb0 /subprojects/language-semantics/src
parentfix(build): avoid cyclic dependency (diff)
downloadrefinery-c63126d2f1ce5f571c316b37e00fb43d2da7c7d3.tar.gz
refinery-c63126d2f1ce5f571c316b37e00fb43d2da7c7d3.tar.zst
refinery-c63126d2f1ce5f571c316b37e00fb43d2da7c7d3.zip
refactor(language): module and node declarations
* New default file extension: .refinery (.problem is also supported). * Add module keyword for self-contained modules. * Rename indiv declarations to atom declaration. * Add node and multi declarations for explicitly declared nodes and multi-objects, respectively.
Diffstat (limited to 'subprojects/language-semantics/src')
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java120
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/SolutionSerializer.java7
-rw-r--r--subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/SolutionSerializerTest.java43
3 files changed, 116 insertions, 54 deletions
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java
index 38bf5a61..b462fd70 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java
@@ -169,9 +169,9 @@ public class ModelInitializer {
169 169
170 private void collectNodes() { 170 private void collectNodes() {
171 for (var statement : problem.getStatements()) { 171 for (var statement : problem.getStatements()) {
172 if (statement instanceof IndividualDeclaration individualDeclaration) { 172 if (statement instanceof NodeDeclaration nodeDeclaration) {
173 for (var individual : individualDeclaration.getNodes()) { 173 for (var node : nodeDeclaration.getNodes()) {
174 collectNode(individual); 174 collectNode(node);
175 } 175 }
176 } else if (statement instanceof ClassDeclaration classDeclaration) { 176 } else if (statement instanceof ClassDeclaration classDeclaration) {
177 var newNode = classDeclaration.getNewNode(); 177 var newNode = classDeclaration.getNewNode();
@@ -355,10 +355,8 @@ public class ModelInitializer {
355 collectClassDeclarationAssertions(classDeclaration); 355 collectClassDeclarationAssertions(classDeclaration);
356 } else if (statement instanceof EnumDeclaration enumDeclaration) { 356 } else if (statement instanceof EnumDeclaration enumDeclaration) {
357 collectEnumAssertions(enumDeclaration); 357 collectEnumAssertions(enumDeclaration);
358 } else if (statement instanceof IndividualDeclaration individualDeclaration) { 358 } else if (statement instanceof NodeDeclaration nodeDeclaration) {
359 for (var individual : individualDeclaration.getNodes()) { 359 collectNodeDeclarationAssertions(nodeDeclaration);
360 collectIndividualAssertions(individual);
361 }
362 } else if (statement instanceof Assertion assertion) { 360 } else if (statement instanceof Assertion assertion) {
363 collectAssertion(assertion); 361 collectAssertion(assertion);
364 } 362 }
@@ -379,7 +377,7 @@ public class ModelInitializer {
379 private void collectEnumAssertions(EnumDeclaration enumDeclaration) { 377 private void collectEnumAssertions(EnumDeclaration enumDeclaration) {
380 var overlay = MutableSeed.of(1, null); 378 var overlay = MutableSeed.of(1, null);
381 for (var literal : enumDeclaration.getLiterals()) { 379 for (var literal : enumDeclaration.getLiterals()) {
382 collectIndividualAssertions(literal); 380 collectCardinalityAssertions(literal, TruthValue.TRUE);
383 var nodeId = getNodeId(literal); 381 var nodeId = getNodeId(literal);
384 overlay.mergeValue(Tuple.of(nodeId), TruthValue.TRUE); 382 overlay.mergeValue(Tuple.of(nodeId), TruthValue.TRUE);
385 } 383 }
@@ -387,9 +385,25 @@ public class ModelInitializer {
387 info.assertions().overwriteValues(overlay); 385 info.assertions().overwriteValues(overlay);
388 } 386 }
389 387
390 private void collectIndividualAssertions(Node node) { 388 private void collectNodeDeclarationAssertions(NodeDeclaration nodeDeclaration) {
389 var kind = nodeDeclaration.getKind();
390 TruthValue value;
391 switch (kind) {
392 case ATOM -> value = TruthValue.TRUE;
393 case MULTI -> value = TruthValue.UNKNOWN;
394 case NODE -> {
395 return;
396 }
397 default -> throw new IllegalArgumentException("Unknown node kind: " + kind);
398 }
399 for (var node : nodeDeclaration.getNodes()) {
400 collectCardinalityAssertions(node, value);
401 }
402 }
403
404 private void collectCardinalityAssertions(Node node, TruthValue value) {
391 var nodeId = getNodeId(node); 405 var nodeId = getNodeId(node);
392 collectCardinalityAssertions(nodeId, TruthValue.TRUE); 406 collectCardinalityAssertions(nodeId, value);
393 } 407 }
394 408
395 private void collectCardinalityAssertions(int nodeId, TruthValue value) { 409 private void collectCardinalityAssertions(int nodeId, TruthValue value) {
@@ -587,47 +601,51 @@ public class ModelInitializer {
587 601
588 private void toLiterals(Expr expr, Map<tools.refinery.language.model.problem.Variable, Variable> localScope, 602 private void toLiterals(Expr expr, Map<tools.refinery.language.model.problem.Variable, Variable> localScope,
589 List<Literal> literals) { 603 List<Literal> literals) {
590 if (expr instanceof LogicConstant logicConstant) { 604 switch (expr) {
591 switch (logicConstant.getLogicValue()) { 605 case LogicConstant logicConstant -> {
592 case TRUE -> literals.add(BooleanLiteral.TRUE); 606 switch (logicConstant.getLogicValue()) {
593 case FALSE -> literals.add(BooleanLiteral.FALSE); 607 case TRUE -> literals.add(BooleanLiteral.TRUE);
594 default -> throw new TracedException(logicConstant, "Unsupported literal"); 608 case FALSE -> literals.add(BooleanLiteral.FALSE);
595 } 609 default -> throw new TracedException(logicConstant, "Unsupported literal");
596 } else if (expr instanceof Atom atom) { 610 }
597 var target = getPartialRelation(atom.getRelation()); 611 }
598 var polarity = atom.isTransitiveClosure() ? CallPolarity.TRANSITIVE : CallPolarity.POSITIVE; 612 case Atom atom -> {
599 var argumentList = toArgumentList(atom.getArguments(), localScope, literals); 613 var target = getPartialRelation(atom.getRelation());
600 literals.add(target.call(polarity, argumentList)); 614 var polarity = atom.isTransitiveClosure() ? CallPolarity.TRANSITIVE : CallPolarity.POSITIVE;
601 } else if (expr instanceof NegationExpr negationExpr) { 615 var argumentList = toArgumentList(atom.getArguments(), localScope, literals);
602 var body = negationExpr.getBody(); 616 literals.add(target.call(polarity, argumentList));
603 if (!(body instanceof Atom atom)) { 617 }
604 throw new TracedException(body, "Cannot negate literal"); 618 case NegationExpr negationExpr -> {
605 } 619 var body = negationExpr.getBody();
606 var target = getPartialRelation(atom.getRelation()); 620 if (!(body instanceof Atom atom)) {
607 Constraint constraint; 621 throw new TracedException(body, "Cannot negate literal");
608 if (atom.isTransitiveClosure()) { 622 }
609 constraint = Query.of(target.name() + "#transitive", (builder, p1, p2) -> builder.clause( 623 var target = getPartialRelation(atom.getRelation());
610 target.callTransitive(p1, p2) 624 Constraint constraint;
611 )).getDnf(); 625 if (atom.isTransitiveClosure()) {
612 } else { 626 constraint = Query.of(target.name() + "#transitive", (builder, p1, p2) -> builder.clause(
613 constraint = target; 627 target.callTransitive(p1, p2)
614 } 628 )).getDnf();
615 var negatedScope = extendScope(localScope, negationExpr.getImplicitVariables()); 629 } else {
616 var argumentList = toArgumentList(atom.getArguments(), negatedScope, literals); 630 constraint = target;
617 literals.add(constraint.call(CallPolarity.NEGATIVE, argumentList)); 631 }
618 } else if (expr instanceof ComparisonExpr comparisonExpr) { 632 var negatedScope = extendScope(localScope, negationExpr.getImplicitVariables());
619 var argumentList = toArgumentList(List.of(comparisonExpr.getLeft(), comparisonExpr.getRight()), 633 var argumentList = toArgumentList(atom.getArguments(), negatedScope, literals);
620 localScope, literals); 634 literals.add(constraint.call(CallPolarity.NEGATIVE, argumentList));
621 boolean positive = switch (comparisonExpr.getOp()) { 635 }
622 case EQ -> true; 636 case ComparisonExpr comparisonExpr -> {
623 case NOT_EQ -> false; 637 var argumentList = toArgumentList(List.of(comparisonExpr.getLeft(), comparisonExpr.getRight()),
624 default -> throw new TracedException( 638 localScope, literals);
625 comparisonExpr, "Unsupported operator"); 639 boolean positive = switch (comparisonExpr.getOp()) {
626 }; 640 case EQ -> true;
627 literals.add(new EquivalenceLiteral(positive, argumentList.get(0), argumentList.get(1))); 641 case NOT_EQ -> false;
628 } else { 642 default -> throw new TracedException(
629 throw new TracedException(expr, "Unsupported literal"); 643 comparisonExpr, "Unsupported operator");
630 } 644 };
645 literals.add(new EquivalenceLiteral(positive, argumentList.get(0), argumentList.get(1)));
646 }
647 default -> throw new TracedException(expr, "Unsupported literal");
648 }
631 } 649 }
632 650
633 private List<Variable> toArgumentList( 651 private List<Variable> toArgumentList(
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/SolutionSerializer.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/SolutionSerializer.java
index 09ba34fc..537d94ca 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/SolutionSerializer.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/SolutionSerializer.java
@@ -197,9 +197,10 @@ public class SolutionSerializer {
197 var originalNode = pair.getOne(); 197 var originalNode = pair.getOne();
198 int nodeId = pair.getTwo(); 198 int nodeId = pair.getTwo();
199 var newNode = findNode(originalNode); 199 var newNode = findNode(originalNode);
200 // Since all implicit nodes that do not exist has already been remove in serializeSolution, 200 // Since all implicit nodes that do not exist has already been removed in serializeSolution,
201 // we only need to add !exists assertions to ::new nodes (nodes marked as an individual must always exist). 201 // we only need to add !exists assertions to ::new nodes and explicitly declared nodes that do not exist.
202 if (ProblemUtil.isNewNode(originalNode)) { 202 if (ProblemUtil.isMultiNode(originalNode) ||
203 (ProblemUtil.isDeclaredNode(originalNode) && !isExistingNode(nodeId))) {
203 sortedNewNodes.put(nodeId, newNode); 204 sortedNewNodes.put(nodeId, newNode);
204 } else { 205 } else {
205 nodes.put(nodeId, newNode); 206 nodes.put(nodeId, newNode);
diff --git a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/SolutionSerializerTest.java b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/SolutionSerializerTest.java
index 8ef449b0..b682a7d6 100644
--- a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/SolutionSerializerTest.java
+++ b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/SolutionSerializerTest.java
@@ -183,6 +183,49 @@ class SolutionSerializerTest {
183 !exists(Foo::new). 183 !exists(Foo::new).
184 Foo(a). 184 Foo(a).
185 default !ref(*, *). 185 default !ref(*, *).
186 """), Arguments.of("""
187 atom a.
188 class Foo.
189 """, """
190 Foo(a).
191 scope Foo += 0.
192 """, """
193 !exists(Foo::new).
194 Foo(a).
195 """), Arguments.of("""
196 multi a.
197 class Foo.
198 """, """
199 Foo(a).
200 !exists(Foo::new).
201 scope Foo = 2.
202 """, """
203 !exists(a).
204 !exists(Foo::new).
205 Foo(foo1).
206 Foo(foo2).
207 """), Arguments.of("""
208 node a.
209 class Foo.
210 """, """
211 Foo(a).
212 ?exists(a).
213 scope Foo = 2, Foo += 1.
214 """, """
215 !exists(Foo::new).
216 Foo(a).
217 Foo(foo1).
218 """), Arguments.of("""
219 node a.
220 class Foo.
221 """, """
222 Foo(a).
223 ?exists(a).
224 scope Foo = 1, Foo += 1.
225 """, """
226 !exists(a).
227 !exists(Foo::new).
228 Foo(foo1).
186 """)); 229 """));
187 } 230 }
188} 231}