From ffb2cb067d7b219890a039ab1ec52d5de11c9c75 Mon Sep 17 00:00:00 2001 From: MarkBeB <177214717+MarkBeB@users.noreply.github.com> Date: Fri, 14 Aug 2026 12:43:44 +0200 Subject: [PATCH 1/9] Add lower/upper bounds to gipsl variables --- .../model/generated/Gipsl.ecore | 10 ++++++++++ .../model/generated/Gipsl.genmodel | 9 ++++++++- .../src/org/emoflon/gips/gipsl/Gipsl.xtext | 16 ++++++++++++++-- .../gips/gipsl/formatting2/GipslFormatter.xtend | 15 +++++++++++---- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/org.emoflon.gips.gipsl/model/generated/Gipsl.ecore b/org.emoflon.gips.gipsl/model/generated/Gipsl.ecore index 85576dda..520e9abd 100644 --- a/org.emoflon.gips.gipsl/model/generated/Gipsl.ecore +++ b/org.emoflon.gips.gipsl/model/generated/Gipsl.ecore @@ -64,6 +64,8 @@ + @@ -83,6 +85,14 @@ + + + + + + @@ -126,6 +126,7 @@ + @@ -143,6 +144,12 @@ + + + + + + diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/Gipsl.xtext b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/Gipsl.xtext index d809c29d..bce24ceb 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/Gipsl.xtext +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/Gipsl.xtext @@ -64,7 +64,9 @@ GipsMapping : ; GipsMappingVariable : - 'var' name=ID ':' type=[ecore::EDataType] (bound ?= 'bind' parameter=[GT::EditorParameter])? + 'var' name=ID ':' type=[ecore::EDataType] + (interval=GipsInterval)? + (bound ?= 'bind' parameter=[GT::EditorParameter])? ; GipsTypeExtension : @@ -74,7 +76,17 @@ GipsTypeExtension : ; GipsTypeExtensionVariable : - 'var' name=ID ':' type=[ecore::EDataType] (bound ?= 'bind' 'to' attribute=[ecore::EAttribute])? + 'var' name=ID ':' type=[ecore::EDataType] + (interval=GipsInterval)? + (bound ?= 'bind' 'to' attribute=[ecore::EAttribute])? +; + +GipsInterval: + '[' + ( (lowerBound=GipsArithmeticLiteral) | lowerInfinity?='*' ) + ',' + ( (upperBound=GipsArithmeticLiteral) | upperInfinity?='*' ) + ']' ; GipsConstant: diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/formatting2/GipslFormatter.xtend b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/formatting2/GipslFormatter.xtend index 562cc0c9..ad418fcb 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/formatting2/GipslFormatter.xtend +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/formatting2/GipslFormatter.xtend @@ -80,6 +80,7 @@ import org.emoflon.ibex.gt.editor.gT.EditorAttributeAssignment import static org.emoflon.gips.gipsl.gipsl.GipslPackage.Literals.* import org.emoflon.gips.gipsl.gipsl.GipsTypeExtension import org.emoflon.gips.gipsl.gipsl.GipsTypeExtensionVariable +import org.emoflon.gips.gipsl.gipsl.GipsInterval class GipslFormatter extends GTFormatter implements IFormatter2 { @@ -214,7 +215,7 @@ class GipslFormatter extends GTFormatter implements IFormatter2 { def dispatch void format(GipsMappingVariable gipsMappingVariable, extension IFormattableDocument document) { gipsMappingVariable.regionFor.keyword(gipsMappingVariableAccess.varKeyword_0).append[oneSpace] gipsMappingVariable.regionFor.keyword(gipsMappingVariableAccess.colonKeyword_2).surround[oneSpace] - gipsMappingVariable.regionFor.keyword(gipsMappingVariableAccess.boundBindKeyword_4_0_0).surround[oneSpace] + gipsMappingVariable.regionFor.keyword(gipsMappingVariableAccess.boundBindKeyword_5_0_0).surround[oneSpace] gipsMappingVariable.formatChilds(document) } @@ -237,11 +238,17 @@ class GipslFormatter extends GTFormatter implements IFormatter2 { def dispatch void format(GipsTypeExtensionVariable gipsTypeExtensionVariable, extension IFormattableDocument document) { gipsTypeExtensionVariable.regionFor.keyword(gipsTypeExtensionVariableAccess.varKeyword_0).append[oneSpace] gipsTypeExtensionVariable.regionFor.keyword(gipsTypeExtensionVariableAccess.colonKeyword_2).surround[oneSpace] - gipsTypeExtensionVariable.regionFor.keyword(gipsTypeExtensionVariableAccess.boundBindKeyword_4_0_0).surround[oneSpace] - gipsTypeExtensionVariable.regionFor.keyword(gipsTypeExtensionVariableAccess.toKeyword_4_1).append[oneSpace] - + gipsTypeExtensionVariable.interval.prepend[oneSpace] + gipsTypeExtensionVariable.regionFor.keyword(gipsTypeExtensionVariableAccess.boundBindKeyword_5_0_0).surround[oneSpace] + gipsTypeExtensionVariable.regionFor.keyword(gipsTypeExtensionVariableAccess.toKeyword_5_1).append[oneSpace] gipsTypeExtensionVariable.formatChilds(document) } + + def dispatch void format(GipsInterval gipsInterval, extension IFormattableDocument document) { + gipsInterval.regionFor.keyword(gipsIntervalAccess.leftSquareBracketKeyword_0).append[noSpace] + gipsInterval.regionFor.keyword(gipsIntervalAccess.commaKeyword_2).prepend[noSpace].append[oneSpace] + gipsInterval.regionFor.keyword(gipsIntervalAccess.rightSquareBracketKeyword_4).prepend[noSpace] + } def dispatch void format(GipsConstant gipsConstant, extension IFormattableDocument document) { gipsConstant.regionFor.keyword(gipsConstantAccess.letKeyword_0).append[oneSpace] From 25f6a84754bc98856c0277e650739c7bbea8af7e Mon Sep 17 00:00:00 2001 From: MarkBeB <177214717+MarkBeB@users.noreply.github.com> Date: Tue, 18 Aug 2026 10:51:18 +0200 Subject: [PATCH 2/9] Add upper/lower bounds to variables --- .../preprocess/RuleBinaryValueNegation.java | 6 +- .../preprocess/RuleEquivalenceShortcutA.java | 7 +-- .../preprocess/RuleEquivalenceShortcutB.java | 5 +- .../preprocess/RuleEquivalenceShortcutC.java | 3 +- .../preprocess/RuleEquivalenceShortcutD.java | 6 +- .../preprocess/RuleImplicitBooleans.java | 2 +- .../helper/GipsTransformationUtils.java | 27 ++++++++- .../ArithmeticExpressionTransformer.java | 32 +++++----- .../model/generated/Gipsl.ecore | 10 +++- .../model/generated/Gipsl.genmodel | 10 +++- .../src/org/emoflon/gips/gipsl/Gipsl.xtext | 6 +- .../gips/gipsl/generator/GeneratorUtil.java | 12 +++- .../special/pattern/BinaryValueNegation.java | 8 +-- .../special/pattern/EquivalenceShortcutA.java | 4 +- .../special/pattern/EquivalenceShortcutB.java | 2 +- .../special/pattern/EquivalenceShortcutC.java | 2 +- .../special/pattern/EquivalenceShortcutD.java | 17 +++--- .../special/pattern/ImplicationShortcutA.java | 2 +- .../pattern/ValueConstantRelation.java | 16 ++--- .../validation/GipslMappingValidator.java | 11 ++++ .../gips/gipsl/validation/GipslValidator.java | 58 ++++++++++++++++--- .../gipsl/validation/GipslValidatorUtil.java | 3 + 22 files changed, 169 insertions(+), 80 deletions(-) diff --git a/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleBinaryValueNegation.java b/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleBinaryValueNegation.java index 9ae27b09..c89d2d01 100644 --- a/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleBinaryValueNegation.java +++ b/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleBinaryValueNegation.java @@ -20,10 +20,10 @@ public GipsBooleanExpression tryRule(GipslFactory factory, GipsBooleanExpression relational.setOperator(RelationalOperator.EQUAL); relational.setLeft(EcoreUtil.copy(pattern.getNodeA())); - if (pattern.getLiteral().getValue().equals("1")) { - relational.setRight(GeneratorUtil.createArithmeticLiteral(factory, "0")); + if (pattern.getLiteral().getValue() == 1) { + relational.setRight(GeneratorUtil.createIntegerLiteral(factory, 0)); } else { - relational.setRight(GeneratorUtil.createArithmeticLiteral(factory, "1")); + relational.setRight(GeneratorUtil.createIntegerLiteral(factory, 1)); } return relational; diff --git a/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutA.java b/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutA.java index b0e7aebc..cab8a9f9 100644 --- a/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutA.java +++ b/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutA.java @@ -63,8 +63,8 @@ public GipsBooleanExpression tryRule(GipslFactory factory, GipsBooleanExpression for (var element : pattern.getOtherNodes()) summands.add(EcoreUtil.copy(element)); - var minusN = factory.createGipsArithmeticLiteral(); - minusN.setValue(Integer.toString(1 - pattern.getOtherNodes().size())); + var minusN = factory.createGipsIntegerLiteral(); + minusN.setValue(1 - pattern.getOtherNodes().size()); summands.add(minusN); // B + C + ... + (1-n) @@ -81,8 +81,7 @@ public GipsBooleanExpression tryRule(GipslFactory factory, GipsBooleanExpression // A <= B*M // ... for (var element : pattern.getOtherNodes()) { - var bigM = GeneratorUtil.createArithmeticLiteral(factory, - Double.toString(PluginPreferences.getBigMValue())); + var bigM = GeneratorUtil.createDoubleLiteral(factory, PluginPreferences.getBigMValue()); var bigMProduct = factory.createGipsArithmeticProduct(); bigMProduct.setOperator(GipsProductOperator.MULT); diff --git a/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutB.java b/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutB.java index b6c99e36..3425c880 100644 --- a/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutB.java +++ b/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutB.java @@ -70,8 +70,7 @@ public GipsBooleanExpression tryRule(GipslFactory factory, GipsBooleanExpression for (var element : pattern.getOtherNodes()) summands.add(EcoreUtil.copy(element)); - var minusN = factory.createGipsArithmeticLiteral(); - minusN.setValue(Integer.toString(1 - pattern.getOtherNodes().size())); + var minusN = GeneratorUtil.createIntegerLiteral(factory, 1 - pattern.getOtherNodes().size()); summands.add(minusN); // B + C + ... + (1-n) @@ -95,7 +94,7 @@ public GipsBooleanExpression tryRule(GipslFactory factory, GipsBooleanExpression var sum = GeneratorUtil.sum(factory, GipsSumOperator.PLUS, summands); // n - var n = GeneratorUtil.createArithmeticLiteral(factory, Double.toString(summands.size())); + var n = GeneratorUtil.createIntegerLiteral(factory, summands.size()); // n * A var nProduct = factory.createGipsArithmeticProduct(); diff --git a/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutC.java b/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutC.java index 63a7e6f6..1c1ba9f4 100644 --- a/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutC.java +++ b/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutC.java @@ -57,8 +57,7 @@ public GipsBooleanExpression tryRule(GipslFactory factory, GipsBooleanExpression var product = factory.createGipsArithmeticProduct(); product.setOperator(GipsProductOperator.MULT); product.setLeft(EcoreUtil.copy(pattern.getNodeA())); - product.setRight( - GeneratorUtil.createArithmeticLiteral(factory, Integer.toString(pattern.getOtherNodes().size()))); + product.setRight(GeneratorUtil.createIntegerLiteral(factory, pattern.getOtherNodes().size())); // B + C (+ D + ...) <= A*n var conjunctTwo = factory.createGipsRelationalExpression(); diff --git a/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutD.java b/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutD.java index 4f9013f5..138c031d 100644 --- a/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutD.java +++ b/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleEquivalenceShortcutD.java @@ -1,7 +1,5 @@ package org.emoflon.gips.build.gipsl.preprocess; -import static org.emoflon.gips.gipsl.generator.GeneratorUtil.createArithmeticLiteral; - import org.eclipse.emf.ecore.util.EcoreUtil; import org.emoflon.gips.build.preference.PluginPreferences; import org.emoflon.gips.gipsl.generator.GeneratorUtil; @@ -41,7 +39,7 @@ public GipsBooleanExpression tryRule(GipslFactory factory, GipsBooleanExpression if (!pattern.matchPattern(expression)) return null; - var one = createArithmeticLiteral(factory, "1"); + var one = GeneratorUtil.createIntegerLiteral(factory, 1); // 1-B var oneMinusB = factory.createGipsArithmeticSum(); @@ -55,7 +53,7 @@ public GipsBooleanExpression tryRule(GipslFactory factory, GipsBooleanExpression conjunctOne.setLeft(EcoreUtil.copy(oneMinusB)); conjunctOne.setRight(EcoreUtil.copy(pattern.getNodeA())); - var bigM = createArithmeticLiteral(factory, Double.toString(PluginPreferences.getBigMValue())); + var bigM = GeneratorUtil.createDoubleLiteral(factory, PluginPreferences.getBigMValue()); // (1-B)*M var bigMProduct = factory.createGipsArithmeticProduct(); diff --git a/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleImplicitBooleans.java b/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleImplicitBooleans.java index 5787244a..df388a3e 100644 --- a/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleImplicitBooleans.java +++ b/org.emoflon.gips.build/src/org/emoflon/gips/build/gipsl/preprocess/RuleImplicitBooleans.java @@ -19,7 +19,7 @@ public GipsBooleanExpression tryRule(GipslFactory factory, GipsBooleanExpression var relational = factory.createGipsRelationalExpression(); relational.setOperator(RelationalOperator.EQUAL); relational.setLeft(EcoreUtil.copy(pattern.getNodeA())); - relational.setRight(GeneratorUtil.createArithmeticLiteral(factory, "1")); + relational.setRight(GeneratorUtil.createIntegerLiteral(factory, 1)); // if (expression.eContainer() instanceof GipsBooleanNegation) { // var brackets = factory.createGipsBooleanBracket(); diff --git a/org.emoflon.gips.build/src/org/emoflon/gips/build/transformation/helper/GipsTransformationUtils.java b/org.emoflon.gips.build/src/org/emoflon/gips/build/transformation/helper/GipsTransformationUtils.java index ade49c7d..3474f965 100644 --- a/org.emoflon.gips.build/src/org/emoflon/gips/build/transformation/helper/GipsTransformationUtils.java +++ b/org.emoflon.gips.build/src/org/emoflon/gips/build/transformation/helper/GipsTransformationUtils.java @@ -6,6 +6,9 @@ import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EcorePackage; +import org.emoflon.gips.gipsl.gipsl.GipsArithmeticLiteral; +import org.emoflon.gips.gipsl.gipsl.GipsDoubleLiteral; +import org.emoflon.gips.gipsl.gipsl.GipsIntegerLiteral; import org.emoflon.gips.gipsl.gipsl.GipsVariable; import org.emoflon.gips.intermediate.GipsIntermediate.ArithmeticBinaryExpression; import org.emoflon.gips.intermediate.GipsIntermediate.ArithmeticExpression; @@ -310,29 +313,49 @@ public static Set extractConstantReference(final RelationalEx } public static double getUpperBound(final GipsVariable gipsVar, final VariableType type) { - if (type == VariableType.BINARY) { + if (type == VariableType.BINARY) return 1; + + if (gipsVar.getInterval() != null && !gipsVar.getInterval().isUpperInfinity()) { + return getValue(gipsVar.getInterval().getUpperBound()); + } else if (type == VariableType.INTEGER) { return Integer.MAX_VALUE; + } else if (type == VariableType.REAL) { return Double.MAX_VALUE; + } throw new UnsupportedOperationException(); } public static double getLowerBound(final GipsVariable gipsVar, final VariableType type) { - if (type == VariableType.BINARY) { + if (type == VariableType.BINARY) return 0; + + if (gipsVar.getInterval() != null && !gipsVar.getInterval().isLowerInfinity()) { + return getValue(gipsVar.getInterval().getLowerBound()); + } else if (type == VariableType.INTEGER) { return Integer.MIN_VALUE; + } else if (type == VariableType.REAL) { return -Double.MAX_VALUE; + } throw new UnsupportedOperationException(); } + private static double getValue(final GipsArithmeticLiteral literal) { + return switch (literal) { + case GipsIntegerLiteral val -> val.getValue(); + case GipsDoubleLiteral val -> val.getValue(); + default -> throw new IllegalArgumentException("Unexpected value: " + literal); + }; + } + public static ExpressionReturnType extractReturnType(BooleanExpression expression) { return ExpressionReturnTypeResolver.extractReturnType(expression); } diff --git a/org.emoflon.gips.build/src/org/emoflon/gips/build/transformation/transformer/ArithmeticExpressionTransformer.java b/org.emoflon.gips.build/src/org/emoflon/gips/build/transformation/transformer/ArithmeticExpressionTransformer.java index 51ab5418..69c7542c 100644 --- a/org.emoflon.gips.build/src/org/emoflon/gips/build/transformation/transformer/ArithmeticExpressionTransformer.java +++ b/org.emoflon.gips.build/src/org/emoflon/gips/build/transformation/transformer/ArithmeticExpressionTransformer.java @@ -16,6 +16,8 @@ import org.emoflon.gips.gipsl.gipsl.GipsArithmeticUnary; import org.emoflon.gips.gipsl.gipsl.GipsConstantReference; import org.emoflon.gips.gipsl.gipsl.GipsConstraint; +import org.emoflon.gips.gipsl.gipsl.GipsDoubleLiteral; +import org.emoflon.gips.gipsl.gipsl.GipsIntegerLiteral; import org.emoflon.gips.gipsl.gipsl.GipsLinearFunction; import org.emoflon.gips.gipsl.gipsl.GipsLinearFunctionReference; import org.emoflon.gips.gipsl.gipsl.GipsObjective; @@ -162,22 +164,20 @@ public ArithmeticExpression transform(final GipsArithmeticBracket bracket) throw } public ArithmeticExpression transform(final GipsArithmeticLiteral literal) throws Exception { - try { - int value = Integer.parseInt(literal.getValue()); - IntegerLiteral intLit = factory.createIntegerLiteral(); - intLit.setLiteral(value); - return intLit; - } catch (Exception e) { - try { - double dValue = Double.parseDouble(literal.getValue()); - DoubleLiteral doubleLit = factory.createDoubleLiteral(); - doubleLit.setLiteral(dValue); - return doubleLit; - } catch (Exception e2) { - throw new IllegalArgumentException( - "Value <" + literal.getValue() + "> can't be parsed to neither integer nor double value."); - } - } + return switch (literal) { + case GipsIntegerLiteral value -> { + IntegerLiteral lit = factory.createIntegerLiteral(); + lit.setLiteral(value.getValue()); + yield lit; + } + case GipsDoubleLiteral value -> { + DoubleLiteral lit = factory.createDoubleLiteral(); + lit.setLiteral(value.getValue()); + yield lit; + } + default -> throw new IllegalArgumentException( + "Value <" + literal + "> can't be parsed to neither integer nor double value."); + }; } public ArithmeticExpression transform(final GipsArithmeticConstant constant) throws Exception { diff --git a/org.emoflon.gips.gipsl/model/generated/Gipsl.ecore b/org.emoflon.gips.gipsl/model/generated/Gipsl.ecore index 520e9abd..ca471031 100644 --- a/org.emoflon.gips.gipsl/model/generated/Gipsl.ecore +++ b/org.emoflon.gips.gipsl/model/generated/Gipsl.ecore @@ -160,9 +160,7 @@ - - - + @@ -325,6 +323,12 @@ + + + + + + diff --git a/org.emoflon.gips.gipsl/model/generated/Gipsl.genmodel b/org.emoflon.gips.gipsl/model/generated/Gipsl.genmodel index 282ba4bb..053ae1f2 100644 --- a/org.emoflon.gips.gipsl/model/generated/Gipsl.genmodel +++ b/org.emoflon.gips.gipsl/model/generated/Gipsl.genmodel @@ -184,9 +184,7 @@ - - - + @@ -289,6 +287,12 @@ + + + + + + diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/Gipsl.xtext b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/Gipsl.xtext index bce24ceb..203920bc 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/Gipsl.xtext +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/Gipsl.xtext @@ -214,7 +214,7 @@ GipsArithmeticOperand: ; GipsArithmeticLiteral: - value = (GipsDoubleLiteral | GipsIntegerLiteral) + GipsDoubleLiteral | GipsIntegerLiteral ; GipsArithmeticConstant: @@ -450,11 +450,11 @@ enum QueryOperator : ; GipsDoubleLiteral: - GipsDouble + value = GipsDouble ; GipsIntegerLiteral: - GipsInteger + value = GipsInteger ; GipsDouble returns ecore::EDouble: diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/generator/GeneratorUtil.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/generator/GeneratorUtil.java index fc79b75b..e45269f0 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/generator/GeneratorUtil.java +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/generator/GeneratorUtil.java @@ -10,6 +10,8 @@ import org.emoflon.gips.gipsl.gipsl.GipsBooleanConjunction; import org.emoflon.gips.gipsl.gipsl.GipsBooleanDisjunction; import org.emoflon.gips.gipsl.gipsl.GipsBooleanExpression; +import org.emoflon.gips.gipsl.gipsl.GipsDoubleLiteral; +import org.emoflon.gips.gipsl.gipsl.GipsIntegerLiteral; import org.emoflon.gips.gipsl.gipsl.GipsSumOperator; import org.emoflon.gips.gipsl.gipsl.GipslFactory; @@ -18,8 +20,14 @@ private GeneratorUtil() { } - public static GipsArithmeticLiteral createArithmeticLiteral(GipslFactory factory, String value) { - GipsArithmeticLiteral literal = factory.createGipsArithmeticLiteral(); + public static GipsArithmeticLiteral createIntegerLiteral(GipslFactory factory, int value) { + GipsIntegerLiteral literal = factory.createGipsIntegerLiteral(); + literal.setValue(value); + return literal; + } + + public static GipsArithmeticLiteral createDoubleLiteral(GipslFactory factory, double value) { + GipsDoubleLiteral literal = factory.createGipsDoubleLiteral(); literal.setValue(value); return literal; } diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/BinaryValueNegation.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/BinaryValueNegation.java index cef8293a..09ac872b 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/BinaryValueNegation.java +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/BinaryValueNegation.java @@ -3,9 +3,9 @@ import java.util.Arrays; import java.util.Collection; -import org.emoflon.gips.gipsl.gipsl.GipsArithmeticLiteral; import org.emoflon.gips.gipsl.gipsl.GipsBooleanExpression; import org.emoflon.gips.gipsl.gipsl.GipsBooleanNegation; +import org.emoflon.gips.gipsl.gipsl.GipsIntegerLiteral; import org.emoflon.gips.gipsl.gipsl.GipsRelationalExpression; import org.emoflon.gips.gipsl.gipsl.GipsValueExpression; import org.emoflon.gips.gipsl.gipsl.RelationalOperator; @@ -34,7 +34,7 @@ public class BinaryValueNegation extends AbstractPatternMatcher { RelationalOperator.EQUAL, // this::matchLiteral); - public GipsArithmeticLiteral getLiteral() { + public GipsIntegerLiteral getLiteral() { return pattern.getLiteral(); } @@ -68,8 +68,8 @@ protected void tryMatchPattern(GipsBooleanExpression expression) { } - private boolean matchLiteral(String literal) { - return "1".equals(literal) || "0".equals(literal); + private boolean matchLiteral(Integer literal) { + return 1 == literal || 0 == literal; } private void matchNodes(GipsRelationalExpression expression) { diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutA.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutA.java index 8661b9a9..1ac0fdff 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutA.java +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutA.java @@ -32,12 +32,12 @@ public class EquivalenceShortcutA extends AbstractPatternMatcher { private final ValueConstantRelation isGreaterEqualPair = new ValueConstantRelation( // false, // RelationalOperator.GREATER_OR_EQUAL, // - c -> "1".equals(c)); + c -> 1 == c); private final ValueConstantRelation isEqualPair = new ValueConstantRelation( // false, // RelationalOperator.EQUAL, // - c -> "1".equals(c)); + c -> 1 == c); private final ImplicitBoolean isImplicitBool = new ImplicitBoolean(); diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutB.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutB.java index b2ea0aab..0227453b 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutB.java +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutB.java @@ -32,7 +32,7 @@ public class EquivalenceShortcutB extends AbstractPatternMatcher { private final ValueConstantRelation isRelationalPair = new ValueConstantRelation( // false, // RelationalOperator.EQUAL, // - c -> "1".equals(c)); + c -> 1 == c); public GipsArithmeticExpression getNodeA() { return nodeA; diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutC.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutC.java index e51b56ea..86016a05 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutC.java +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutC.java @@ -32,7 +32,7 @@ public class EquivalenceShortcutC extends AbstractPatternMatcher { private final ValueConstantRelation isRelationalPair = new ValueConstantRelation( // false, // RelationalOperator.EQUAL, // - c -> "1".equals(c)); + c -> 1 == c); public GipsArithmeticExpression getNodeA() { return nodeA; diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutD.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutD.java index da1b3bed..a2ed079d 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutD.java +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/EquivalenceShortcutD.java @@ -29,7 +29,7 @@ public class EquivalenceShortcutD extends AbstractPatternMatcher { private final ValueConstantRelation isRelationalPair = new ValueConstantRelation( // false, // RelationalOperator.EQUAL, // - c -> "0".equals(c) || "1".equals(c)); + c -> 0 == c || 1 == c); public GipsArithmeticExpression getNodeA() { return nodeA; @@ -57,27 +57,26 @@ public void tryMatchPattern(GipsBooleanExpression expression) { return; if (!hasMatch()) { - nodeA = matchNode(implication.getLeft(), "0"); - nodeB = matchNode(implication.getRight(), "1"); + nodeA = matchNode(implication.getLeft(), 0); + nodeB = matchNode(implication.getRight(), 1); clearPartialMatch(); } if (!hasMatch()) { - nodeA = matchNode(implication.getRight(), "0"); - nodeB = matchNode(implication.getLeft(), "1"); + nodeA = matchNode(implication.getRight(), 0); + nodeB = matchNode(implication.getLeft(), 1); clearPartialMatch(); } } - private GipsArithmeticExpression matchNode(GipsBooleanExpression expression, String expectedConstant) { + private GipsArithmeticExpression matchNode(GipsBooleanExpression expression, int expectedConstant) { expression = peelBrackets(expression); // A == c - if (isRelationalPair.matchPattern(expression) - && expectedConstant.equals(isRelationalPair.getLiteral().getValue())) + if (isRelationalPair.matchPattern(expression) && expectedConstant == isRelationalPair.getLiteral().getValue()) return isRelationalPair.getNodeA(); - boolean mustBeNegated = "0".equals(expectedConstant); + boolean mustBeNegated = 0 == expectedConstant; // A / !A if (isImplicitBool.matchPattern(expression) && mustBeNegated == isImplicitBool.isNegated()) diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/ImplicationShortcutA.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/ImplicationShortcutA.java index 6a5e71e3..afa1acff 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/ImplicationShortcutA.java +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/ImplicationShortcutA.java @@ -29,7 +29,7 @@ public class ImplicationShortcutA extends AbstractPatternMatcher { private final ValueConstantRelation isRelationalPair = new ValueConstantRelation( // false, // RelationalOperator.EQUAL, // - c -> "1".equals(c)); + c -> 1 == c); public GipsArithmeticExpression getNodeA() { return nodeA; diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/ValueConstantRelation.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/ValueConstantRelation.java index aa6a8238..3283ef67 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/ValueConstantRelation.java +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/special/pattern/ValueConstantRelation.java @@ -6,8 +6,8 @@ import java.util.Objects; import java.util.function.Predicate; -import org.emoflon.gips.gipsl.gipsl.GipsArithmeticLiteral; import org.emoflon.gips.gipsl.gipsl.GipsBooleanExpression; +import org.emoflon.gips.gipsl.gipsl.GipsIntegerLiteral; import org.emoflon.gips.gipsl.gipsl.GipsRelationalExpression; import org.emoflon.gips.gipsl.gipsl.GipsValueExpression; import org.emoflon.gips.gipsl.gipsl.RelationalOperator; @@ -20,14 +20,14 @@ public class ValueConstantRelation extends AbstractPatternMatcher { private final RelationalOperator matchOperator; private final RelationalOperator reversedmatchOperator; - private final Predicate matchConstant; + private final Predicate matchConstant; private final boolean onlyBinaries; private GipsValueExpression nodeA; - private GipsArithmeticLiteral literal; + private GipsIntegerLiteral literal; public ValueConstantRelation(boolean onlyBinaries, RelationalOperator matchOperator, - Predicate matchConstant) { + Predicate matchConstant) { this.onlyBinaries = onlyBinaries; this.matchOperator = Objects.requireNonNull(matchOperator); this.matchConstant = Objects.requireNonNull(matchConstant); @@ -41,7 +41,7 @@ public ValueConstantRelation(boolean onlyBinaries, RelationalOperator matchOpera }; } - public GipsArithmeticLiteral getLiteral() { + public GipsIntegerLiteral getLiteral() { return literal; } @@ -75,14 +75,14 @@ protected void tryMatchPattern(GipsBooleanExpression expression) { if (matchOperator == relational.getOperator()) { if (leftNode instanceof GipsValueExpression exp // - && rightNode instanceof GipsArithmeticLiteral literal // + && rightNode instanceof GipsIntegerLiteral literal // && matchConstant.test(literal.getValue())) { matchPair(exp, literal); } } else if (reversedmatchOperator == relational.getOperator()) { - if (leftNode instanceof GipsArithmeticLiteral literal // + if (leftNode instanceof GipsIntegerLiteral literal // && rightNode instanceof GipsValueExpression exp // && matchConstant.test(literal.getValue())) { @@ -92,7 +92,7 @@ protected void tryMatchPattern(GipsBooleanExpression expression) { } } - protected void matchPair(GipsValueExpression exp, GipsArithmeticLiteral literal) { + protected void matchPair(GipsValueExpression exp, GipsIntegerLiteral literal) { var type = GipslExpressionValidator.evaluate(exp, new LinkedList<>()); if (type.isScalar()) { if (onlyBinaries) { diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslMappingValidator.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslMappingValidator.java index 2bd1a2a1..80983b50 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslMappingValidator.java +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslMappingValidator.java @@ -42,6 +42,17 @@ public static void checkMapping(final GipsMapping mapping) { checkMappingValueInUse(mapping); } + public static void checkMappingVariable(final GipsMappingVariable variable) { + if (GipslValidator.DISABLE_VALIDATOR) + return; + + if (variable == null) + return; + + checkMappingVariableNameUnique(variable); + checkMappingVariableInUse(variable); + } + /** * Checks for validity of a mapping name. The name must not be on the list of * invalid names, the name should be in lowerCamelCase, and the name should diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java index 8cabaf0c..c7009109 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java @@ -16,8 +16,10 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.EcoreUtil2; import org.eclipse.xtext.resource.XtextResourceSet; @@ -29,6 +31,9 @@ import org.emoflon.gips.gipsl.gipsl.GipsConfig; import org.emoflon.gips.gipsl.gipsl.GipsConstant; import org.emoflon.gips.gipsl.gipsl.GipsConstraint; +import org.emoflon.gips.gipsl.gipsl.GipsDoubleLiteral; +import org.emoflon.gips.gipsl.gipsl.GipsIntegerLiteral; +import org.emoflon.gips.gipsl.gipsl.GipsInterval; import org.emoflon.gips.gipsl.gipsl.GipsJoinAllOperation; import org.emoflon.gips.gipsl.gipsl.GipsJoinBySelectionOperation; import org.emoflon.gips.gipsl.gipsl.GipsLinearFunction; @@ -42,6 +47,7 @@ import org.emoflon.gips.gipsl.gipsl.GipsTypeExtension; import org.emoflon.gips.gipsl.gipsl.GipsTypeExtensionVariable; import org.emoflon.gips.gipsl.gipsl.GipsTypeSelect; +import org.emoflon.gips.gipsl.gipsl.GipsVariable; import org.emoflon.gips.gipsl.gipsl.GipsVariableReferenceExpression; import org.emoflon.gips.gipsl.gipsl.GipslPackage; import org.emoflon.gips.gipsl.gipsl.ImportedPattern; @@ -374,14 +380,7 @@ public void checkMapping(final GipsMapping mapping) { @Check public void checkMappingVariable(final GipsMappingVariable variable) { - if (GipslValidator.DISABLE_VALIDATOR) { - return; - } - if (variable == null) { - return; - } - GipslMappingValidator.checkMappingVariableNameUnique(variable); - GipslMappingValidator.checkMappingVariableInUse(variable); + GipslMappingValidator.checkMappingVariable(variable); } @Check @@ -394,6 +393,49 @@ public void checkTypeExtensionVariable(final GipsTypeExtensionVariable variable) GipslTypeExtensionValidator.checkTypeExtensionVariable(variable); } + @Check + public void checkInterval(final GipsInterval interval) { + if (GipslValidator.DISABLE_VALIDATOR) + return; + + if (!interval.isLowerInfinity() && !interval.isUpperInfinity()) { + double lowerBound = switch (interval.getLowerBound()) { + case GipsDoubleLiteral val -> val.getValue(); + case GipsIntegerLiteral val -> val.getValue(); + default -> throw new IllegalArgumentException("Unexpected value: " + interval.getLowerBound()); + }; + + double upperBound = switch (interval.getUpperBound()) { + case GipsDoubleLiteral val -> val.getValue(); + case GipsIntegerLiteral val -> val.getValue(); + default -> throw new IllegalArgumentException("Unexpected value: " + interval.getLowerBound()); + }; + + if (Double.compare(lowerBound, upperBound) > 0) + GipslValidator.err( // + GipslValidatorUtil.VARIABLE_BOUNDS_LIMIT_ERROR, // + interval, // + GipslPackage.Literals.GIPS_VARIABLE__INTERVAL); + } + + // intervals cannot be used with booleans + + EObject container = interval.eContainer(); + if (container == null) + return; + + EDataType type = null; + if (container instanceof GipsVariable variable) + type = variable.getType(); + + if (type == EcorePackage.Literals.EBOOLEAN) { + GipslValidator.err(GipslValidatorUtil.VARIABLE_BOUNDS_SUPPORT_ERROR, // + interval, // + GipslPackage.Literals.GIPS_VARIABLE__INTERVAL); + } + + } + @Check public void checkConstant(final GipsConstant constant) { if (GipslValidator.DISABLE_VALIDATOR) { diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidatorUtil.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidatorUtil.java index 9b49eef3..dd5e7dff 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidatorUtil.java +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidatorUtil.java @@ -119,6 +119,9 @@ protected enum ContextType { public static final String TYPE_EXTENSION_VARIABLE_ATTRIBUTE_ALREADY_BOUND = "Variable '%s' in extension '%s' is already bound to this attribute."; public static final String TYPE_EXTENSION_VARIABLE_NOT_USED = "Variable '%s' is never used. No (M)ILP variable will be created for this variable."; + public static final String VARIABLE_BOUNDS_SUPPORT_ERROR = "Boolean does not support lower or upper bounds."; + public static final String VARIABLE_BOUNDS_LIMIT_ERROR = "The lower bound cannot be greater than the upper bound."; + public static final String FUNCTION_NAME_MULTIPLE_DECLARATIONS_MESSAGE = "Linear function '%s' must not be declared '%s' (case insensitive)"; public static final String FUNCTION_NAME_FORBIDDEN_MESSAGE = "Objectives cannot be be named '%s'. Use a different name."; public static final String FUNCTION_NAME_CONTAINS_UNDERSCORES_MESSAGE = "Objective name '%s' contains underscores. Use camelCase instead."; From c86d7cbf5d62bc0b388286eff8d45f5f298574b5 Mon Sep 17 00:00:00 2001 From: MarkBeB <177214717+MarkBeB@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:25:21 +0200 Subject: [PATCH 3/9] Improve validator --- .../validation/GipslIntervalValidator.java | 60 +++++++++++++++++++ .../gips/gipsl/validation/GipslValidator.java | 47 ++------------- .../validation/GipslVariableValidator.java | 33 ++++++++++ 3 files changed, 98 insertions(+), 42 deletions(-) create mode 100644 org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslIntervalValidator.java create mode 100644 org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslVariableValidator.java diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslIntervalValidator.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslIntervalValidator.java new file mode 100644 index 00000000..3ee3a710 --- /dev/null +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslIntervalValidator.java @@ -0,0 +1,60 @@ +package org.emoflon.gips.gipsl.validation; + +import org.emoflon.gips.gipsl.gipsl.GipsDoubleLiteral; +import org.emoflon.gips.gipsl.gipsl.GipsIntegerLiteral; +import org.emoflon.gips.gipsl.gipsl.GipsInterval; +import org.emoflon.gips.gipsl.gipsl.GipslPackage; + +public class GipslIntervalValidator { + private GipslIntervalValidator() { + + } + + public static void checkInterval(final GipsInterval interval) { + if (GipslValidator.DISABLE_VALIDATOR) + return; + + if (interval == null) + return; + + checkBounds(interval); + } + + private static void checkBounds(GipsInterval interval) { + if (!interval.isLowerInfinity() && interval.getLowerBound() == null) { + GipslValidator.err( // + "Lower bound not defined", // + interval, GipslPackage.Literals.GIPS_INTERVAL__LOWER_BOUND); + return; + } + + if (!interval.isUpperInfinity() && interval.getUpperBound() == null) { + GipslValidator.err( // + "Upper bound not defined", // + interval, GipslPackage.Literals.GIPS_INTERVAL__UPPER_BOUND); + return; + } + + if (!interval.isLowerInfinity() && !interval.isUpperInfinity()) { + double lowerBound = switch (interval.getLowerBound()) { + case GipsDoubleLiteral val -> val.getValue(); + case GipsIntegerLiteral val -> val.getValue(); + case null, default -> throw new IllegalArgumentException("Unexpected value: " + interval.getLowerBound()); + }; + + double upperBound = switch (interval.getUpperBound()) { + case GipsDoubleLiteral val -> val.getValue(); + case GipsIntegerLiteral val -> val.getValue(); + case null, default -> throw new IllegalArgumentException("Unexpected value: " + interval.getLowerBound()); + }; + + if (Double.compare(lowerBound, upperBound) > 0) { + GipslValidator.err( // + GipslValidatorUtil.VARIABLE_BOUNDS_LIMIT_ERROR, // + interval, // + GipslPackage.Literals.GIPS_INTERVAL__LOWER_BOUND); + return; + } + } + } +} diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java index c7009109..e3bd9c11 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java @@ -16,10 +16,8 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.EcoreUtil2; import org.eclipse.xtext.resource.XtextResourceSet; @@ -31,8 +29,6 @@ import org.emoflon.gips.gipsl.gipsl.GipsConfig; import org.emoflon.gips.gipsl.gipsl.GipsConstant; import org.emoflon.gips.gipsl.gipsl.GipsConstraint; -import org.emoflon.gips.gipsl.gipsl.GipsDoubleLiteral; -import org.emoflon.gips.gipsl.gipsl.GipsIntegerLiteral; import org.emoflon.gips.gipsl.gipsl.GipsInterval; import org.emoflon.gips.gipsl.gipsl.GipsJoinAllOperation; import org.emoflon.gips.gipsl.gipsl.GipsJoinBySelectionOperation; @@ -395,45 +391,12 @@ public void checkTypeExtensionVariable(final GipsTypeExtensionVariable variable) @Check public void checkInterval(final GipsInterval interval) { - if (GipslValidator.DISABLE_VALIDATOR) - return; - - if (!interval.isLowerInfinity() && !interval.isUpperInfinity()) { - double lowerBound = switch (interval.getLowerBound()) { - case GipsDoubleLiteral val -> val.getValue(); - case GipsIntegerLiteral val -> val.getValue(); - default -> throw new IllegalArgumentException("Unexpected value: " + interval.getLowerBound()); - }; - - double upperBound = switch (interval.getUpperBound()) { - case GipsDoubleLiteral val -> val.getValue(); - case GipsIntegerLiteral val -> val.getValue(); - default -> throw new IllegalArgumentException("Unexpected value: " + interval.getLowerBound()); - }; - - if (Double.compare(lowerBound, upperBound) > 0) - GipslValidator.err( // - GipslValidatorUtil.VARIABLE_BOUNDS_LIMIT_ERROR, // - interval, // - GipslPackage.Literals.GIPS_VARIABLE__INTERVAL); - } - - // intervals cannot be used with booleans - - EObject container = interval.eContainer(); - if (container == null) - return; - - EDataType type = null; - if (container instanceof GipsVariable variable) - type = variable.getType(); - - if (type == EcorePackage.Literals.EBOOLEAN) { - GipslValidator.err(GipslValidatorUtil.VARIABLE_BOUNDS_SUPPORT_ERROR, // - interval, // - GipslPackage.Literals.GIPS_VARIABLE__INTERVAL); - } + GipslIntervalValidator.checkInterval(interval); + } + @Check + public void checkInterval(final GipsVariable variable) { + GipslVariableValidator.checkVariable(variable); } @Check diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslVariableValidator.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslVariableValidator.java new file mode 100644 index 00000000..fb73a301 --- /dev/null +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslVariableValidator.java @@ -0,0 +1,33 @@ +package org.emoflon.gips.gipsl.validation; + +import org.eclipse.emf.ecore.EcorePackage; +import org.emoflon.gips.gipsl.gipsl.GipsVariable; +import org.emoflon.gips.gipsl.gipsl.GipslPackage; + +public class GipslVariableValidator { + private GipslVariableValidator() { + + } + + public static void checkVariable(final GipsVariable variable) { + if (GipslValidator.DISABLE_VALIDATOR) + return; + + if (variable == null) + return; + + checkBounds(variable); + } + + private static void checkBounds(GipsVariable variable) { + if (variable.getInterval() == null) + return; + + if (variable.getType() == EcorePackage.Literals.EBOOLEAN) { + GipslValidator.err(GipslValidatorUtil.VARIABLE_BOUNDS_SUPPORT_ERROR, // + variable, // + GipslPackage.Literals.GIPS_VARIABLE__INTERVAL); + } + } + +} From 41c560e6933de2af07a836b0e85681c4b90ceebf Mon Sep 17 00:00:00 2001 From: MarkBeB <177214717+MarkBeB@users.noreply.github.com> Date: Thu, 20 Aug 2026 10:53:30 +0200 Subject: [PATCH 4/9] xtext update --- org.emoflon.gips.gipsl/model/generated/Gipsl.genmodel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.emoflon.gips.gipsl/model/generated/Gipsl.genmodel b/org.emoflon.gips.gipsl/model/generated/Gipsl.genmodel index 053ae1f2..06571e64 100644 --- a/org.emoflon.gips.gipsl/model/generated/Gipsl.genmodel +++ b/org.emoflon.gips.gipsl/model/generated/Gipsl.genmodel @@ -1,6 +1,6 @@ From d1cf738fc21bfa475232749d3560e3460f77bed6 Mon Sep 17 00:00:00 2001 From: MarkBeB <177214717+MarkBeB@users.noreply.github.com> Date: Thu, 20 Aug 2026 14:00:57 +0200 Subject: [PATCH 5/9] Allow bounds to be set on EBooleans --- .../gips/gipsl/validation/GipslValidator.java | 6 ---- .../validation/GipslVariableValidator.java | 33 ------------------- 2 files changed, 39 deletions(-) delete mode 100644 org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslVariableValidator.java diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java index e3bd9c11..859d4f69 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java @@ -43,7 +43,6 @@ import org.emoflon.gips.gipsl.gipsl.GipsTypeExtension; import org.emoflon.gips.gipsl.gipsl.GipsTypeExtensionVariable; import org.emoflon.gips.gipsl.gipsl.GipsTypeSelect; -import org.emoflon.gips.gipsl.gipsl.GipsVariable; import org.emoflon.gips.gipsl.gipsl.GipsVariableReferenceExpression; import org.emoflon.gips.gipsl.gipsl.GipslPackage; import org.emoflon.gips.gipsl.gipsl.ImportedPattern; @@ -394,11 +393,6 @@ public void checkInterval(final GipsInterval interval) { GipslIntervalValidator.checkInterval(interval); } - @Check - public void checkInterval(final GipsVariable variable) { - GipslVariableValidator.checkVariable(variable); - } - @Check public void checkConstant(final GipsConstant constant) { if (GipslValidator.DISABLE_VALIDATOR) { diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslVariableValidator.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslVariableValidator.java deleted file mode 100644 index fb73a301..00000000 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslVariableValidator.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.emoflon.gips.gipsl.validation; - -import org.eclipse.emf.ecore.EcorePackage; -import org.emoflon.gips.gipsl.gipsl.GipsVariable; -import org.emoflon.gips.gipsl.gipsl.GipslPackage; - -public class GipslVariableValidator { - private GipslVariableValidator() { - - } - - public static void checkVariable(final GipsVariable variable) { - if (GipslValidator.DISABLE_VALIDATOR) - return; - - if (variable == null) - return; - - checkBounds(variable); - } - - private static void checkBounds(GipsVariable variable) { - if (variable.getInterval() == null) - return; - - if (variable.getType() == EcorePackage.Literals.EBOOLEAN) { - GipslValidator.err(GipslValidatorUtil.VARIABLE_BOUNDS_SUPPORT_ERROR, // - variable, // - GipslPackage.Literals.GIPS_VARIABLE__INTERVAL); - } - } - -} From f53b460dc6dbb5ee524338169937e105275cc9d7 Mon Sep 17 00:00:00 2001 From: MarkBeB <177214717+MarkBeB@users.noreply.github.com> Date: Thu, 20 Aug 2026 14:35:45 +0200 Subject: [PATCH 6/9] Revert "Allow bounds to be set on EBooleans" This reverts commit d1cf738fc21bfa475232749d3560e3460f77bed6. --- .../gips/gipsl/validation/GipslValidator.java | 6 ++++ .../validation/GipslVariableValidator.java | 35 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslVariableValidator.java diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java index 859d4f69..e3bd9c11 100644 --- a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslValidator.java @@ -43,6 +43,7 @@ import org.emoflon.gips.gipsl.gipsl.GipsTypeExtension; import org.emoflon.gips.gipsl.gipsl.GipsTypeExtensionVariable; import org.emoflon.gips.gipsl.gipsl.GipsTypeSelect; +import org.emoflon.gips.gipsl.gipsl.GipsVariable; import org.emoflon.gips.gipsl.gipsl.GipsVariableReferenceExpression; import org.emoflon.gips.gipsl.gipsl.GipslPackage; import org.emoflon.gips.gipsl.gipsl.ImportedPattern; @@ -393,6 +394,11 @@ public void checkInterval(final GipsInterval interval) { GipslIntervalValidator.checkInterval(interval); } + @Check + public void checkInterval(final GipsVariable variable) { + GipslVariableValidator.checkVariable(variable); + } + @Check public void checkConstant(final GipsConstant constant) { if (GipslValidator.DISABLE_VALIDATOR) { diff --git a/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslVariableValidator.java b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslVariableValidator.java new file mode 100644 index 00000000..14503658 --- /dev/null +++ b/org.emoflon.gips.gipsl/src/org/emoflon/gips/gipsl/validation/GipslVariableValidator.java @@ -0,0 +1,35 @@ +package org.emoflon.gips.gipsl.validation; + +import org.eclipse.emf.ecore.EcorePackage; +import org.emoflon.gips.gipsl.gipsl.GipsVariable; +import org.emoflon.gips.gipsl.gipsl.GipslPackage; + +public class GipslVariableValidator { + private GipslVariableValidator() { + + } + + public static void checkVariable(final GipsVariable variable) { + if (GipslValidator.DISABLE_VALIDATOR) + return; + + if (variable == null) + return; + + checkBounds(variable); + } + + private static void checkBounds(GipsVariable variable) { + if (variable.getInterval() == null) + return; + + // A binary type can only have bounds of 0 and 1, otherwise it is no longer + // binary or can take on a value that is atypical or unexpected for a binary. + if (variable.getType() == EcorePackage.Literals.EBOOLEAN) { + GipslValidator.err(GipslValidatorUtil.VARIABLE_BOUNDS_SUPPORT_ERROR, // + variable, // + GipslPackage.Literals.GIPS_VARIABLE__INTERVAL); + } + } + +} From e82f98014674601fe3a2a1bd969dfba818f1910d Mon Sep 17 00:00:00 2001 From: MarkBeB <177214717+MarkBeB@users.noreply.github.com> Date: Thu, 20 Aug 2026 17:14:14 +0200 Subject: [PATCH 7/9] Add upper/lower bounds to mapping variables (code generator) --- .../templates/RuleMappingTemplate.xtend | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/org.emoflon.gips.build/src/org/emoflon/gips/build/generator/templates/RuleMappingTemplate.xtend b/org.emoflon.gips.build/src/org/emoflon/gips/build/generator/templates/RuleMappingTemplate.xtend index ab4da0aa..803719f6 100644 --- a/org.emoflon.gips.build/src/org/emoflon/gips/build/generator/templates/RuleMappingTemplate.xtend +++ b/org.emoflon.gips.build/src/org/emoflon/gips/build/generator/templates/RuleMappingTemplate.xtend @@ -52,18 +52,22 @@ class RuleMappingTemplate extends ClassGeneratorTemplate { «ENDIF» public «className»(final String milpVariable, final boolean hasBinaryVariable, final «data.mapping2matchClassName.get(context)» match) { - super(milpVariable, hasBinaryVariable, match); + super(milpVariable, hasBinaryVariable, match); + + «IF !context.freeVariables.isNullOrEmpty» + «FOR v : context.freeVariables» + «v.name.toFirstLower» = new «GipsImportManager.variableToJavaDataType(v, imports)»(name + "->«v.name»"); + «v.name.toFirstLower».setUpperBound(«v.upperBound»); + «v.name.toFirstLower».setLowerBound(«v.lowerBound»); + «ENDFOR» + «ENDIF» - «IF !context.freeVariables.isNullOrEmpty» - «FOR v : context.freeVariables» - «v.name.toFirstLower» = new «GipsImportManager.variableToJavaDataType(v, imports)»(name + "->«v.name»"); - «ENDFOR» - «ENDIF» - «IF !context.boundVariables.isNullOrEmpty» - «FOR v : context.boundVariables» - «v.name.toFirstLower» = new «GipsImportManager.variableToJavaDataType(v, imports)»(name + "->«v.name»"); - «ENDFOR» + «FOR v : context.boundVariables» + «v.name.toFirstLower» = new «GipsImportManager.variableToJavaDataType(v, imports)»(name + "->«v.name»"); + «v.name.toFirstLower».setUpperBound(«v.upperBound»); + «v.name.toFirstLower».setLowerBound(«v.lowerBound»); + «ENDFOR» «ENDIF» } From 0a62c9fad3cc02777caff18e5903d2651f3e03dc Mon Sep 17 00:00:00 2001 From: MarkBeB <177214717+MarkBeB@users.noreply.github.com> Date: Wed, 26 Aug 2026 23:03:03 +0200 Subject: [PATCH 8/9] Cast upper/lower bound to int for integer/binary variables --- .../templates/RuleMappingTemplate.xtend | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/org.emoflon.gips.build/src/org/emoflon/gips/build/generator/templates/RuleMappingTemplate.xtend b/org.emoflon.gips.build/src/org/emoflon/gips/build/generator/templates/RuleMappingTemplate.xtend index 803719f6..dc6cbbb6 100644 --- a/org.emoflon.gips.build/src/org/emoflon/gips/build/generator/templates/RuleMappingTemplate.xtend +++ b/org.emoflon.gips.build/src/org/emoflon/gips/build/generator/templates/RuleMappingTemplate.xtend @@ -6,6 +6,7 @@ import org.emoflon.gips.intermediate.GipsIntermediate.RuleMapping import org.emoflon.gips.intermediate.GipsIntermediate.VariableType import org.emoflon.ibex.patternmodel.IBeXPatternModel.IBeXContextAlternatives import org.emoflon.ibex.patternmodel.IBeXPatternModel.IBeXContextPattern +import org.eclipse.xtend.core.richstring.EndIf class RuleMappingTemplate extends ClassGeneratorTemplate { @@ -57,16 +58,26 @@ class RuleMappingTemplate extends ClassGeneratorTemplate { «IF !context.freeVariables.isNullOrEmpty» «FOR v : context.freeVariables» «v.name.toFirstLower» = new «GipsImportManager.variableToJavaDataType(v, imports)»(name + "->«v.name»"); - «v.name.toFirstLower».setUpperBound(«v.upperBound»); - «v.name.toFirstLower».setLowerBound(«v.lowerBound»); + «IF v.type === VariableType.REAL» + «v.name.toFirstLower».setUpperBound(«v.upperBound»); + «v.name.toFirstLower».setLowerBound(«v.lowerBound»); + «ELSE» + «v.name.toFirstLower».setUpperBound((int)«v.upperBound»); + «v.name.toFirstLower».setLowerBound((int)«v.lowerBound»); + «ENDIF» «ENDFOR» «ENDIF» «IF !context.boundVariables.isNullOrEmpty» «FOR v : context.boundVariables» «v.name.toFirstLower» = new «GipsImportManager.variableToJavaDataType(v, imports)»(name + "->«v.name»"); - «v.name.toFirstLower».setUpperBound(«v.upperBound»); - «v.name.toFirstLower».setLowerBound(«v.lowerBound»); + «IF v.type === VariableType.REAL» + «v.name.toFirstLower».setUpperBound(«v.upperBound»); + «v.name.toFirstLower».setLowerBound(«v.lowerBound»); + «ELSE» + «v.name.toFirstLower».setUpperBound((int)«v.upperBound»); + «v.name.toFirstLower».setLowerBound((int)«v.lowerBound»); + «ENDIF» «ENDFOR» «ENDIF» } From a6475fbea1ab79996c79961ccbff8752a04ba63b Mon Sep 17 00:00:00 2001 From: MarkBeB <177214717+MarkBeB@users.noreply.github.com> Date: Thu, 27 Aug 2026 14:17:44 +0200 Subject: [PATCH 9/9] Compute max/min bounds for ints --- .../helper/GipsTransformationUtils.java | 90 ++++++++++++++----- 1 file changed, 66 insertions(+), 24 deletions(-) diff --git a/org.emoflon.gips.build/src/org/emoflon/gips/build/transformation/helper/GipsTransformationUtils.java b/org.emoflon.gips.build/src/org/emoflon/gips/build/transformation/helper/GipsTransformationUtils.java index 3474f965..f4feedce 100644 --- a/org.emoflon.gips.build/src/org/emoflon/gips/build/transformation/helper/GipsTransformationUtils.java +++ b/org.emoflon.gips.build/src/org/emoflon/gips/build/transformation/helper/GipsTransformationUtils.java @@ -313,39 +313,21 @@ public static Set extractConstantReference(final RelationalEx } public static double getUpperBound(final GipsVariable gipsVar, final VariableType type) { - if (type == VariableType.BINARY) - return 1; - if (gipsVar.getInterval() != null && !gipsVar.getInterval().isUpperInfinity()) { - return getValue(gipsVar.getInterval().getUpperBound()); - - } else if (type == VariableType.INTEGER) { - return Integer.MAX_VALUE; - - } else if (type == VariableType.REAL) { - return Double.MAX_VALUE; - + var upperBound = getValue(gipsVar.getInterval().getUpperBound()); + return getLeastUpperBound(upperBound, type); } - throw new UnsupportedOperationException(); + return getMaxValue(type); } public static double getLowerBound(final GipsVariable gipsVar, final VariableType type) { - if (type == VariableType.BINARY) - return 0; - if (gipsVar.getInterval() != null && !gipsVar.getInterval().isLowerInfinity()) { - return getValue(gipsVar.getInterval().getLowerBound()); - - } else if (type == VariableType.INTEGER) { - return Integer.MIN_VALUE; - - } else if (type == VariableType.REAL) { - return -Double.MAX_VALUE; - + var lowerBound = getValue(gipsVar.getInterval().getLowerBound()); + return getGreatestLowerBound(lowerBound, type); } - throw new UnsupportedOperationException(); + return getMinValue(type); } private static double getValue(final GipsArithmeticLiteral literal) { @@ -356,6 +338,66 @@ private static double getValue(final GipsArithmeticLiteral literal) { }; } + public static double getLeastUpperBound(double upperBound, VariableType type) { + if (Double.isNaN(upperBound)) + throw new IllegalArgumentException("Boundary value cannot be NaN."); + + return switch (type) { + case BINARY -> getMaxValue(VariableType.BINARY); + case REAL -> upperBound; + case INTEGER -> { + double floored = Math.floor(upperBound); + if (floored <= getMinValue(VariableType.INTEGER)) + yield getMinValue(VariableType.INTEGER); + + if (floored >= getMaxValue(VariableType.INTEGER)) + yield getMaxValue(VariableType.INTEGER); + + yield floored; + } + default -> throw new IllegalArgumentException("Unexpected value: " + type); + }; + } + + public static double getGreatestLowerBound(double lowerBound, VariableType type) { + if (Double.isNaN(lowerBound)) + throw new IllegalArgumentException("Boundary value cannot be NaN."); + + return switch (type) { + case BINARY -> getMinValue(VariableType.BINARY); + case REAL -> lowerBound; + case INTEGER -> { + double ceiled = Math.ceil(lowerBound); + if (ceiled <= getMinValue(VariableType.INTEGER)) + yield getMinValue(VariableType.INTEGER); + + if (ceiled >= getMaxValue(VariableType.INTEGER)) + yield getMaxValue(VariableType.INTEGER); + + yield ceiled; + } + default -> throw new IllegalArgumentException("Unexpected value: " + type); + }; + } + + public static double getMaxValue(VariableType type) { + return switch (type) { + case BINARY -> 1.0; + case INTEGER -> Integer.MAX_VALUE; + case REAL -> Double.MAX_VALUE; + default -> throw new IllegalArgumentException("Unexpected value: " + type); + }; + } + + public static double getMinValue(VariableType type) { + return switch (type) { + case BINARY -> 0.0; + case INTEGER -> Integer.MIN_VALUE; + case REAL -> -Double.MAX_VALUE; + default -> throw new IllegalArgumentException("Unexpected value: " + type); + }; + } + public static ExpressionReturnType extractReturnType(BooleanExpression expression) { return ExpressionReturnTypeResolver.extractReturnType(expression); }