diff --git a/gipsl.all.build.boolexpr/.classpath b/gipsl.all.build.boolexpr/.classpath
new file mode 100644
index 00000000..0b423a2c
--- /dev/null
+++ b/gipsl.all.build.boolexpr/.classpath
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/gipsl.all.build.boolexpr/.project b/gipsl.all.build.boolexpr/.project
new file mode 100644
index 00000000..62ae14e1
--- /dev/null
+++ b/gipsl.all.build.boolexpr/.project
@@ -0,0 +1,25 @@
+
+
+ gipsl.all.build.boolexpr
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextBuilder
+
+
+
+
+
+ org.emoflon.gips.gipsl.ui.gipsNature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.pde.PluginNature
+ org.eclipse.xtext.ui.shared.xtextNature
+
+
diff --git a/gipsl.all.build.boolexpr/.settings/org.eclipse.jdt.core.prefs b/gipsl.all.build.boolexpr/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..3a79233b
--- /dev/null
+++ b/gipsl.all.build.boolexpr/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,10 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
+org.eclipse.jdt.core.compiler.compliance=21
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=21
diff --git a/gipsl.all.build.boolexpr/META-INF/MANIFEST.MF b/gipsl.all.build.boolexpr/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..3c0d0d6b
--- /dev/null
+++ b/gipsl.all.build.boolexpr/META-INF/MANIFEST.MF
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Automatic-Module-Name: gipsl.all.build.boolexpr
+Bundle-ManifestVersion: 2
+Bundle-Name: gipsl.all.build.boolexpr
+Bundle-Vendor: My Company
+Bundle-Version: 1.0.0.qualifier
+Export-Package: gipsl.all.build.boolexpr.connector
+Import-Package: test.suite.gips.utils
+Require-Bundle: gipsl.all.build.model;bundle-version="0.0.1",
+ org.emoflon.ibex.common,
+ org.emoflon.ibex.gt,
+ org.emoflon.gips.core,
+ org.emoflon.ibex.gt.democles,
+ org.emoflon.ibex.gt.hipe
+Bundle-SymbolicName: gipsl.all.build.boolexpr; singleton:=true
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-21
diff --git a/gipsl.all.build.boolexpr/build.properties b/gipsl.all.build.boolexpr/build.properties
new file mode 100644
index 00000000..14acfb7c
--- /dev/null
+++ b/gipsl.all.build.boolexpr/build.properties
@@ -0,0 +1,5 @@
+source.. = src/,\
+ src-gen/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml
diff --git a/gipsl.all.build.boolexpr/src/gipsl/all/build/boolexpr/Model.gipsl b/gipsl.all.build.boolexpr/src/gipsl/all/build/boolexpr/Model.gipsl
new file mode 100644
index 00000000..e4cdc90d
--- /dev/null
+++ b/gipsl.all.build.boolexpr/src/gipsl/all/build/boolexpr/Model.gipsl
@@ -0,0 +1,35 @@
+package "gipsl.all.build.boolexpr"
+import "platform:/resource/gipsl.all.build.model/model/Model.ecore"
+
+config {
+ solver := GUROBI [home:="fu", license:="bar"];
+ launchConfig := true [main := "TODO"];
+ timeLimit := true [value := 10.0];
+ randomSeed := true [value := 0];
+ presolve := true;
+ debugOutput := false;
+}
+
+pattern snode {
+ snode: SubstrateResourceNode
+}
+
+//
+// GIPSL starts here!
+//
+
+mapping sn with snode;
+
+constraint -> class::SubstrateResourceNode {
+ [self.resourceAmountAvailable == 1]
+ ==
+ [mappings.sn->filter(m | m.nodes().snode == self)->count() >= 1]
+}
+
+objective o -> mapping::sn {
+ 1
+}
+
+global objective : max {
+ o
+}
diff --git a/gipsl.all.build.boolexpr/src/gipsl/all/build/boolexpr/connector/BoolExprConnector.java b/gipsl.all.build.boolexpr/src/gipsl/all/build/boolexpr/connector/BoolExprConnector.java
new file mode 100644
index 00000000..730290a5
--- /dev/null
+++ b/gipsl.all.build.boolexpr/src/gipsl/all/build/boolexpr/connector/BoolExprConnector.java
@@ -0,0 +1,22 @@
+package gipsl.all.build.boolexpr.connector;
+
+import org.emoflon.gips.core.ilp.ILPSolverOutput;
+
+import gipsl.all.build.boolexpr.api.gips.BoolexprGipsAPI;
+import test.suite.gips.utils.AConnector;
+import test.suite.gips.utils.GipsTestUtils;
+
+public class BoolExprConnector extends AConnector {
+
+ public BoolExprConnector(final String modelPath) {
+ api = new BoolexprGipsAPI();
+ api.init(GipsTestUtils.pathToAbsUri(modelPath));
+ }
+
+ @Override
+ public ILPSolverOutput run(final String outputPath) {
+ final ILPSolverOutput output = solve();
+ return output;
+ }
+
+}
diff --git a/test.suite.gips/META-INF/MANIFEST.MF b/test.suite.gips/META-INF/MANIFEST.MF
index 51389bf6..4ae0dc52 100644
--- a/test.suite.gips/META-INF/MANIFEST.MF
+++ b/test.suite.gips/META-INF/MANIFEST.MF
@@ -34,6 +34,7 @@ Import-Package: gips.enumequals.connector,
gips.xmiinit.connector,
gipsl.all.build.and.connector,
gipsl.all.build.booleanbrackets.connector,
+ gipsl.all.build.boolexpr.connector,
gipsl.all.build.count.connector,
gipsl.all.build.filter.connector,
gipsl.all.build.implication.connector,
diff --git a/test.suite.gips/src/test/suite/gipsl/all/build/GipslAllBuildBoolExprTest.java b/test.suite.gips/src/test/suite/gipsl/all/build/GipslAllBuildBoolExprTest.java
new file mode 100644
index 00000000..b50eced3
--- /dev/null
+++ b/test.suite.gips/src/test/suite/gipsl/all/build/GipslAllBuildBoolExprTest.java
@@ -0,0 +1,54 @@
+package test.suite.gipsl.all.build;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.emoflon.gips.core.ilp.ILPSolverOutput;
+import org.emoflon.gips.core.ilp.ILPSolverStatus;
+import org.junit.jupiter.api.Test;
+
+import gipsl.all.build.booleanbrackets.connector.BooleanBracketsConnector;
+
+public class GipslAllBuildBoolExprTest extends AGipslAllBuildTest {
+
+ // Setup method
+
+ public void callableSetUp() {
+ gen.persistModel(MODEL_PATH);
+ con = new BooleanBracketsConnector(MODEL_PATH);
+ }
+
+ // Actual tests
+
+ @Test
+ public void testStaticVal1() {
+ // Static value 1 -> Mapping must be chosen
+ gen.genSubstrateNode("s1", 1);
+ callableSetUp();
+
+ final ILPSolverOutput ret = con.run(OUTPUT_PATH);
+ assertEquals(ILPSolverStatus.OPTIMAL, ret.status());
+ assertEquals(1, Math.abs(ret.solutionCount()));
+ }
+
+ @Test
+ public void testStaticVal0() {
+ // Static value = 0 -> Mapping must not be chosen
+ gen.genSubstrateNode("s1", 0);
+ callableSetUp();
+
+ final ILPSolverOutput ret = con.run(OUTPUT_PATH);
+ assertEquals(ILPSolverStatus.OPTIMAL, ret.status());
+ assertEquals(0, Math.abs(ret.solutionCount()));
+ }
+
+ @Test
+ public void testStaticNoNode() {
+ // No SubstrateResourceNode -> No constraint generated
+ callableSetUp();
+
+ final ILPSolverOutput ret = con.run(OUTPUT_PATH);
+ assertEquals(ILPSolverStatus.OPTIMAL, ret.status());
+ assertEquals(1, Math.abs(ret.solutionCount()));
+ }
+
+}