aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects')
-rw-r--r--subprojects/docs/build.gradle.kts81
-rw-r--r--subprojects/docs/docusaurus.config.ts546
-rw-r--r--subprojects/docs/package.json51
-rw-r--r--subprojects/docs/sidebars.ts22
-rw-r--r--subprojects/docs/src/components/ResponsiveImage/ImageTag.tsx29
-rw-r--r--subprojects/docs/src/components/ResponsiveImage/SVG/index.module.css11
-rw-r--r--subprojects/docs/src/components/ResponsiveImage/SVG/index.tsx36
-rw-r--r--subprojects/docs/src/components/ResponsiveImage/Themed.tsx67
-rw-r--r--subprojects/docs/src/components/ResponsiveImage/index.module.css37
-rw-r--r--subprojects/docs/src/components/ResponsiveImage/index.tsx34
-rw-r--r--subprojects/docs/src/components/ResponsiveImage/maxWidth.ts15
-rw-r--r--subprojects/docs/src/components/TryInRefinery.tsx20
-rw-r--r--subprojects/docs/src/components/UseCases/index.tsx2
-rw-r--r--subprojects/docs/src/css/custom.css28
-rw-r--r--subprojects/docs/src/develop/index.md13
-rw-r--r--subprojects/docs/src/develop/javadoc.md40
-rw-r--r--subprojects/docs/src/docs/develop/contributing/commands.md (renamed from subprojects/docs/src/develop/contributing/commands.md)36
-rw-r--r--subprojects/docs/src/docs/develop/contributing/ide-setup.md (renamed from subprojects/docs/src/develop/contributing/ide-setup.md)14
-rw-r--r--subprojects/docs/src/docs/develop/contributing/index.md (renamed from subprojects/docs/src/develop/contributing/index.md)0
-rw-r--r--subprojects/docs/src/docs/develop/java.md460
-rw-r--r--subprojects/docs/src/docs/develop/javadoc.md41
-rw-r--r--subprojects/docs/src/docs/learn/docker/cli.md145
-rw-r--r--subprojects/docs/src/docs/learn/docker/index.md165
-rw-r--r--subprojects/docs/src/docs/learn/index.md11
-rw-r--r--subprojects/docs/src/docs/learn/language/_category_.yml (renamed from subprojects/docs/src/learn/language/_category_.yml)2
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/ContainmentInstance.svg (renamed from subprojects/docs/src/learn/language/classes/ContainmentInstance.svg)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/ContainmentInstance.svg.license (renamed from subprojects/docs/src/learn/language/classes/ContainmentInstance.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/InvalidInstance.svg (renamed from subprojects/docs/src/learn/language/classes/InvalidInstance.svg)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/InvalidInstance.svg.license (renamed from subprojects/docs/src/learn/language/classes/InvalidInstance.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/MultiplicityConstraintsInstance.svg (renamed from subprojects/docs/src/learn/language/classes/MultiplicityConstraintsInstance.svg)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/MultiplicityConstraintsInstance.svg.license (renamed from subprojects/docs/src/learn/language/classes/MultiplicityConstraintsInstance.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/NewObjectsSimple.svg (renamed from subprojects/docs/src/learn/language/classes/NewObjectsSimple.svg)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/NewObjectsSimple.svg.license (renamed from subprojects/docs/src/learn/language/classes/NewObjectsSimple.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/NewObjectsWithInheritance.svg (renamed from subprojects/docs/src/learn/language/classes/NewObjectsWithInheritance.svg)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/NewObjectsWithInheritance.svg.license (renamed from subprojects/docs/src/learn/language/classes/NewObjectsWithInheritance.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeInstance.svg (renamed from subprojects/docs/src/learn/language/classes/ReferencesOppositeInstance.svg)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeInstance.svg.license (renamed from subprojects/docs/src/learn/language/classes/ReferencesOppositeInstance.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeSelf.svg (renamed from subprojects/docs/src/learn/language/classes/ReferencesOppositeSelf.svg)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeSelf.svg.license (renamed from subprojects/docs/src/learn/language/classes/ReferencesOppositeSelf.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/ReferencesSimple.svg (renamed from subprojects/docs/src/learn/language/classes/ReferencesSimple.svg)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/ReferencesSimple.svg.license (renamed from subprojects/docs/src/learn/language/classes/ReferencesSimple.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/language/classes/index.md (renamed from subprojects/docs/src/learn/language/classes/index.md)7
-rw-r--r--subprojects/docs/src/docs/learn/language/logic/AssertionsError.svg (renamed from subprojects/docs/src/learn/language/logic/AssertionsError.svg)0
-rw-r--r--subprojects/docs/src/docs/learn/language/logic/AssertionsError.svg.license (renamed from subprojects/docs/src/learn/language/logic/AssertionsError.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/language/logic/AssertionsExample.svg (renamed from subprojects/docs/src/learn/language/logic/AssertionsExample.svg)0
-rw-r--r--subprojects/docs/src/docs/learn/language/logic/AssertionsExample.svg.license (renamed from subprojects/docs/src/learn/language/logic/AssertionsExample.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/language/logic/DefaultAssertions.svg (renamed from subprojects/docs/src/learn/language/logic/DefaultAssertions.svg)0
-rw-r--r--subprojects/docs/src/docs/learn/language/logic/DefaultAssertions.svg.license (renamed from subprojects/docs/src/learn/language/logic/DefaultAssertions.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/language/logic/MultiObjects.svg (renamed from subprojects/docs/src/learn/language/logic/MultiObjects.svg)0
-rw-r--r--subprojects/docs/src/docs/learn/language/logic/MultiObjects.svg.license (renamed from subprojects/docs/src/learn/language/logic/MultiObjects.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/language/logic/ObjectScopes.svg (renamed from subprojects/docs/src/learn/language/logic/ObjectScopes.svg)0
-rw-r--r--subprojects/docs/src/docs/learn/language/logic/ObjectScopes.svg.license (renamed from subprojects/docs/src/learn/language/logic/ObjectScopes.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/language/logic/StrongerObjectScopes.svg (renamed from subprojects/docs/src/learn/language/logic/StrongerObjectScopes.svg)0
-rw-r--r--subprojects/docs/src/docs/learn/language/logic/StrongerObjectScopes.svg.license (renamed from subprojects/docs/src/learn/language/logic/StrongerObjectScopes.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/language/logic/index.md (renamed from subprojects/docs/src/learn/language/logic/index.md)0
-rw-r--r--subprojects/docs/src/docs/learn/language/predicates/DerivedFeature.svg (renamed from subprojects/docs/src/learn/language/predicates/DerivedFeature.svg)0
-rw-r--r--subprojects/docs/src/docs/learn/language/predicates/DerivedFeature.svg.license (renamed from subprojects/docs/src/learn/language/predicates/DerivedFeature.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/language/predicates/index.md (renamed from subprojects/docs/src/learn/language/predicates/index.md)0
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/_category_.yml (renamed from subprojects/docs/src/learn/tutorials/_category_.yml)2
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/filterPanelDark.pngbin0 -> 38761 bytes
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/filterPanelDark.png.license (renamed from subprojects/docs/src/learn/tutorials/file-system/fig1.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/filterPanelLight.pngbin0 -> 40181 bytes
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/filterPanelLight.png.license (renamed from subprojects/docs/src/learn/tutorials/file-system/fig2.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/generatedModel1.svg254
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/generatedModel1.svg.license (renamed from subprojects/docs/src/learn/tutorials/file-system/fig3.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/generatedModel1Simplified.svg188
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/generatedModel1Simplified.svg.license (renamed from subprojects/docs/src/learn/tutorials/file-system/fig4.svg.license)0
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/index.md173
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.pngbin0 -> 151312 bytes
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.png.license5
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.svg216
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.svg.license3
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.pngbin0 -> 155459 bytes
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.png.license5
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.svg224
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.svg.license3
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/metamodel.svg132
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/metamodel.svg.license3
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationDark.pngbin0 -> 172263 bytes
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationDark.png.license3
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationLight.pngbin0 -> 183811 bytes
-rw-r--r--subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationLight.png.license3
-rw-r--r--subprojects/docs/src/learn/index.md11
-rw-r--r--subprojects/docs/src/plugins/remarkImage.ts249
-rw-r--r--subprojects/docs/src/plugins/remarkPluginUtils.ts58
-rw-r--r--subprojects/docs/src/plugins/remarkPosix2Windows.ts56
-rw-r--r--subprojects/docs/src/plugins/remarkRefinery.ts164
-rw-r--r--subprojects/docs/src/plugins/remarkReplaceVariables.ts49
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/commands.md158
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/ide-setup.md96
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/index.md59
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/develop/java.md351
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/develop/javadoc.md41
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/docker/cli.md145
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/docker/index.md (renamed from subprojects/docs/src/learn/docker.md)39
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/index.md11
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/_category_.yml10
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg227
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg20
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg229
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg29
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg38
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg69
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg24
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg43
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/index.md213
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg20
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg99
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg129
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg81
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg58
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg58
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/index.md256
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg76
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/index.md284
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/_category_.yml11
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig1.svg (renamed from subprojects/docs/src/learn/tutorials/file-system/fig1.svg)0
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig1.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig2.svg (renamed from subprojects/docs/src/learn/tutorials/file-system/fig2.svg)0
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig2.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig3.svg (renamed from subprojects/docs/src/learn/tutorials/file-system/fig3.svg)0
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig3.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig4.svg (renamed from subprojects/docs/src/learn/tutorials/file-system/fig4.svg)0
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig4.svg.license3
-rw-r--r--subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/index.md (renamed from subprojects/docs/src/learn/tutorials/file-system/index.md)0
-rw-r--r--subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json14
-rw-r--r--subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json.license3
-rw-r--r--subprojects/docs/versions.json3
-rw-r--r--subprojects/docs/versions.json.license3
-rw-r--r--subprojects/frontend/package.json51
-rw-r--r--subprojects/frontend/src/graph/GraphStore.ts6
-rw-r--r--subprojects/frontend/src/graph/GraphTheme.tsx15
-rw-r--r--subprojects/frontend/src/graph/dotSource.ts12
-rw-r--r--subprojects/frontend/src/graph/export/exportDiagram.tsx2
-rw-r--r--subprojects/frontend/src/language/problem.grammar3
-rw-r--r--subprojects/frontend/src/persistence/compressionWorker.ts11
-rw-r--r--subprojects/frontend/src/xtext/xtextServiceResults.ts1
-rw-r--r--subprojects/generator-cli/build.gradle.kts9
-rw-r--r--subprojects/generator/build.gradle.kts5
-rw-r--r--subprojects/generator/src/main/java/tools/refinery/generator/CancellableCancellationToken.java38
-rw-r--r--subprojects/generator/src/main/java/tools/refinery/generator/FilteredInterpretation.java108
-rw-r--r--subprojects/generator/src/main/java/tools/refinery/generator/GeneratorResult.java29
-rw-r--r--subprojects/generator/src/main/java/tools/refinery/generator/GeneratorTimeoutException.java12
-rw-r--r--subprojects/generator/src/main/java/tools/refinery/generator/ModelFacadeFactory.java61
-rw-r--r--subprojects/generator/src/main/java/tools/refinery/generator/ModelGenerator.java49
-rw-r--r--subprojects/generator/src/main/java/tools/refinery/generator/ModelGeneratorFactory.java28
-rw-r--r--subprojects/generator/src/main/java/tools/refinery/generator/ModelSemanticsFactory.java33
-rw-r--r--subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java41
-rw-r--r--subprojects/generator/src/test/java/tools/refinery/generator/ProblemLoaderTest.java9
-rw-r--r--subprojects/generator/src/test/resources/tools/refinery/generator/crossreference/typeConstraint.problem85
-rw-r--r--subprojects/generator/src/test/resources/tools/refinery/generator/crossreference/undirectedMultiplicity.problem57
-rw-r--r--subprojects/generator/src/test/resources/tools/refinery/generator/sudoku.problem384
-rw-r--r--subprojects/generator/src/test/resources/tools/refinery/generator/typehierarchy/abstract.problem47
-rw-r--r--subprojects/generator/src/test/resources/tools/refinery/generator/typehierarchy/basic.problem24
-rw-r--r--subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/DynamicTestLoader.java263
-rw-r--r--subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsExpectation.java117
-rw-r--r--subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTest.java18
-rw-r--r--subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestBuilder.java93
-rw-r--r--subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCase.java103
-rw-r--r--subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCaseBuilder.java95
-rw-r--r--subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestLoader.java71
-rw-r--r--subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkAcceptor.java12
-rw-r--r--subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkHeader.java9
-rw-r--r--subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/CommonHeader.java18
-rw-r--r--subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ExpectationHeader.java12
-rw-r--r--subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ProblemSplitter.java92
-rw-r--r--subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/TestCaseHeader.java9
-rw-r--r--subprojects/gradle-plugins/build.gradle.kts163
-rw-r--r--subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/RefineryJavaExtension.java26
-rw-r--r--subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/RefineryJavaPlugin.java215
-rw-r--r--subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/RefinerySettingsPlugin.java79
-rw-r--r--subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/Repository.java32
-rw-r--r--subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/TestDependencies.java35
-rw-r--r--subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/internal/RefineryPluginUtils.java53
-rw-r--r--subprojects/interpreter/build.gradle.kts2
-rw-r--r--subprojects/language-model/problem.aird88
-rw-r--r--subprojects/language-model/src/main/resources/model/problem.ecore9
-rw-r--r--subprojects/language-model/src/main/resources/model/problem.genmodel9
-rw-r--r--subprojects/language-semantics/build.gradle.kts4
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ModelInitializer.java93
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ProblemTraceImpl.java13
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/SolutionSerializer.java23
-rw-r--r--subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/ModelGenerationTest.java10
-rw-r--r--subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/SolutionSerializerTest.java69
-rw-r--r--subprojects/language-web/build.gradle.kts14
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java7
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsWorker.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/BasePredicateDetail.java10
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/MetadataCreator.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/RelationDetail.java2
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java3
-rw-r--r--subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java9
-rw-r--r--subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java60
-rw-r--r--subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java2
-rw-r--r--subprojects/language/build.gradle.kts1
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/Problem.xtext11
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/resource/state/ProblemDerivedStateComputer.java4
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/typesystem/TypedModule.java2
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java28
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java31
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java8
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/documentation/DocumentationCommentParserTest.java10
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java8
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/linking/AmbiguousReferenceTest.java10
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java8
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java8
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java10
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java40
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java12
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java10
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/validation/ArityValidationTest.java10
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssertionValidationTest.java25
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssignmentValidationTest.java10
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/validation/ModuleValidationTest.java10
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/validation/MultiplicityValidationTest.java10
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/validation/OppositeValidationTest.java10
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/InjectWithRefinery.java22
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/ProblemNavigationUtil.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemNavigationUtil.java)2
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/ProblemParseHelper.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemParseHelper.java)2
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAction.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAction.java)2
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedArgument.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java)2
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAssertion.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertion.java)2
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAssertionArgument.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java)2
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAtom.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAtom.java)4
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedClassDeclaration.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java)2
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedConjunction.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConjunction.java)4
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedConsequent.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConsequent.java)2
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedEnumDeclaration.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedEnumDeclaration.java)4
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedLiteral.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java)2
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedParametricDefinition.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java)2
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedPredicateDefinition.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java)2
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedProblem.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java)2
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedRuleDefinition.java (renamed from subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java)2
-rw-r--r--subprojects/logic/src/main/java/tools/refinery/logic/term/truthvalue/TruthValue.java1
-rw-r--r--subprojects/store-dse-visualization/build.gradle.kts2
-rw-r--r--subprojects/store-dse/build.gradle.kts4
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/RuleBuilder.java3
-rw-r--r--subprojects/store-reasoning-scope/build.gradle.kts4
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java12
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java3
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/refinement/AnyPartialInterpretationRefiner.java33
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/refinement/ConcreteSymbolRefiner.java12
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/MapBasedSeed.java4
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/ModelSeed.java4
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/SeedInitializer.java8
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentLinkRefiner.java9
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainsRefiner.java9
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceInitializer.java52
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceRefiner.java42
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceTranslator.java3
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceInitializer.java18
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceRefiner.java50
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceTranslator.java4
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/CleanupPropagator.java9
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiObjectTranslator.java16
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/BasePredicateTranslator.java143
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/PredicateRefiner.java94
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/PredicateTranslator.java13
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/ShadowPredicateTranslator.java71
-rw-r--r--subprojects/store/build.gradle.kts4
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java1
-rw-r--r--subprojects/versions/build.gradle.kts7
277 files changed, 9762 insertions, 949 deletions
diff --git a/subprojects/docs/build.gradle.kts b/subprojects/docs/build.gradle.kts
index ab67128a..fcd6a651 100644
--- a/subprojects/docs/build.gradle.kts
+++ b/subprojects/docs/build.gradle.kts
@@ -22,24 +22,39 @@ val javadocs: Configuration by configurations.creating {
22 isCanBeResolved = true 22 isCanBeResolved = true
23} 23}
24 24
25val releasedJavadocs: Configuration by configurations.creating {
26 isCanBeConsumed = false
27 isCanBeResolved = true
28}
29
30val interpreterGroup = property("tools.refinery.interpreter.group").toString()
31val releasedVersion = property("tools.refinery.release").toString()
32val releasedInterpreterVersion = property("tools.refinery.interpreter.release").toString()
33
34repositories {
35 mavenCentral()
36}
37
25dependencies { 38dependencies {
26 gradle.projectsEvaluated { 39 gradle.projectsEvaluated {
27 for (subproject in rootProject.subprojects) { 40 for (subproject in rootProject.subprojects) {
28 if (subproject.plugins.hasPlugin(JavaLibraryPlugin::class)) { 41 if (subproject.plugins.hasPlugin(JavaLibraryPlugin::class)) {
29 javadocs(project(subproject.path, "javadocElements")) 42 javadocs(project(subproject.path, "javadocElements"))
43 val releasedProjectVersion = if (subproject.group.toString() == interpreterGroup)
44 releasedInterpreterVersion else releasedVersion
45 releasedJavadocs("${subproject.group}:${subproject.name}:$releasedProjectVersion:javadoc@jar")
30 } 46 }
31 } 47 }
32 } 48 }
49
50 javadocs(project(":refinery-gradle-plugins", "javadocElements"))
51 releasedJavadocs("tools.refinery:refinery-gradle-plugins:$releasedVersion:javadoc@jar")
33} 52}
34 53
35val srcDir = "src" 54val srcDir = "src"
36
37val docusaurusOutputDir = layout.buildDirectory.dir("docusaurus") 55val docusaurusOutputDir = layout.buildDirectory.dir("docusaurus")
38
39val javadocsDir = layout.buildDirectory.dir("javadocs") 56val javadocsDir = layout.buildDirectory.dir("javadocs")
40 57
41val javadocsDocsDir = javadocsDir.map { root -> root.dir("develop/javadoc") }
42
43val configFiles: FileCollection = files( 58val configFiles: FileCollection = files(
44 rootProject.file("yarn.lock"), 59 rootProject.file("yarn.lock"),
45 rootProject.file("package.json"), 60 rootProject.file("package.json"),
@@ -54,25 +69,57 @@ val lintConfigFiles: FileCollection = configFiles + files(
54 rootProject.file(".eslintrc.cjs"), rootProject.file("prettier.config.cjs") 69 rootProject.file(".eslintrc.cjs"), rootProject.file("prettier.config.cjs")
55) 70)
56 71
57tasks { 72abstract class ExtractJavadocTask : DefaultTask() {
58 val extractJavadocs by registering { 73 @get:OutputDirectory
59 dependsOn(javadocs) 74 abstract val targetDir: DirectoryProperty
60 outputs.dir(javadocsDir) 75
61 doFirst { 76 @get:Input
62 delete(javadocsDir) 77 abstract val resolvedJavadocArtifacts: MapProperty<String, File>
78
79 @get:Inject
80 abstract val fs: FileSystemOperations
81
82 @get:Inject
83 abstract val archive: ArchiveOperations
84
85 @TaskAction
86 fun action() {
87 fs.delete {
88 delete(targetDir)
63 } 89 }
64 doLast { 90 val javadocsDocsDir = targetDir.get()
65 javadocs.resolvedConfiguration.resolvedArtifacts.forEach { artifact -> 91 resolvedJavadocArtifacts.get().forEach { artifact ->
66 copy { 92 fs.copy {
67 from(zipTree(artifact.file)) 93 from(archive.zipTree(artifact.value))
68 into(javadocsDocsDir.map { root -> root.dir(artifact.moduleVersion.id.name) }) 94 into(javadocsDocsDir.dir(artifact.key))
69 }
70 } 95 }
71 } 96 }
72 } 97 }
98}
99
100fun resolveJavadocs(configuration: Configuration): Provider<Map<String, File>> {
101 return provider {
102 configuration.resolvedConfiguration.resolvedArtifacts.associate { artifact ->
103 artifact.moduleVersion.id.name to artifact.file
104 }
105 }
106}
107
108tasks {
109 val extractJavadocs by registering(ExtractJavadocTask::class) {
110 dependsOn(javadocs)
111 targetDir = javadocsDir.map { it.dir("snapshot/develop/javadoc" ) }
112 resolvedJavadocArtifacts = resolveJavadocs(javadocs)
113 }
114
115 val extractReleasedJavadocs by registering(ExtractJavadocTask::class) {
116 dependsOn(releasedJavadocs)
117 targetDir = javadocsDir.map { it.dir("develop/javadoc" ) }
118 resolvedJavadocArtifacts = resolveJavadocs(releasedJavadocs)
119 }
73 120
74 assembleFrontend { 121 assembleFrontend {
75 dependsOn(extractJavadocs) 122 dependsOn(extractJavadocs, extractReleasedJavadocs)
76 inputs.dir(srcDir) 123 inputs.dir(srcDir)
77 inputs.dir("static") 124 inputs.dir("static")
78 inputs.dir(javadocsDir) 125 inputs.dir(javadocsDir)
diff --git a/subprojects/docs/docusaurus.config.ts b/subprojects/docs/docusaurus.config.ts
index 7e76017b..5c32fcca 100644
--- a/subprojects/docs/docusaurus.config.ts
+++ b/subprojects/docs/docusaurus.config.ts
@@ -5,297 +5,323 @@
5 * SPDX-License-Identifier: MIT AND EPL-2.0 5 * SPDX-License-Identifier: MIT AND EPL-2.0
6 */ 6 */
7 7
8import path from 'node:path';
9
8import type { MDXOptions } from '@docusaurus/mdx-loader'; 10import type { MDXOptions } from '@docusaurus/mdx-loader';
11import type { Options as RedirectOptions } from '@docusaurus/plugin-client-redirects';
9import type { Options as DocsOptions } from '@docusaurus/plugin-content-docs'; 12import type { Options as DocsOptions } from '@docusaurus/plugin-content-docs';
10import type { Options as PagesOptions } from '@docusaurus/plugin-content-pages'; 13import type { Options as PagesOptions } from '@docusaurus/plugin-content-pages';
11import type { Options as ClassicThemeOptions } from '@docusaurus/theme-classic'; 14import type { Options as ClassicThemeOptions } from '@docusaurus/theme-classic';
12import type { UserThemeConfig } from '@docusaurus/theme-common'; 15import type { UserThemeConfig } from '@docusaurus/theme-common';
13import type { UserThemeConfig as AlgoliaConfig } from '@docusaurus/theme-search-algolia'; 16import type { UserThemeConfig as AlgoliaConfig } from '@docusaurus/theme-search-algolia';
14import type { Config } from '@docusaurus/types'; 17import type { Config } from '@docusaurus/types';
15import { Config as SwcConfig } from '@swc/core'; 18import type { Config as SwcConfig } from '@swc/core';
19import { PropertiesFile } from 'java-properties';
16import { themes } from 'prism-react-renderer'; 20import { themes } from 'prism-react-renderer';
17import smartypants from 'remark-smartypants'; 21import smartypants from 'remark-smartypants';
18 22
23import remarkImage from './src/plugins/remarkImage';
19import remarkPosix2Windows from './src/plugins/remarkPosix2Windows'; 24import remarkPosix2Windows from './src/plugins/remarkPosix2Windows';
25import remarkRefinery from './src/plugins/remarkRefinery';
26import remarkReplaceVariables from './src/plugins/remarkReplaceVariables';
20 27
21const markdownOptions: Partial<MDXOptions> = { 28const properties = new PropertiesFile(
22 remarkPlugins: [[smartypants, { dashes: 'oldschool' }], remarkPosix2Windows], 29 path.join(__dirname, '../../gradle.properties'),
23}; 30);
24
25const docsOptions = {
26 ...markdownOptions,
27 sidebarPath: undefined,
28 editUrl:
29 'https://github.com/graphs4value/refinery/edit/main/subprojects/docs',
30} satisfies DocsOptions;
31 31
32export default { 32export default async function createConfigAsync() {
33 title: 'Refinery', 33 const markdownOptions: Partial<MDXOptions> = {
34 tagline: 'An efficient graph solver for generating well-formed models', 34 beforeDefaultRemarkPlugins: [remarkImage],
35 url: 'https://refinery.tools', 35 remarkPlugins: [
36 baseUrl: '/', 36 [remarkReplaceVariables, { properties }],
37 baseUrlIssueBanner: false, 37 [smartypants, { dashes: 'oldschool' }],
38 trailingSlash: true, 38 remarkPosix2Windows,
39 staticDirectories: ['static', 'build/javadocs'], 39 await remarkRefinery(),
40 plugins: [
41 [
42 '@docusaurus/plugin-content-docs',
43 {
44 id: 'learn',
45 path: 'src/learn',
46 routeBasePath: '/learn',
47 ...docsOptions,
48 } satisfies DocsOptions,
49 ], 40 ],
50 [ 41 };
51 '@docusaurus/plugin-content-docs', 42
52 { 43 return {
53 id: 'develop', 44 title: 'Refinery',
54 path: 'src/develop', 45 tagline: 'An efficient graph solver for generating well-formed models',
55 routeBasePath: '/develop', 46 url: 'https://refinery.tools',
56 ...docsOptions, 47 baseUrl: '/',
57 } satisfies DocsOptions, 48 baseUrlIssueBanner: false,
58 ], 49 trailingSlash: true,
59 [ 50 staticDirectories: ['static', 'build/javadocs'],
60 '@docusaurus/plugin-content-pages', 51 plugins: [
61 markdownOptions satisfies PagesOptions, 52 [
62 ], 53 '@docusaurus/plugin-content-docs',
63 '@docusaurus/plugin-sitemap',
64 './src/plugins/loadersPlugin.ts',
65 './src/plugins/swcMinifyPlugin.ts',
66 ],
67 themes: [
68 [
69 '@docusaurus/theme-classic',
70 {
71 customCss: [require.resolve('./src/css/custom.css')],
72 } satisfies ClassicThemeOptions,
73 ],
74 '@docusaurus/theme-search-algolia',
75 ],
76 themeConfig: {
77 colorMode: {
78 respectPrefersColorScheme: true,
79 },
80 prism: {
81 additionalLanguages: ['bash', 'java'],
82 theme: themes.oneLight,
83 darkTheme: themes.oneDark,
84 },
85 navbar: {
86 title: 'Refinery',
87 logo: {
88 src: '/logo.svg',
89 srcDark: '/logo-dark.svg',
90 },
91 hideOnScroll: true,
92 items: [
93 {
94 label: 'Learn',
95 to: '/learn',
96 },
97 {
98 label: 'Develop',
99 to: '/develop',
100 },
101 {
102 label: 'GitHub',
103 position: 'right',
104 href: 'https://github.com/graphs4value/refinery',
105 },
106 {
107 label: 'Try now',
108 position: 'right',
109 href: 'https://refinery.services/',
110 className: 'navbar__link--try-now',
111 },
112 ],
113 },
114 footer: {
115 links: [
116 { 54 {
117 title: 'Learn', 55 path: 'src/docs',
118 items: [ 56 routeBasePath: '/',
119 { 57 sidebarPath: './sidebars.ts',
120 label: 'Introduction', 58 editUrl:
121 to: '/learn', 59 'https://github.com/graphs4value/refinery/edit/main/subprojects/docs',
60 versions: {
61 current: {
62 path: 'snapshot',
63 label: `${String(properties.get('version'))} 🚧`,
122 }, 64 },
123 { 65 },
124 label: 'Tutorials', 66 ...markdownOptions,
125 to: '/learn/tutorials', 67 } satisfies DocsOptions,
126 }, 68 ],
127 { 69 [
128 label: 'Langauge reference', 70 '@docusaurus/plugin-content-pages',
129 to: '/learn/language', 71 markdownOptions satisfies PagesOptions,
130 }, 72 ],
131 { 73 [
132 label: 'Run in Docker', 74 '@docusaurus/plugin-client-redirects',
133 to: '/learn/docker',
134 },
135 ],
136 },
137 { 75 {
138 title: 'Develop', 76 redirects: [
139 items: [
140 {
141 label: 'Programming guide',
142 to: '/develop',
143 },
144 { 77 {
145 label: 'Contributing', 78 to: '/develop/java/',
146 to: '/develop/contributing', 79 from: '/develop/',
147 },
148 {
149 label: 'Javadoc',
150 to: '/develop/javadoc',
151 }, 80 },
152 ], 81 ],
153 }, 82 } satisfies RedirectOptions,
83 ],
84 '@docusaurus/plugin-sitemap',
85 './src/plugins/loadersPlugin.ts',
86 './src/plugins/swcMinifyPlugin.ts',
87 ],
88 themes: [
89 [
90 '@docusaurus/theme-classic',
154 { 91 {
155 title: 'More', 92 customCss: [require.resolve('./src/css/custom.css')],
156 items: [ 93 } satisfies ClassicThemeOptions,
157 { 94 ],
158 label: 'Try now', 95 '@docusaurus/theme-search-algolia',
159 href: 'https://refinery.services/', 96 ],
160 }, 97 themeConfig: {
161 { 98 colorMode: {
162 label: 'GitHub', 99 respectPrefersColorScheme: true,
163 href: 'https://github.com/graphs4value/refinery', 100 },
164 }, 101 prism: {
165 { 102 additionalLanguages: ['bash', 'groovy', 'ini', 'java', 'kotlin'],
166 label: 'License', 103 theme: themes.oneLight,
167 to: '/license', 104 darkTheme: themes.oneDark,
168 }, 105 },
169 ], 106 navbar: {
107 title: 'Refinery',
108 logo: {
109 src: '/logo.svg',
110 srcDark: '/logo-dark.svg',
170 }, 111 },
171 { 112 hideOnScroll: true,
172 title: 'Supporters', 113 items: [
173 items: [ 114 {
174 { 115 type: 'doc',
175 label: 'BME MIT FTSRG', 116 label: 'Learn',
176 href: 'https://ftsrg.mit.bme.hu/en/', 117 docId: 'learn/index',
177 }, 118 },
178 { 119 {
179 label: 'McGill ECE', 120 type: 'doc',
180 href: 'https://www.mcgill.ca/', 121 label: 'Develop',
181 }, 122 docId: 'develop/java',
182 { 123 },
183 label: '2022 Amazon Research Awards', 124 {
184 href: 'https://www.amazon.science/research-awards/recipients/daniel-varro-fall-2021', 125 label: 'GitHub',
185 }, 126 position: 'right',
186 { 127 href: 'https://github.com/graphs4value/refinery',
187 label: 'LiU Software and Systems', 128 },
188 href: 'https://liu.se/en/organisation/liu/ida/sas', 129 {
130 label: 'Try now',
131 position: 'right',
132 href: 'https://refinery.services/',
133 className: 'navbar__link--try-now',
134 },
135 {
136 type: 'docsVersionDropdown',
137 position: 'right',
138 },
139 ],
140 },
141 footer: {
142 links: [
143 {
144 title: 'Learn',
145 items: [
146 {
147 label: 'Introduction',
148 to: '/learn',
149 },
150 {
151 label: 'Tutorials',
152 to: '/learn/tutorials',
153 },
154 {
155 label: 'Langauge reference',
156 to: '/learn/language',
157 },
158 {
159 label: 'Run in Docker',
160 to: '/learn/docker',
161 },
162 ],
163 },
164 {
165 title: 'Develop',
166 items: [
167 {
168 label: 'Programming guide',
169 to: '/develop/java',
170 },
171 {
172 label: 'Contributing',
173 to: '/develop/contributing',
174 },
175 {
176 label: 'Javadoc',
177 to: '/develop/javadoc',
178 },
179 ],
180 },
181 {
182 title: 'More',
183 items: [
184 {
185 label: 'Try now',
186 href: 'https://refinery.services/',
187 },
188 {
189 label: 'GitHub',
190 href: 'https://github.com/graphs4value/refinery',
191 },
192 {
193 label: 'License',
194 to: '/license',
195 },
196 ],
197 },
198 {
199 title: 'Supporters',
200 items: [
201 {
202 label: 'BME MIT FTSRG',
203 href: 'https://ftsrg.mit.bme.hu/en/',
204 },
205 {
206 label: 'McGill ECE',
207 href: 'https://www.mcgill.ca/',
208 },
209 {
210 label: '2022 Amazon Research Awards',
211 href: 'https://www.amazon.science/research-awards/recipients/daniel-varro-fall-2021',
212 },
213 {
214 label: 'LiU Software and Systems',
215 href: 'https://liu.se/en/organisation/liu/ida/sas',
216 },
217 {
218 label: 'WASP',
219 href: 'https://wasp-sweden.org/',
220 },
221 ],
222 },
223 ],
224 copyright: `
225 Copyright &copy; 2021-2024
226 <a href="https://github.com/graphs4value/refinery/blob/main/CONTRIBUTORS.md#the-refinery-authors" target="_blank">The Refinery Authors</a>.
227 Available under the
228 <a href="/license/">Eclipse Public License - v 2.0</a>.
229 `,
230 },
231 algolia: {
232 appId: 'KYHOYEO80F',
233 apiKey: '152acfb8d1ad9e10f29f083a6b017a69',
234 indexName: 'refinery',
235 // Javadoc doesn't use the Docusaurus router and has to be navigated to with `location.href` instead.
236 externalUrlRegex: '/([^/]+/)?develop/javadoc/.+',
237 },
238 } satisfies UserThemeConfig & AlgoliaConfig,
239 webpack: {
240 // Speed up builds by using a native Javascript loader.
241 // See: https://github.com/facebook/docusaurus/issues/4765#issuecomment-841135926
242 // But we follow the Docusaurus upstream from
243 // https://github.com/facebook/docusaurus/blob/791da2e4a1a53aa6309887059e3f112fcb35bec4/website/docusaurus.config.ts#L152-L171
244 // and use swc instead of esbuild.
245 jsLoader: (isServer) => ({
246 loader: require.resolve('swc-loader'),
247 options: {
248 jsc: {
249 parser: {
250 syntax: 'typescript',
251 tsx: true,
189 }, 252 },
190 { 253 transform: {
191 label: 'WASP', 254 react: {
192 href: 'https://wasp-sweden.org/', 255 runtime: 'automatic',
256 },
193 }, 257 },
194 ], 258 target: 'es2022',
195 },
196 ],
197 copyright: `
198 Copyright &copy; 2021-2024
199 <a href="https://github.com/graphs4value/refinery/blob/main/CONTRIBUTORS.md#the-refinery-authors" target="_blank">The Refinery Authors</a>.
200 Available under the
201 <a href="/license/">Eclipse Public License - v 2.0</a>.
202 `,
203 },
204 algolia: {
205 appId: 'KYHOYEO80F',
206 apiKey: '152acfb8d1ad9e10f29f083a6b017a69',
207 indexName: 'refinery',
208 // We don't have any context specified, so we need to disable this to return results.
209 contextualSearch: false,
210 // Javadoc doesn't use the Docusaurus router and has to be navigated to with `location.href` instead.
211 externalUrlRegex: '/develop/javadoc/.+',
212 },
213 } satisfies UserThemeConfig & AlgoliaConfig,
214 webpack: {
215 // Speed up builds by using a native Javascript loader.
216 // See: https://github.com/facebook/docusaurus/issues/4765#issuecomment-841135926
217 // But we follow the Docusaurus upstream from
218 // https://github.com/facebook/docusaurus/blob/791da2e4a1a53aa6309887059e3f112fcb35bec4/website/docusaurus.config.ts#L152-L171
219 // and use swc instead of esbuild.
220 jsLoader: (isServer) => ({
221 loader: require.resolve('swc-loader'),
222 options: {
223 jsc: {
224 parser: {
225 syntax: 'typescript',
226 tsx: true,
227 }, 259 },
228 transform: { 260 module: {
229 react: { 261 type: isServer ? 'commonjs' : 'es6',
230 runtime: 'automatic',
231 },
232 }, 262 },
233 target: 'es2022', 263 } satisfies SwcConfig,
234 }, 264 }),
235 module: { 265 },
236 type: isServer ? 'commonjs' : 'es6', 266 headTags: [
267 {
268 tagName: 'link',
269 attributes: {
270 rel: 'icon',
271 href: '/favicon.svg',
272 type: 'image/svg+xml',
237 }, 273 },
238 } satisfies SwcConfig,
239 }),
240 },
241 headTags: [
242 {
243 tagName: 'link',
244 attributes: {
245 rel: 'icon',
246 href: '/favicon.svg',
247 type: 'image/svg+xml',
248 }, 274 },
249 }, 275 {
250 { 276 tagName: 'link',
251 tagName: 'link', 277 attributes: {
252 attributes: { 278 rel: 'icon',
253 rel: 'icon', 279 href: '/favicon.png',
254 href: '/favicon.png', 280 type: 'image/png',
255 type: 'image/png', 281 sizes: '32x32',
256 sizes: '32x32', 282 },
257 }, 283 },
258 }, 284 {
259 { 285 tagName: 'link',
260 tagName: 'link', 286 attributes: {
261 attributes: { 287 rel: 'icon',
262 rel: 'icon', 288 href: '/favicon-96x96.png',
263 href: '/favicon-96x96.png', 289 type: 'image/png',
264 type: 'image/png', 290 sizes: '96x96',
265 sizes: '96x96', 291 },
266 }, 292 },
267 }, 293 {
268 { 294 tagName: 'link',
269 tagName: 'link', 295 attributes: {
270 attributes: { 296 rel: 'apple-touch-icon',
271 rel: 'apple-touch-icon', 297 href: '/apple-touch-icon.png',
272 href: '/apple-touch-icon.png', 298 type: 'image/png',
273 type: 'image/png', 299 sizes: '180x180',
274 sizes: '180x180', 300 },
275 }, 301 },
276 }, 302 {
277 { 303 tagName: 'link',
278 tagName: 'link', 304 attributes: {
279 attributes: { 305 rel: 'manifest',
280 rel: 'manifest', 306 href: '/manifest.webmanifest',
281 href: '/manifest.webmanifest', 307 },
282 }, 308 },
283 }, 309 {
284 { 310 tagName: 'meta',
285 tagName: 'meta', 311 attributes: {
286 attributes: { 312 name: 'theme-color',
287 name: 'theme-color', 313 media: '(prefers-color-scheme:light)',
288 media: '(prefers-color-scheme:light)', 314 content: '#f5f5f5',
289 content: '#f5f5f5', 315 },
290 }, 316 },
291 }, 317 {
292 { 318 tagName: 'meta',
293 tagName: 'meta', 319 attributes: {
294 attributes: { 320 name: 'theme-color',
295 name: 'theme-color', 321 media: '(prefers-color-scheme:dark)',
296 media: '(prefers-color-scheme:dark)', 322 content: '#282c34',
297 content: '#282c34', 323 },
298 }, 324 },
299 }, 325 ],
300 ], 326 } satisfies Config;
301} satisfies Config; 327}
diff --git a/subprojects/docs/package.json b/subprojects/docs/package.json
index 31df0339..f28042b1 100644
--- a/subprojects/docs/package.json
+++ b/subprojects/docs/package.json
@@ -30,45 +30,48 @@
30 }, 30 },
31 "homepage": "https://refinery.tools", 31 "homepage": "https://refinery.tools",
32 "dependencies": { 32 "dependencies": {
33 "@algolia/client-search": "^4.24.0", 33 "@algolia/client-search": "^5.2.3",
34 "@docusaurus/core": "^3.4.0", 34 "@docusaurus/core": "^3.5.2",
35 "@docusaurus/plugin-content-docs": "^3.4.0", 35 "@docusaurus/plugin-client-redirects": "^3.5.2",
36 "@docusaurus/plugin-content-pages": "^3.4.0", 36 "@docusaurus/plugin-content-docs": "^3.5.2",
37 "@docusaurus/plugin-sitemap": "^3.4.0", 37 "@docusaurus/plugin-content-pages": "^3.5.2",
38 "@docusaurus/theme-classic": "^3.4.0", 38 "@docusaurus/plugin-sitemap": "^3.5.2",
39 "@docusaurus/theme-common": "^3.4.0", 39 "@docusaurus/theme-classic": "^3.5.2",
40 "@docusaurus/theme-search-algolia": "^3.4.0", 40 "@docusaurus/theme-common": "^3.5.2",
41 "@fontsource-variable/jetbrains-mono": "^5.0.21", 41 "@docusaurus/theme-search-algolia": "^3.5.2",
42 "@fontsource-variable/open-sans": "^5.0.29", 42 "@fontsource-variable/jetbrains-mono": "^5.0.22",
43 "@fontsource/open-sans": "^5.0.28", 43 "@fontsource-variable/open-sans": "^5.0.30",
44 "@fontsource/open-sans": "^5.0.29",
45 "@hpcc-js/wasm-zstd": "^1.2.0",
44 "@material-icons/svg": "^1.0.33", 46 "@material-icons/svg": "^1.0.33",
45 "@mdx-js/react": "^3.0.1", 47 "@mdx-js/react": "^3.0.1",
46 "@swc/core": "^1.6.13", 48 "@swc/core": "^1.7.22",
47 "clsx": "^2.1.1", 49 "clsx": "^2.1.1",
50 "java-properties": "^1.0.2",
48 "mdast-util-mdx": "^3.0.0", 51 "mdast-util-mdx": "^3.0.0",
49 "prism-react-renderer": "^2.3.1", 52 "prism-react-renderer": "^2.4.0",
50 "react": "^18.3.1", 53 "react": "^18.3.1",
51 "react-dom": "^18.3.1", 54 "react-dom": "^18.3.1",
52 "remark-smartypants": "^3.0.1", 55 "remark-smartypants": "^3.0.2",
53 "responsive-loader": "^3.1.2", 56 "responsive-loader": "^3.1.2",
54 "search-insights": "^2.14.0", 57 "search-insights": "^2.17.0",
55 "sharp": "^0.33.4", 58 "sharp": "^0.33.5",
56 "swc-loader": "^0.2.6", 59 "swc-loader": "^0.2.6",
57 "terser-webpack-plugin": "^5.3.10", 60 "terser-webpack-plugin": "^5.3.10",
58 "typescript": "5.5.3", 61 "typescript": "5.5.4",
59 "unified": "^11.0.5", 62 "unified": "^11.0.5",
60 "unist-util-visit": "^5.0.0", 63 "unist-util-visit": "^5.0.0",
61 "webpack": "^5.92.1" 64 "webpack": "^5.94.0"
62 }, 65 },
63 "devDependencies": { 66 "devDependencies": {
64 "@docusaurus/mdx-loader": "^3.4.0", 67 "@docusaurus/mdx-loader": "^3.5.2",
65 "@docusaurus/module-type-aliases": "^3.4.0", 68 "@docusaurus/module-type-aliases": "^3.5.2",
66 "@docusaurus/types": "^3.4.0", 69 "@docusaurus/types": "^3.5.2",
67 "@types/babel__core": "^7.20.5", 70 "@types/babel__core": "^7.20.5",
68 "@types/mdast": "^4.0.4", 71 "@types/mdast": "^4.0.4",
69 "@types/node": "^20.14.10", 72 "@types/node": "^20.16.2",
70 "@types/react": "^18.3.3", 73 "@types/react": "^18.3.5",
71 "@types/react-dom": "^18.3.0", 74 "@types/react-dom": "^18.3.0",
72 "@types/unist": "^3.0.2" 75 "@types/unist": "^3.0.3"
73 } 76 }
74} 77}
diff --git a/subprojects/docs/sidebars.ts b/subprojects/docs/sidebars.ts
new file mode 100644
index 00000000..29348767
--- /dev/null
+++ b/subprojects/docs/sidebars.ts
@@ -0,0 +1,22 @@
1/*
2 * Copyright (c) 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import { SidebarsConfig } from '@docusaurus/plugin-content-docs';
8
9export default {
10 learnSidebar: [
11 {
12 type: 'autogenerated',
13 dirName: 'learn',
14 },
15 ],
16 developSidebar: [
17 {
18 type: 'autogenerated',
19 dirName: 'develop',
20 },
21 ],
22} satisfies SidebarsConfig;
diff --git a/subprojects/docs/src/components/ResponsiveImage/ImageTag.tsx b/subprojects/docs/src/components/ResponsiveImage/ImageTag.tsx
new file mode 100644
index 00000000..b2002947
--- /dev/null
+++ b/subprojects/docs/src/components/ResponsiveImage/ImageTag.tsx
@@ -0,0 +1,29 @@
1/*
2 * Copyright (c) 2024 The Refinery Authors
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import styles from './index.module.css';
8
9export interface Props {
10 image: ResponsiveImageOutput;
11 alt?: string | undefined;
12 title?: string | undefined;
13}
14
15export default function ImageTag({ image, alt, title }: Props) {
16 return (
17 <img
18 alt={alt}
19 title={title}
20 width={image.width}
21 height={image.height}
22 sizes="(min-width: 1440px) 1320px, (max-width: 996px) calc(100vw - 32px), calc(75vw - 257px)"
23 loading="lazy"
24 src={image.src}
25 srcSet={image.srcSet}
26 className={styles['image']}
27 />
28 );
29}
diff --git a/subprojects/docs/src/components/ResponsiveImage/SVG/index.module.css b/subprojects/docs/src/components/ResponsiveImage/SVG/index.module.css
new file mode 100644
index 00000000..7738f412
--- /dev/null
+++ b/subprojects/docs/src/components/ResponsiveImage/SVG/index.module.css
@@ -0,0 +1,11 @@
1/*
2 * Copyright (c) 2024 The Refinery Authors
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7.container {
8 display: flex;
9 flex-direction: row;
10 justify-content: center;
11}
diff --git a/subprojects/docs/src/components/ResponsiveImage/SVG/index.tsx b/subprojects/docs/src/components/ResponsiveImage/SVG/index.tsx
new file mode 100644
index 00000000..13567504
--- /dev/null
+++ b/subprojects/docs/src/components/ResponsiveImage/SVG/index.tsx
@@ -0,0 +1,36 @@
1/*
2 * Copyright (c) 2024 The Refinery Authors
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import { useId, type FunctionComponent, type SVGAttributes } from 'react';
8
9import styles from './index.module.css';
10
11export default function SVG({
12 Component,
13 alt,
14 title,
15}: {
16 Component: FunctionComponent<SVGAttributes<SVGElement> & { title?: string }>;
17 alt?: string;
18 title?: string;
19}) {
20 const labelID = useId();
21
22 return (
23 <div className={styles['container']}>
24 <Component
25 role="img"
26 {...(title === undefined ? {} : { title })}
27 {...(alt === undefined ? {} : { 'aria-labelledby': labelID })}
28 />
29 {alt !== undefined && (
30 <div id={labelID} className="sr-only">
31 {alt}
32 </div>
33 )}
34 </div>
35 );
36}
diff --git a/subprojects/docs/src/components/ResponsiveImage/Themed.tsx b/subprojects/docs/src/components/ResponsiveImage/Themed.tsx
new file mode 100644
index 00000000..5573685a
--- /dev/null
+++ b/subprojects/docs/src/components/ResponsiveImage/Themed.tsx
@@ -0,0 +1,67 @@
1/*
2 * Copyright (c) 2024 The Refinery Authors
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import Link from '@docusaurus/Link';
8import { useColorMode } from '@docusaurus/theme-common';
9import useIsBrowser from '@docusaurus/useIsBrowser';
10import clsx from 'clsx';
11
12import ImageTag, { type Props as ImageTagProps } from './ImageTag';
13import styles from './index.module.css';
14import maxWidth from './maxWidth';
15
16interface Props extends Omit<ImageTagProps, 'image'> {
17 light: ResponsiveImageOutput;
18 dark: ResponsiveImageOutput;
19 originalLight: string;
20 originalDark: string;
21}
22
23export default function Themed({
24 light,
25 dark,
26 originalLight,
27 originalDark,
28 ...props
29}: Props) {
30 // Force re-render in browser.
31 // https://github.com/facebook/docusaurus/blob/e012e0315862b2ca02cad40c58d11d31c319ff75/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx#L32-L36
32 const isBrowser = useIsBrowser();
33 const { colorMode } = useColorMode();
34 const isDark = colorMode === 'dark';
35 const image = isDark ? dark : light;
36 const original = isDark ? originalDark : originalLight;
37 const imageTag = <ImageTag image={image} {...props} />;
38 const responsiveTag = isBrowser ? imageTag : <noscript>{imageTag}</noscript>;
39
40 if (light.width !== dark.width || light.height !== dark.height) {
41 throw new Error(
42 `Image size mismatch: ${light.src} is ${light.width}×${light.height}, but ${dark.src} is ${dark.width}×${dark.height}`,
43 );
44 }
45
46 return (
47 <div
48 style={{
49 aspectRatio: `${light.width}/${light.height}`,
50 maxWidth: maxWidth(light),
51 }}
52 className={styles['container']}
53 >
54 <div
55 style={{ backgroundImage: `url(${light.placeholder})` }}
56 className={styles['placeholder']}
57 />
58 <div
59 style={{ backgroundImage: `url(${dark.placeholder})` }}
60 className={clsx(styles['placeholder'], styles['placeholder--dark'])}
61 />
62 <Link href={`pathname://${original}`} className={String(styles['link'])}>
63 {responsiveTag}
64 </Link>
65 </div>
66 );
67}
diff --git a/subprojects/docs/src/components/ResponsiveImage/index.module.css b/subprojects/docs/src/components/ResponsiveImage/index.module.css
new file mode 100644
index 00000000..8e868ac7
--- /dev/null
+++ b/subprojects/docs/src/components/ResponsiveImage/index.module.css
@@ -0,0 +1,37 @@
1/*
2 * Copyright (c) 2024 The Refinery Authors
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7.container {
8 position: relative;
9 width: 100%;
10 margin: 0 auto;
11}
12
13.placeholder, .link, .image {
14 position: absolute;
15 top: 0;
16 left: 0;
17 width: 100%;
18 height: 100%;
19}
20
21.placeholder {
22 z-index: 0;
23 background-size: cover;
24}
25
26.placeholder--dark {
27 display: none;
28 z-index: 10;
29}
30
31[data-theme='dark'] .placeholder--dark {
32 display: block;
33}
34
35.link, .image {
36 z-index: 100;
37}
diff --git a/subprojects/docs/src/components/ResponsiveImage/index.tsx b/subprojects/docs/src/components/ResponsiveImage/index.tsx
new file mode 100644
index 00000000..7ce43853
--- /dev/null
+++ b/subprojects/docs/src/components/ResponsiveImage/index.tsx
@@ -0,0 +1,34 @@
1/*
2 * Copyright (c) 2024 The Refinery Authors
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import Link from '@docusaurus/Link';
8
9import ImageTag, { type Props as ImageTagProps } from './ImageTag';
10import styles from './index.module.css';
11
12interface Props extends ImageTagProps {
13 original: string;
14}
15
16export default function ThemedImage({ original, ...props }: Props) {
17 const {
18 image: { width, height, placeholder },
19 } = props;
20 return (
21 <div
22 style={{ aspectRatio: `${width}/${height}` }}
23 className={styles['container']}
24 >
25 <div
26 style={{ backgroundImage: `url(${placeholder})` }}
27 className={styles['placeholder']}
28 />
29 <Link href={`pathname://${original}`} className={String(styles['link'])}>
30 <ImageTag {...props} />
31 </Link>
32 </div>
33 );
34}
diff --git a/subprojects/docs/src/components/ResponsiveImage/maxWidth.ts b/subprojects/docs/src/components/ResponsiveImage/maxWidth.ts
new file mode 100644
index 00000000..bc9872d7
--- /dev/null
+++ b/subprojects/docs/src/components/ResponsiveImage/maxWidth.ts
@@ -0,0 +1,15 @@
1/*
2 * Copyright (c) 2024 The Refinery Authors
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7export default function maxWidth(image: ResponsiveImageOutput): number {
8 let result = 0;
9 image.images.forEach(({ width }) => {
10 if (width > result) {
11 result = width;
12 }
13 });
14 return result;
15}
diff --git a/subprojects/docs/src/components/TryInRefinery.tsx b/subprojects/docs/src/components/TryInRefinery.tsx
new file mode 100644
index 00000000..40766582
--- /dev/null
+++ b/subprojects/docs/src/components/TryInRefinery.tsx
@@ -0,0 +1,20 @@
1/*
2 * Copyright (c) 2024 The Refinery Authors
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import Link from '@docusaurus/Link';
8
9export default function TryInRefinery({ href }: { href: string }) {
10 return (
11 <p>
12 <Link
13 href={href}
14 className="button button--primary button--outline button--play"
15 >
16 Try in Refinery
17 </Link>
18 </p>
19 );
20}
diff --git a/subprojects/docs/src/components/UseCases/index.tsx b/subprojects/docs/src/components/UseCases/index.tsx
index c9570cc6..a7332f3e 100644
--- a/subprojects/docs/src/components/UseCases/index.tsx
+++ b/subprojects/docs/src/components/UseCases/index.tsx
@@ -49,7 +49,7 @@ export default function UseCases() {
49 <b>Scenario generation</b> for testing autonomous vechicles 49 <b>Scenario generation</b> for testing autonomous vechicles
50 </> 50 </>
51 } 51 }
52 href="https://doi.org/10.1007/s10270-021-00884-z" 52 href="https://doi.org/10.1007/s10270-021-00918-6"
53 /> 53 />
54 <UseCase 54 <UseCase
55 icon={<Uc2 />} 55 icon={<Uc2 />}
diff --git a/subprojects/docs/src/css/custom.css b/subprojects/docs/src/css/custom.css
index 146b45a0..3f0b5b35 100644
--- a/subprojects/docs/src/css/custom.css
+++ b/subprojects/docs/src/css/custom.css
@@ -80,14 +80,18 @@ code {
80 --ifm-navbar-shadow: var(--ifm-global-shadow-lw) !important; 80 --ifm-navbar-shadow: var(--ifm-global-shadow-lw) !important;
81} 81}
82 82
83.button, .navbar__link, .footer__link-item, .DocSearch-Button-Placeholder { 83.button, .navbar__link, .footer__link-item {
84 text-transform: uppercase; 84 text-transform: uppercase;
85 font-variation-settings: 'wdth' 87.5; 85 font-variation-settings: 'wdth' 87.5;
86} 86}
87 87
88.DocSearch-Button-Placeholder { 88.DocSearch-Button-Placeholder {
89 padding: 0 9px 0 6px !important; 89 font-family: var(--ifm-font-family-base) !important;
90 font-family: var(--ifm-font-family-base); 90}
91
92.button {
93 /* No decoration even in `::: info` boxes. */
94 text-decoration: none;
91} 95}
92 96
93.button--play::before { 97.button--play::before {
@@ -108,7 +112,7 @@ code {
108} 112}
109 113
110.navbar__inner .navbar__link--try-now { 114.navbar__inner .navbar__link--try-now {
111 margin: 0 0.75rem 0 0.5rem; 115 margin: 0 0.5rem;
112 padding: 0.25rem 1.25rem; 116 padding: 0.25rem 1.25rem;
113 border-radius: 50em; 117 border-radius: 50em;
114} 118}
@@ -145,3 +149,19 @@ code {
145.markdown svg { 149.markdown svg {
146 max-width: 100%; 150 max-width: 100%;
147} 151}
152
153.footnotes {
154 margin-top: 3rem;
155 padding-top: var(--ifm-hr-margin-vertical);
156 border-top: var(--ifm-hr-height) solid var(--ifm-hr-background-color);
157}
158
159.markdown > .footnotes ol,
160.markdown > .footnotes li:last-of-type :last-of-type {
161 margin-bottom: 0;
162}
163
164.inline-icon {
165 fill: currentColor;
166 vertical-align: text-top;
167}
diff --git a/subprojects/docs/src/develop/index.md b/subprojects/docs/src/develop/index.md
deleted file mode 100644
index 4537889e..00000000
--- a/subprojects/docs/src/develop/index.md
+++ /dev/null
@@ -1,13 +0,0 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4sidebar_position: 0
5---
6
7# Programming guide
8
9:::warning
10
11Under construction
12
13:::
diff --git a/subprojects/docs/src/develop/javadoc.md b/subprojects/docs/src/develop/javadoc.md
deleted file mode 100644
index e94e3eab..00000000
--- a/subprojects/docs/src/develop/javadoc.md
+++ /dev/null
@@ -1,40 +0,0 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4description: API documentation for Refinery components automatically generated by Javadoc
5sidebar_position: 999
6---
7
8# Javadoc
9
10Here you can find API documentation for Refinery components automatically generated by Javadoc. We recommend reading the [Programming guide](/develop) first to understand how to use these components.
11
12# Refinery
13
14* [`tools.refinery:refinery-generator`](pathname://refinery-generator)
15* [`tools.refinery:refinery-language`](pathname://refinery-language)
16* [`tools.refinery:refinery-language-ide`](pathname://refinery-language-ide)
17* [`tools.refinery:refinery-language-model`](pathname://refinery-language-model)
18* [`tools.refinery:refinery-language-semantics`](pathname://refinery-language-semantics)
19* [`tools.refinery:refinery-logic`](pathname://refinery-logic)
20* [`tools.refinery:refinery-store`](pathname://refinery-store)
21* [`tools.refinery:refinery-store-dse`](pathname://refinery-store-dse)
22* [`tools.refinery:refinery-store-dse-visualization`](pathname://refinery-store-dse-visualization)
23* [`tools.refinery:refinery-store-query`](pathname://refinery-store-query)
24* [`tools.refinery:refinery-store-query-interpreter`](pathname://refinery-store-query-interpreter)
25* [`tools.refinery:refinery-store-reasoning`](pathname://refinery-store-reasoning)
26* [`tools.refinery:refinery-store-reasoning-scope`](pathname://refinery-store-reasoning-scope)
27* [`tools.refinery:refinery-store-reasoning-smt`](pathname://refinery-store-reasoning-smt)
28
29# Interpreter
30
31:::note
32
33The _Refinery Interpreter_ is modified version of [VIATRA&trade;](https://eclipse.dev/viatra/) specifically for use in Refinery. If you're interested in learning about [VIATRA&trade;](https://eclipse.dev/viatra/), we recommend the [VIATRA&trade; documentation](https://eclipse.dev/viatra/documentation/index.html) and [source code](https://github.com/eclipse-viatra/org.eclipse.viatra) instead. Eclipse&reg;, VIATRA&trade; and &lsquo;Eclipse VIATRA&trade;&rsquo; are trademarks of Eclipse Foundation, Inc.
34
35:::
36
37* [`tools.refinery.interpreter:refinery-interpreter`](pathname://refinery-interpreter)
38* [`tools.refinery.interpreter:refinery-interpreter-localsearch`](pathname://refinery-interpreter-localsearch)
39* [`tools.refinery.interpreter:refinery-interpreter-rete`](pathname://refinery-interpreter-rete)
40* [`tools.refinery.interpreter:refinery-interpreter-rete-recipes`](pathname://refinery-interpreter-rete-recipes)
diff --git a/subprojects/docs/src/develop/contributing/commands.md b/subprojects/docs/src/docs/develop/contributing/commands.md
index abfea704..7ffe2a6c 100644
--- a/subprojects/docs/src/develop/contributing/commands.md
+++ b/subprojects/docs/src/docs/develop/contributing/commands.md
@@ -28,28 +28,14 @@ This will also be run by GitHub Actions for each commit or pull requests.
28 28
29### `publishToMavenLocal` 29### `publishToMavenLocal`
30 30
31
32```bash posix2windows 31```bash posix2windows
33./gradlew publishToMavenLocal 32./gradlew publishToMavenLocal
34``` 33```
35 34
36Publishes the Refinery Java artifacts to the [Maven local repository](https://www.baeldung.com/maven-local-repository). 35Publishes the Refinery Java artifacts to the [Maven local repository](https://www.baeldung.com/maven-local-repository).
37 36
38Build tools, such as Gradle, will be able to consume such artifacts, which enables you to use the latest version of Refinery -- possibly including your own modification -- in other Java projects. 37Build tools, such as Gradle, will be able to consume such artifacts, which enables you to use the latest version of Refinery -- possibly including your own modifications -- in other Java projects.
39 38For more information, see our [programming guide](/snapshot/develop/java).
40For example, in Gradle, you may set
41
42```kotlin title="build.gradle.kts"
43repositories {
44 mavenLocal()
45}
46
47dependencies {
48 implementation("tools.refinery:refinery-generator:0.0.0-SNAPSHOT")
49}
50```
51
52to add a dependency on Refinery to your Java project.
53 39
54### `serve` 40### `serve`
55 41
@@ -63,7 +49,7 @@ This task is ideal for running the Refinery backend if you don't intend to work
63The Refinery frontend TypeScript projects is automatically built before the server starts. 49The Refinery frontend TypeScript projects is automatically built before the server starts.
64The server will use the latest build output of the frontend as static assets. 50The server will use the latest build output of the frontend as static assets.
65 51
66The behavior of this task is influenced by the same [environmental variables](/learn/docker#environmental-variables) as the Refinery [Docker container](/learn/docker). 52The behavior of this task is influenced by the same [environmental variables](../../../learn/docker#environmental-variables) as the Refinery [Docker container](../../../learn/docker).
67However, the default value of `REFINERY_LISTEN_PORT` is `1312`. 53However, the default value of `REFINERY_LISTEN_PORT` is `1312`.
68 54
69### `serveBackend` 55### `serveBackend`
@@ -78,18 +64,18 @@ This task is ideal for running the Refinery backend if you're working on the fro
78No static assets will be build. 64No static assets will be build.
79You'll need to use [`yarnw frontend dev`](#frontend-dev) 65You'll need to use [`yarnw frontend dev`](#frontend-dev)
80 66
81Like [`gradlew serve`](#serve), the behavior of this task is influenced by the same [environmental variables](/learn/docker#environmental-variables) as the Refinery [Docker container](/learn/docker). 67Like [`./gradlew serve`](#serve), the behavior of this task is influenced by the same [environmental variables](../../../learn/docker#environmental-variables) as the Refinery [Docker container](../../../learn/docker).
82However, the default value of `REFINERY_LISTEN_PORT` is `1312`. 68However, the default value of `REFINERY_LISTEN_PORT` is `1312`.
83 69
84## Yarn commands 70## Yarn commands
85 71
86We provide a `yarnw` wrapper script to invoke the Yarn distribution installed by frontend-gradle-plugin directly. 72We provide a `yarnw` wrapper script to invoke the Yarn distribution installed by frontend-gradle-plugin directly.
87The following commands can only be run once [`gradlew build`](#build) has installed the necessary Node.js and Yarn packages. 73The following commands can only be run once [`./gradlew build`](#build) has installed the necessary Node.js and Yarn packages.
88 74
89### `docs dev` 75### `docs dev`
90 76
91```bash posix2windows 77```bash posix2windows
92./yarn docs dev 78./yarnw docs dev
93``` 79```
94 80
95Builds and serves this documentation in development mode on port 3000. 81Builds and serves this documentation in development mode on port 3000.
@@ -98,7 +84,7 @@ Saved changes to most documentation sources are immediately reflected in the bro
98You can set the port with the `-p` option, e.g. to use port 1313, use 84You can set the port with the `-p` option, e.g. to use port 1313, use
99 85
100```bash posix2windows 86```bash posix2windows
101./yarn docs dev -p 1313 87./yarnw docs dev -p 1313
102``` 88```
103 89
104:::note 90:::note
@@ -114,13 +100,13 @@ which can be safely ignored.
114### `frontend dev` 100### `frontend dev`
115 101
116```bash posix2windows 102```bash posix2windows
117./yarn frontend dev 103./yarnw frontend dev
118``` 104```
119 105
120Builds and serves the refinery frontend on port 1313. 106Builds and serves the refinery frontend on port 1313.
121Saved changes to most source files are immediately reflected in the browser without reload. 107Saved changes to most source files are immediately reflected in the browser without reload.
122 108
123Before running this command, you need to start [`gradlew serveBackend`](#servebackend) to provide a backend for the frontend to connect to. 109Before running this command, you need to start [`./gradlew serveBackend`](#servebackend) to provide a backend for the frontend to connect to.
124The development server of the frontend will proxy all WebSocket connections to the backend. 110The development server of the frontend will proxy all WebSocket connections to the backend.
125 111
126The following environmental variables influence the behavior of this command: 112The following environmental variables influence the behavior of this command:
@@ -141,7 +127,7 @@ TCP port to listen at for incoming HTTP connections.
141 127
142Hostname of the Refinery backend. 128Hostname of the Refinery backend.
143 129
144This should match the `REFINERY_LISTEN_HOST` passed to [`gradlew serveBackend`](#servebackend). 130This should match the `REFINERY_LISTEN_HOST` passed to [`./gradlew serveBackend`](#servebackend).
145 131
146**Default value:** `127.0.0.1` (connect to `localhost` over IPv4 only) 132**Default value:** `127.0.0.1` (connect to `localhost` over IPv4 only)
147 133
@@ -149,7 +135,7 @@ This should match the `REFINERY_LISTEN_HOST` passed to [`gradlew serveBackend`](
149 135
150TCP port of the Refinery backend. 136TCP port of the Refinery backend.
151 137
152This should match the `REFINERY_LISTEN_PORT` passed to [`gradlew serveBackend`](#servebackend). 138This should match the `REFINERY_LISTEN_PORT` passed to [`./gradlew serveBackend`](#servebackend).
153 139
154**Default value:** `1312` 140**Default value:** `1312`
155 141
diff --git a/subprojects/docs/src/develop/contributing/ide-setup.md b/subprojects/docs/src/docs/develop/contributing/ide-setup.md
index 742035e0..d5dd4eb5 100644
--- a/subprojects/docs/src/develop/contributing/ide-setup.md
+++ b/subprojects/docs/src/docs/develop/contributing/ide-setup.md
@@ -12,7 +12,7 @@ title: IDE setup
12We prefer [IntelliJ IDEA](https://www.jetbrains.com/idea/) as a Java development environment. 12We prefer [IntelliJ IDEA](https://www.jetbrains.com/idea/) as a Java development environment.
13No special preparations should be necessary for importing the project as a Gradle project into IDEA: 13No special preparations should be necessary for importing the project as a Gradle project into IDEA:
14 14
151. See the [required tools](/develop/contributing#required-tools) for compiling Refinery about obtaining the required JDK version. You'll also need a version of IntelliJ IDEA that supports **Java 21** (version **2023.3** or later). 151. See the [required tools](/develop/contributing#required-tools) for compiling Refinery on obtaining the required JDK version. You'll also need a version of IntelliJ IDEA that supports **Java 21** (version **2023.3** or later).
16 16
172. Clone the project git repository and open it in IntelliJ IDEA. Make sure to _open_ the project instead of creating a _new_ one in the same directory. 172. Clone the project git repository and open it in IntelliJ IDEA. Make sure to _open_ the project instead of creating a _new_ one in the same directory.
18 18
@@ -20,7 +20,7 @@ No special preparations should be necessary for importing the project as a Gradl
20 * In _Project Structure > Project settings > Project > SDK_, a Java 21 compatible JDK should be selected. 20 * In _Project Structure > Project settings > Project > SDK_, a Java 21 compatible JDK should be selected.
21 * In _Project Structure > Project settings > Project > Language level_, either _SDK default_ or _21_ should be selected. 21 * In _Project Structure > Project settings > Project > Language level_, either _SDK default_ or _21_ should be selected.
22 * Make sure that each module in _Project Structure > Project settings > Module_ uses the _Project default_ language level in _Sources > Language level_ and the _Project SDK_ in _Dependencies > Module SDK._ 22 * Make sure that each module in _Project Structure > Project settings > Module_ uses the _Project default_ language level in _Sources > Language level_ and the _Project SDK_ in _Dependencies > Module SDK._
23 * In _Settings > Gradle settings > Gralde Projects > Gradle_, the _Distribution_ should be set to _Wrapper_ and the _Gradle JVM_ should be set to _Project SDK._ 23 * In _Settings > Gradle settings > Gradle Projects > Gradle_, the _Distribution_ should be set to _Wrapper_ and the _Gradle JVM_ should be set to _Project SDK._
24 24
254. We recommend installing the latest _SonarLint_ plugin in _Settings > Plugins_ to get real-time code quality analysis in your IDE. 254. We recommend installing the latest _SonarLint_ plugin in _Settings > Plugins_ to get real-time code quality analysis in your IDE.
26 26
@@ -35,7 +35,7 @@ You'll also need [VS Code](#vs-code) to edit the TypeScript code in Refinery.
35 35
36## Eclipse 36## Eclipse
37 37
381. See the [required tools](/develop/contributing#required-tools) for compiling Refinery about obtaining the required JDK version. 381. See the [required tools](/develop/contributing#required-tools) for compiling Refinery on obtaining the required JDK version.
39 39
402. Download and extract the [Eclipse IDE for Java and DSL Developers 2023-12](https://www.eclipse.org/downloads/packages/release/2023-12/r/eclipse-ide-java-and-dsl-developers) package. 402. Download and extract the [Eclipse IDE for Java and DSL Developers 2023-12](https://www.eclipse.org/downloads/packages/release/2023-12/r/eclipse-ide-java-and-dsl-developers) package.
41 41
@@ -63,7 +63,7 @@ You'll also need [VS Code](#vs-code) to edit the TypeScript code in Refinery.
63 ``` 63 ```
64 in the cloned repository. 64 in the cloned repository.
65 * This should complete without any compilation errors. 65 * This should complete without any compilation errors.
66 * To troubleshoot any error, see the [instructions about compiling Refinery](/develop/contributing#compiling). 66 * To troubleshoot any error, see the [instructions for compiling Refinery](/develop/contributing#compiling).
67 67
688. Select _File > Import... > Gradle > Existing Gradle Project_ and import the cloned repository in Eclipse. 688. Select _File > Import... > Gradle > Existing Gradle Project_ and import the cloned repository in Eclipse.
69 * Make sure to select the root of the repository (containing this file) as the _Project root directory_ and that the _Gradle distribution_ is _Gradle wrapper_. 69 * Make sure to select the root of the repository (containing this file) as the _Project root directory_ and that the _Gradle distribution_ is _Gradle wrapper_.
@@ -73,13 +73,15 @@ You'll also need [VS Code](#vs-code) to edit the TypeScript code in Refinery.
73 73
74We recommend [VSCodium](https://github.com/VSCodium/vscodium) or [Visual Studio Code](https://code.visualstudio.com/) to work with the parts of Refinery that are written is TypeScript. 74We recommend [VSCodium](https://github.com/VSCodium/vscodium) or [Visual Studio Code](https://code.visualstudio.com/) to work with the parts of Refinery that are written is TypeScript.
75 75
761. See the [required tools](/develop/contributing#required-tools) for compiling Refinery about obtaining the required JDK version. You'll also need a version of IntelliJ IDEA that supports **Java 21** (version **2023.3** or later). 761. See the [required tools](/develop/contributing#required-tools) for compiling Refinery on obtaining the required JDK version.
77 77
782. Install the following VS Code extensions: 782. Install the following VS Code extensions:
79 * _EditorConfig for VS Code_ [[Open VSX](https://open-vsx.org/extension/EditorConfig/EditorConfig)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig)] 79 * _EditorConfig for VS Code_ [[Open VSX](https://open-vsx.org/extension/EditorConfig/EditorConfig)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig)]
80 * _ZipFS - a zip file system_ [[Open VSX](https://open-vsx.org/extension/arcanis/vscode-zipfs)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=arcanis.vscode-zipfs)]
81 * _ESLint_ [[Open VSX](https://open-vsx.org/extension/dbaeumer/vscode-eslint)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)] 80 * _ESLint_ [[Open VSX](https://open-vsx.org/extension/dbaeumer/vscode-eslint)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)]
81 * _MDX_ [[Open VSX](https://open-vsx.org/extension/unifiedjs/vscode-mdx)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=unifiedjs.vscode-mdx)]
82 * _Prettier - Code formatter_ [[Open VSX](https://open-vsx.org/extension/esbenp/prettier-vscode)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)]
82 * _XState VSCode_ [[Open VSX](https://open-vsx.org/extension/statelyai/stately-vscode)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=statelyai.stately-vscode)] 83 * _XState VSCode_ [[Open VSX](https://open-vsx.org/extension/statelyai/stately-vscode)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=statelyai.stately-vscode)]
84 * _ZipFS - a zip file system_ [[Open VSX](https://open-vsx.org/extension/arcanis/vscode-zipfs)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=arcanis.vscode-zipfs)]
83 85
843. Clone the project Git repository but _do not_ import it into VS Code yet. 863. Clone the project Git repository but _do not_ import it into VS Code yet.
85 87
diff --git a/subprojects/docs/src/develop/contributing/index.md b/subprojects/docs/src/docs/develop/contributing/index.md
index aa0bdb2f..aa0bdb2f 100644
--- a/subprojects/docs/src/develop/contributing/index.md
+++ b/subprojects/docs/src/docs/develop/contributing/index.md
diff --git a/subprojects/docs/src/docs/develop/java.md b/subprojects/docs/src/docs/develop/java.md
new file mode 100644
index 00000000..8bf796a5
--- /dev/null
+++ b/subprojects/docs/src/docs/develop/java.md
@@ -0,0 +1,460 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4sidebar_position: 0
5---
6
7# Programming guide
8
9This guide is aimed at developers who wish to create Java applications that leverage Refinery as a library.
10We also recommend browsing the [Javadoc documentation](../javadoc) associated with Refinery components.
11See the [contributor's guide](../contributing) for information on building and modifying Refinery itself.
12
13:::note
14
15Refinery can run as a cloud-based [_Graph Solver as a Service_](https://refinery.services/) without local installation.
16You can also run a compiled version as a [Docker container](../../learn/docker).
17
18:::
19
20Below, you can find instructions on using [Gradle](#gradle) or [Apache Maven](#maven) to create applications that use Refinery as a Java library.
21
22## Working with Gradle {#gradle}
23
24We recommend [Gradle](https://gradle.org/) as a build system for creating Java programs that use Refinery as a library.
25We created a [Gradle plugin](pathname://../javadoc/refinery-gradle-plugins/) to simplify project configuration.
26
27This tutorial explains how to use a **snapshot** or **local** pre-release version of Refinery with Gradle.
28Released versions, such as the [**latest version**](/develop/java#gradle), are available from [Maven Central](https://central.sonatype.com/namespace/tools.refinery).
29
30import Tabs from '@theme/Tabs';
31import TabItem from '@theme/TabItem';
32
33<Tabs groupId="version">
34 <TabItem value="snapshot" label="Snapshot" default>
35 We always publish a [SNAPSHOT](https://maven.apache.org/guides/getting-started/index.html#what-is-a-snapshot-version) version of Refinery based on the latest commit in our [Git repository](https://github.com/graphs4value/refinery). This is the development version of our code and may change without warning at any time.
36
37 To find out the configuration for using our snapshot artifacts, select whether you use a Kotlin-based (`.gradle.kts`) or a Groovy-based (`.gradle`) configuration format for your Gradle build. You should add this code to your Gradle *settings* file, which is named `settings.gradle.kts` or `settings.gradle`.
38
39 <Tabs groupId="gradleLanguage">
40 <TabItem value="kotlin" label="Kotlin">
41 ```kotlin title="settings.gradle.kts"
42 pluginManagement {
43 repositories {
44 maven {
45 name = "refinery-snapshots"
46 url = uri("https://refinery.tools/maven/snapshots/")
47 }
48 gradlePluginPortal()
49 }
50 }
51
52 plugins {
53 id("tools.refinery.settings") version "@@@version@@@"
54 }
55 ```
56 </TabItem>
57 <TabItem value="groovy" label="Groovy">
58 ```groovy title="settings.gradle"
59 pluginManagement {
60 repositories {
61 maven {
62 name 'refinery-snapshots'
63 url 'https://refinery.tools/maven/snapshots/'
64 }
65 gradlePluginPortal()
66 }
67 }
68
69 plugins {
70 id 'tools.refinery.settings' version '@@@version@@@'
71 }
72 ```
73 </TabItem>
74 </Tabs>
75 </TabItem>
76 <TabItem value="mavenLocal" label="Local">
77 Running Refinery from a local build is an _advanced technique_ that you should only use if you want to [contribute to Refinery](../contributing) and have modified it yourself.
78 First you'll have to run the [`./gradlew publishToMavenLocal`](../contributing/commands#publishtomavenlocal) command in your local clone of the Refinery repository to install Refinery into your [local Maven repository](https://www.baeldung.com/maven-local-repository).
79
80 Next, to find out the configuration for using local artifacts, select whether you use a Kotlin-based (`.gradle.kts`) or a Groovy-based (`.gradle`) configuration format for your Gradle build. You should add this code to your Gradle *settings* file, which is named `settings.gradle.kts` or `settings.gradle`.
81
82 <Tabs groupId="gradleLanguage">
83 <TabItem value="kotlin" label="Kotlin">
84 ```kotlin title="settings.gradle.kts"
85 pluginManagement {
86 repositories {
87 mavenLocal()
88 gradlePluginPortal()
89 }
90 }
91
92 plugins {
93 id("tools.refinery.settings") version "@@@version@@@"
94 }
95 ```
96 </TabItem>
97 <TabItem value="groovy" label="Groovy">
98 ```groovy title="settings.gradle"
99 pluginManagement {
100 repositories {
101 mavenLocal()
102 gradlePluginPortal()
103 }
104 }
105
106 plugins {
107 id 'tools.refinery.settings' version '@@@version@@@'
108 }
109 ```
110 </TabItem>
111 </Tabs>
112 </TabItem>
113</Tabs>
114
115This plugin will perform the following actions automatically:
116* Add a [version catalog](https://docs.gradle.org/current/userguide/platforms.html#sec:sharing-catalogs) to your build to enable easy access to Refinery artifacts and their [dependencies](#declaring-dependencies).
117* Lock refinery artifacts and their dependencies to a [platform](https://docs.gradle.org/current/userguide/platforms.html#sub:using-platform-to-control-transitive-deps) (Maven BOM) of tested versions.
118* Configure a logger based on [Log4J over SLF4J](https://www.slf4j.org/legacy.html) and [SLF4J Simple](https://www.slf4j.org/apidocs/org/slf4j/simple/SimpleLogger.html) that is free from vulnerabilities and works out of the box for most use-cases.
119* Generate [application](#building-applications) artifacts, if any, according to best practices used in the Refinery project.
120* Add common dependencies for writing [unit tests](#writing-tests) for your Java code.
121
122See the [multi-module projects](#multi-module-projects) section of this tutorial on how to disable some of these automated actions for a part of your build.
123
124### Declaring dependencies
125
126The Refinery Gradle plugins adds a [version catalog](https://docs.gradle.org/current/userguide/platforms.html#sec:sharing-catalogs) named `refinery` that you can use to quickly access dependencies.
127For example, to add a dependency to the [`tools.refinery:refinery-generator`](pathname://../javadoc/refinery-generator/) library, you add the following to your `build.gradle.kts` or `build.gradle` file:
128
129<Tabs groupId="gradleLanguage">
130 <TabItem value="kotlin" label="Kotlin">
131 ```kotlin title="build.gradle.kts"
132 depndencies {
133 implementation(refinery.generator)
134 }
135 ```
136 </TabItem>
137 <TabItem value="groovy" label="Groovy">
138 ```groovy title="build.gradle"
139 dependencies {
140 implementation refinery.generator
141 }
142 ```
143 </TabItem>
144</Tabs>
145
146The version catalog also contains the external dependencies used by the Refinery framework.
147For example, you may add [GSON](https://google.github.io/gson/) for JSON parsing and [JCommander](https://jcommander.org/) for command-line argument parsing as follows:
148
149<Tabs groupId="gradleLanguage">
150 <TabItem value="kotlin" label="Kotlin">
151 ```kotlin title="build.gradle.kts"
152 depndencies {
153 implementation(refinery.gson)
154 implementation(refinery.jcommander)
155 }
156 ```
157 </TabItem>
158 <TabItem value="groovy" label="Groovy">
159 ```groovy title="build.gradle"
160 dependencies {
161 implementation refinery.gson
162 implementation refinery.jcommander
163 }
164 ```
165 </TabItem>
166</Tabs>
167
168### Building applications
169
170You can use the built-in [`application`](https://docs.gradle.org/current/userguide/application_plugin.html) to build stand-alone Java applications.
171
172When developing you main application code in the `src/main/java` directory of you project, you can use the [`StandaloneRefinery`](pathname://../javadoc/refinery-generator/tools/refinery/generator/standalone/StandaloneRefinery.html) class from [`tools.refinery:refinery-generator`](pathname://../javadoc/refinery-generator/) to access Refinery generator components. See the tutorial on Xtext's [dependency injection](https://eclipse.dev/Xtext/documentation/302_configuration.html#dependency-injection) for more advanced use-cases.
173
174```java
175package org.example;
176
177import tools.refinery.generator.standalone.StandaloneRefinery;
178
179import java.io.IOException;
180
181public class ExampleMain {
182 public static void main(String[] args) throws IOException {
183 var problem = StandaloneRefinery.getProblemLoader().loadString("""
184 class Filesystem {
185 contains Directory[1] root
186 }
187
188 class File.
189
190 class Directory extends File {
191 contains Directory[] children
192 }
193
194 scope Filesystem = 1, File = 20.
195 """);
196 var generator = StandaloneRefinery.getGeneratorFactory().createGenerator(problem);
197 generator.generate();
198 var trace = generator.getProblemTrace();
199 var childrenRelation = trace.getPartialRelation("Directory::children");
200 var childrenInterpretation = generator.getPartialInterpretation(childrenRelation);
201 var cursor = childrenInterpretation.getAll();
202 while (cursor.move()) {
203 System.out.printf("%s: %s%n", cursor.getKey(), cursor.getValue());
204 }
205 }
206}
207```
208
209If you want to produce a "fat JAR" that embeds all dependencies (e.g., for invoking from the command line or from Python with a single command), you should also add the [shadow](https://github.com/Goooler/shadow) plugin.
210The recommended version of the shadow plugin is set in our [version catalog](#declaring-dependencies). You can add it to your build script as follows:
211
212<Tabs groupId="gradleLanguage">
213 <TabItem value="kotlin" label="Kotlin">
214 ```kotlin title="build.gradle.kts"
215 plugins {
216 application
217 alias(refinery.plugins.shadow)
218 }
219
220 application {
221 mainClass = "org.example.ExampleMain"
222 }
223 ```
224 </TabItem>
225 <TabItem value="groovy" label="Groovy">
226 ```groovy title="build.gradle"
227 plugins {
228 application
229 alias refinery.plugins.shadow
230 }
231
232 application {
233 mainClass 'org.example.ExampleMain'
234 }
235 ```
236 </TabItem>
237</Tabs>
238
239After building your project with `./gradlew build`, you may find the produced "fat JAR" in the `build/libs` directory.
240Its file name will be suffixed with `-all.jar`.
241In you have Java 21 installed, you'll be able to run the application with the command
242
243<Tabs groupId="posix2windows">
244 <TabItem value="posix" label="Linux or macOS">
245 ```bash
246 java -jar ./build/libs/example-0.0.0-SNAPSHOT-all.jar
247 ```
248 </TabItem>
249 <TabItem value="windows" label="Windows (PowerShell)">
250 ```bash
251 java -jar .\build\libs\example-0.0.0-SNAPSHOT-all.jar
252 ```
253 </TabItem>
254</Tabs>
255
256Be sure to replace `example-0.0.0-SNAPSHOT` with the name and version of your project.
257
258### Writing tests
259
260Our Gradle plugin automatically sets up [JUnit 5](https://junit.org/junit5/) for writing tests and [parameterized tests](https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests).
261It also sets up [Hamcrest](https://hamcrest.org/JavaHamcrest/) for writing assertions.
262You should put your test files into the `src/test/java` directory in your projects.
263You may run test with the commands `./gradlew test` or `./gradlew build`.
264
265To ensure that your tests are properly isolated, you should *not* rely on the [`StandaloneRefinery`](pathname://../javadoc/refinery-generator/tools/refinery/generator/standalone/StandaloneRefinery.html) class from [`tools.refinery:refinery-generator`](pathname://../javadoc/refinery-generator/) when accessing Refinery generator components.
266Instead, you should use Xtext's [dependency injection](https://eclipse.dev/Xtext/documentation/302_configuration.html#dependency-injection) and [unit testing](https://eclipse.dev/Xtext/documentation/103_domainmodelnextsteps.html#tutorial-unit-tests) support to instantiate the components. You'll need to add a dependency to Refinery's Xtext testing support library to your project.
267
268<Tabs groupId="gradleLanguage">
269 <TabItem value="kotlin" label="Kotlin">
270 ```kotlin title="build.gradle.kts"
271 depndencies {
272 implementation(refinery.generator)
273 // highlight-next-line
274 testImplementation(testFixtures(refinery.language))
275 }
276 ```
277 </TabItem>
278 <TabItem value="groovy" label="Groovy">
279 ```groovy title="build.gradle"
280 dependencies {
281 implementation refinery.generator
282 // highlight-next-line
283 testImplementation testFixtures(refinery.language)
284 }
285 ```
286 </TabItem>
287</Tabs>
288
289The test fixtures for `refinery-language` include the `@InjectWithRefinery` [composed annotation](https://junit.org/junit5/docs/current/user-guide/#writing-tests-meta-annotations) to simplify Xtext injector configuration.
290You can use this annotation in conjunction with `@Inject` annotations to set up your unit test.
291
292```java
293package org.example;
294
295import com.google.inject.Inject;
296import org.junit.jupiter.api.Test;
297import tools.refinery.generator.GeneratorResult;
298import tools.refinery.generator.ModelGeneratorFactory;
299import tools.refinery.generator.ProblemLoader;
300import tools.refinery.language.tests.InjectWithRefinery;
301
302import java.io.IOException;
303
304import static org.hamcrest.MatcherAssert.assertThat;
305import static org.hamcrest.Matchers.*;
306
307// highlight-start
308@InjectWithRefinery
309// highlight-end
310class ExampleTest {
311 // highlight-start
312 @Inject
313 private ProblemLoader problemLoader;
314
315 @Inject
316 private ModelGeneratorFactory generatorFactory;
317 // highlight-end
318
319 @Test
320 void testModelGeneration() throws IOException {
321 var problem = problemLoader.loadString("""
322 class Filesystem {
323 contains Directory[1] root
324 }
325
326 class File.
327
328 class Directory extends File {
329 contains Directory[] children
330 }
331
332 scope Filesystem = 1, File = 20.
333 """);
334 var generator = generatorFactory.createGenerator(problem);
335 var result = generator.tryGenerate();
336 assertThat(result, is(GeneratorResult.SUCCESS));
337 }
338}
339```
340
341### Multi-module projects
342
343By default, the `tools.refinery.settings` plugin will apply our `tools.refinery.java` plugin to all Java projects in your build and configure them for use with Refinery. This is sufficient for single-module Java projects, and multi-module projects where all of your Java modules use Refinery.
344
345If you wish to use Refinery in only some modules in your multi-module project, you can disable this behavior by adding
346
347```ini title="gradle.properties"
348tools.refinery.gradle.auto-apply=false
349```
350
351to the `gradle.properties` file in the root directory of your project.
352
353If you use this setting, you'll need to add the `tools.refinery.java` plugin manually to any Java projects where you want to use Refinery like this:
354
355<Tabs groupId="gradleLanguage">
356 <TabItem value="kotlin" label="Kotlin">
357 ```kotlin title="build.gradle.kts"
358 plugins {
359 id("tools.refinery.java")
360 }
361 ```
362 </TabItem>
363 <TabItem value="groovy" label="Groovy">
364 ```groovy title="build.gradle"
365 plugins {
366 id 'tools.refinery.java'
367 }
368 ```
369 </TabItem>
370</Tabs>
371
372Do *not* attempt to set a `version` for this plugin, because versioning is already managed by the `tools.refinery.settings` plugin. Trying to set a version for the `tools.refinery.java` plugin separately will result in a Gradle error.
373
374## Working with Maven {#maven}
375
376You may also develop applications based on Refiney using [Apache Maven](https://maven.apache.org/) as the build system.
377Although we don't provide a Maven plugin for simplified configuration, you can still use our [platform](https://docs.gradle.org/current/userguide/platforms.html#sub:using-platform-to-control-transitive-deps) (Maven BOM) to lock the versions of Refinery and its dependencies to tested versions.
378
379This tutorial explains how to use a **snapshot** or **local** pre-release version of Refinery with Maven.
380Released versions, such as the [**latest version**](/develop/java#maven), are available from [Maven Central](https://central.sonatype.com/namespace/tools.refinery).
381
382<Tabs groupId="version">
383 <TabItem value="snapshot" label="Snapshot" default>
384 We always publish a [SNAPSHOT](https://maven.apache.org/guides/getting-started/index.html#what-is-a-snapshot-version) version of Refinery based on the latest commit in our [Git repository](https://github.com/graphs4value/refinery). This is the development version of our code and may change without warning at any time.
385
386 You should add the following configuration to your `pom.xml` file. If you use multi-module projects, we recommend that you add this to your parent POM.
387
388 ```xml title="pom.xml"
389 <project>
390 ...
391 <repositories>
392 <repository>
393 <id>refinery-snapshots</id>
394 <name>Refinery Snapshots</name>
395 <url>https://refinery.tools/maven/snapshots/</url>
396 <releases>
397 <enabled>false</enabled>
398 </releases>
399 <snapshots>
400 <enabled>true</enabled>
401 </snapshots>
402 </repository>
403 </repositories>
404 <dependencyManagement>
405 <dependencies>
406 <dependency>
407 <groupId>tools.refinery</groupId>
408 <artifactId>refinery-bom</artifactId>
409 <version>@@@version@@@</version>
410 <type>pom</type>
411 <scope>import</scope>
412 </dependency>
413 </dependencies>
414 </dependencyManagement>
415 ...
416 </project>
417 ```
418 </TabItem>
419 <TabItem value="mavenLocal" label="Local">
420 Running Refinery from a local build is an _advanced technique_ that you should only use if you want to [contribute to Refinery](../contributing) and have modified it yourself.
421 First you'll have to run the [`./gradlew publishToMavenLocal`](../contributing/commands#publishtomavenlocal) command in your local clone of the Refinery repository to install Refinery into your [local Maven repository](https://www.baeldung.com/maven-local-repository).
422
423 Next, you should add the following configuration to your `pom.xml` file. If you use multi-module projects, we recommend that you add this to your parent POM.
424
425 ```xml title="pom.xml"
426 <project>
427 ...
428 <dependencyManagement>
429 <dependencies>
430 <dependency>
431 <groupId>tools.refinery</groupId>
432 <artifactId>refinery-bom</artifactId>
433 <version>@@@version@@@</version>
434 <type>pom</type>
435 <scope>import</scope>
436 </dependency>
437 </dependencies>
438 </dependencyManagement>
439 ...
440 </project>
441 ```
442 </TabItem>
443</Tabs>
444
445You'll be able to add dependencies to Refinery components without an explicit reference to the dependency version, since version numbers are managed by the BOM:
446
447```xml title="pom.xml"
448<project>
449 ...
450 <dependencies>
451 <dependency>
452 <groupId>tools.refinery</groupId>
453 <artifactId>refinery-generator</artifactId>
454 </dependency>
455 </dependencies>
456 ...
457</project>
458```
459
460However, since the Maven BOM doesn't offer additional configuration, you'll have to take care of tasks such as configuring logging and testing, as well as building applications yourself.
diff --git a/subprojects/docs/src/docs/develop/javadoc.md b/subprojects/docs/src/docs/develop/javadoc.md
new file mode 100644
index 00000000..b85825b5
--- /dev/null
+++ b/subprojects/docs/src/docs/develop/javadoc.md
@@ -0,0 +1,41 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4description: API documentation for Refinery components automatically generated by Javadoc
5sidebar_position: 998
6---
7
8# Javadoc
9
10Here you can find API documentation for Refinery components automatically generated by Javadoc. We recommend reading the [Programming guide](../java/) first to understand how to use these components.
11
12# Refinery
13
14* [`tools.refinery:refinery-generator:@@@version@@@`](pathname://refinery-generator/)
15* [`tools.refinery:refinery-gradle-plugins:@@@version@@@`](pathname://refinery-gradle-plugins/)
16* [`tools.refinery:refinery-language:@@@version@@@`](pathname://refinery-language/)
17* [`tools.refinery:refinery-language-ide:@@@version@@@`](pathname://refinery-language-ide/)
18* [`tools.refinery:refinery-language-model:@@@version@@@`](pathname://refinery-language-model/)
19* [`tools.refinery:refinery-language-semantics:@@@version@@@`](pathname://refinery-language-semantics/)
20* [`tools.refinery:refinery-logic:@@@version@@@`](pathname://refinery-logic/)
21* [`tools.refinery:refinery-store:@@@version@@@`](pathname://refinery-store/)
22* [`tools.refinery:refinery-store-dse:@@@version@@@`](pathname://refinery-store-dse/)
23* [`tools.refinery:refinery-store-dse-visualization:@@@version@@@`](pathname://refinery-store-dse-visualization/)
24* [`tools.refinery:refinery-store-query:@@@version@@@`](pathname://refinery-store-query/)
25* [`tools.refinery:refinery-store-query-interpreter:@@@version@@@`](pathname://refinery-store-query-interpreter/)
26* [`tools.refinery:refinery-store-reasoning:@@@version@@@`](pathname://refinery-store-reasoning/)
27* [`tools.refinery:refinery-store-reasoning-scope:@@@version@@@`](pathname://refinery-store-reasoning-scope/)
28* [`tools.refinery:refinery-store-reasoning-smt:@@@version@@@`](pathname://refinery-store-reasoning-smt/)
29
30# Interpreter
31
32:::note
33
34The _Refinery Interpreter_ is modified version of [VIATRA&trade;](https://eclipse.dev/viatra/) specifically for use in Refinery. If you're interested in learning about [VIATRA&trade;](https://eclipse.dev/viatra/), we recommend the [VIATRA&trade; documentation](https://eclipse.dev/viatra/documentation/index.html) and [source code](https://github.com/eclipse-viatra/org.eclipse.viatra) instead. Eclipse&reg;, VIATRA&trade; and &lsquo;Eclipse VIATRA&trade;&rsquo; are trademarks of Eclipse Foundation, Inc.
35
36:::
37
38* [`tools.refinery.interpreter:refinery-interpreter:@@@tools.refinery.interpreter.version@@@`](pathname://refinery-interpreter/)
39* [`tools.refinery.interpreter:refinery-interpreter-localsearch:@@@tools.refinery.interpreter.version@@@`](pathname://refinery-interpreter-localsearch/)
40* [`tools.refinery.interpreter:refinery-interpreter-rete:@@@tools.refinery.interpreter.version@@@`](pathname://refinery-interpreter-rete/)
41* [`tools.refinery.interpreter:refinery-interpreter-rete-recipes:@@@tools.refinery.interpreter.version@@@`](pathname://refinery-interpreter-rete-recipes/)
diff --git a/subprojects/docs/src/docs/learn/docker/cli.md b/subprojects/docs/src/docs/learn/docker/cli.md
new file mode 100644
index 00000000..0c3df088
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/docker/cli.md
@@ -0,0 +1,145 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4sidebar_position: 1
5sidebar_label: CLI
6---
7
8# Command-line interface
9
10You can run Refinery as a command-line applications via our [Docker container](https://github.com/graphs4value/refinery/pkgs/container/refinery-cli) on either `amd64` or `arm64` machines:
11
12```shell
13docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:latest
14```
15
16This will let you read input files and generate models in the current directory (`${PWD}`) of your terminal session.
17Module imports (e.g., `import some::module.` to import `some/module.refinery`) relative to the current directory are also supported.
18
19For example, to generate a model based on the file named `input.problem` in the current directory and write the results into the file named `output.refinery`, you may run the [`generate` subcommand](#generate) with
20
21```shell
22docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:latest generate -o output.refinery input.problem
23```
24
25If you want Refinery CLI to print its documentation, run
26
27```shell
28docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:latest -help
29```
30
31## The `generate` subcommand {#generate}
32
33The `generate` subcommand generates a consistent concrete model from a partial model.
34
35```shell
36docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:latest generate [options] input path
37```
38
39The `input path` should be a path to a `.problem` file relative to the current directory.
40Due to Docker containerization, paths _outside_ the current directory (e.g., `../input.problem`) are not supported.
41
42Passing `-` as the `input path` will read a partial model from the standard input.
43
44By default, the generator is _deterministic_ and always outputs the same concrete model. See the [`-random-seed`](#generate-random-seed) option to customize this behavior.
45
46See below for the list of supported `[options]`.
47
48### `-output`, `-o` {#generate-output}
49
50The output path for the generated model.
51Passing `-o -` will write the generated model to the standard output.
52
53When generating multiple models with [`-solution-number`](#generate-solution-number), the value `-` is not supported and individual solutions will be saved to numbered files.
54For example, if you pass `-o output.refinery -n 10`, solutions will be saved as `output_001.refinery`, `output_002.refinery`, ..., `output_010.refinery`.
55
56**Default value:** `-`, i.e., the solution is written to the standard output.
57
58### `-random-seed`, `-r` {#generate-random-seed}
59
60Random seed to control the behavior of model generation.
61
62The same random seed value and Refinery release will produce the same output model for an input problem.
63Models generated with different values of `-random-seed` are highly likely (but are not guaranteed) to be _substantially_ different.
64
65**Default value:** `1`
66
67### `-scope`, `-s` {#generate-scope}
68
69Add [scope constraints](../../language/logic#type-scopes) to the input problem.
70
71This option is especially useful if you want to generate models of multiple sizes from the same partial model.
72
73For example, the command
74
75```shell
76docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:latest generate -s File=20..25 input.problem
77```
78
79is equivalent to appending
80
81```refinery title="input.problem"
82scope File = 20..25.
83```
84
85to `input.problem`.
86The syntax of the argument is equivalent to the [`scope`](../../language/logic#type-scopes) declaration, but you be careful with the handling of spaces in your shell.
87Any number of `-s` arguments are supported. For example, the following argument lists are equivalent:
88
89```shell
90-scope File=20..25,Directory=3
91-s File=20..25,Directory=3
92-s File=20..25 -s Directory=3
93-s "File = 20..25, Directory = 3"
94-s "File = 20..25" -s "Directory = 3"
95```
96
97The `*` opeator also has to be quoted to avoid shell expansion:
98
99```shell
100-s "File=20..*"
101```
102
103### `-scope-override`, `-S` {#generate-scope-override}
104
105Override [scope constraints](../../language/logic#type-scopes) to the input problem.
106
107This argument is similar to [`-scope`](#generate-scope), but has higher precedence than the [`scope`](../../language/logic#type-scopes) declarations already present in the input file.
108However, you can't override `scope` declarations in modules imported in the input file using the `import` statement.
109
110For example, if we have
111
112```refinery title="input.problem"
113scope File = 20..25, Directory = 3.
114```
115
116in the input file, the arguments `-s File=10..12 input.problem` will be interpreted as
117
118```refinery
119scope File = 20..25, Directory = 3.
120scope File = 10..12.
121```
122
123which results in an _unsatisfiable_ problem. If the use `-S File=10..12 input.problem` instead, the type scope for `File` is overridden as
124
125```refinery
126scope Directory = 3.
127scope File = 10..12.
128```
129
130and model generation can proceed as requested. Since we had specified no override for `Directory`, its type scope declared in `input.problem` was preserved.
131
132Scope overrides do not override additional scopes, i.e., `-s File=20..30 -S File=10..25` is interpreted as `-S File=20..25`.
133
134### `-solution-number`, `-n` {#generate-solution-number}
135
136The number of distinct solutions to generate.
137
138Generated solutions are always different, but are frequently not _substantially_ different, i.e., the differences between generated solutions comprise only a few model elements.
139You'll likely generate substantially different models by calling the generator multiple times with different [`-random-seed`](#generate-random-seed) values instead.
140
141The generator will create [numbered output files](#generate-output) for each solution found.
142The generation is considered successful if it finds at least one solution, but may find less than the requested number of solutions if no more exist.
143In this case, there will be fewer output files than requested.
144
145**Default value:** `1`
diff --git a/subprojects/docs/src/docs/learn/docker/index.md b/subprojects/docs/src/docs/learn/docker/index.md
new file mode 100644
index 00000000..1499bea3
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/docker/index.md
@@ -0,0 +1,165 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4autogenerated_sidebar_hidden: true
5sidebar_position: 100
6sidebar_label: Docker
7---
8
9# Running in Docker
10
11:::note
12
13Refinery can run as a cloud-based _Graph Solver as a Service_ without local installation.
14If you're just looking to try Refinery, our [online demo](https://refinery.services/) provides a seamless experience without installation.
15
16:::
17
18:::info
19
20Installing Refinery as a Docker container can support more advanced use cases, such as when generating models with more resources or a longer timeout.
21
22:::
23
24To generate larger models with a longer timeout, you can use our [Docker container](https://github.com/graphs4value/refinery/pkgs/container/refinery) on either `amd64` or `arm64` machines:
25
26```shell
27docker run --rm -it -p 8888:8888 ghcr.io/graphs4value/refinery:latest
28```
29
30Once Docker pulls and starts the container, you can navigate to http://localhost:8888 to open the model generation interface and start editing.
31
32A [command-line interface (CLI)](cli) version of Refinery is also available as a Docker container.
33
34Alternatively, you can follow the [instructions to set up a local development environment](/develop/contributing) and compile and run Refinery from source.
35
36## Environmental variables
37
38The Docker container supports the following environmental variables to customize its behavior.
39Customizing these variables should only be needed if you want to _increase resource limits_ or _expose your Refinery instance over the network_ for others.
40
41Notes for **local-only instances** are highlighted with the :arrow_right: arrow emoji.
42
43Important security notices for **public instances** are highlighted with the :warning: warning emoji.
44
45### Networking
46
47#### `REFINERY_LISTEN_HOST`
48
49Hostname to listen at for incoming HTTP connections.
50
51**Default value:** `0.0.0.0` (accepts connections on any IP address)
52
53#### `REFINERY_LISTEN_PORT`
54
55TCP port to listen at for incoming HTTP connections.
56
57Refinery doesn't support HTTPS connections out of the box, so there's no point in setting this to `443`. Use a [reverse proxy](https://en.wikipedia.org/wiki/Reverse_proxy) instead if you wish to expose Refinery to encrypted connections.
58
59If you change this value, don't forget to adjust the `-p 8888:8888` option of the `docker run` command to [expose](https://docs.docker.com/reference/cli/docker/container/run/#publish) the selected port.
60
61**Default value:** `8888`
62
63#### `REFINERY_PUBLIC_HOST`
64
65Publicly visible hostname of the Refinery instance.
66
67:arrow_right: For installations only accessed locally (i.e., `localhost:8888`) without any reverse proxy, you can safely leave this empty.
68
69:warning: You should set this to the publicly visible hostname of your Refinery instance if you wish to expose Refinery over the network. Most likely, this will be the hostname of a reverse proxy that terminates TLS connections. Our online demo sets this to [refinery.services](https://refinery.services/).
70
71**Default value:** _empty_
72
73#### `REFINERY_PUBLIC_PORT`
74
75Publicly visible port of the Refinery instance.
76
77:arrow_right: For installations only accessed locally (i.e., `localhost:8888`), this value is ignored because `REFINERY_PUBLC_HOST` is not set.
78
79**Default value:** `443`
80
81#### `REFINERY_ALLOWED_ORIGINS`
82
83Comma-separated list of allowed origins for incoming WebSocket connections. If this variable is empty, all incoming WebSocket connections are accepted.
84
85:arrow_right: For installations only accessed locally (i.e., `localhost:8888`) without any reverse proxy, you can safely leave this empty.
86
87:warning: The value inferred from `REFINERY_PUBLIC_HOST` and `REFINERY_PUBLIC_PORT` should be suitable for instances exposed over the network. For security reasons, public instances should never leave this empty.
88
89**Default value:** equal to `REFINERY_PUBLIC_HOST:REFINERY_PUBLIC_PORT` if they are both set, _empty_ otherwise
90
91### Timeouts
92
93#### `REFINERY_SEMANTICS_TIMEOUT_MS`
94
95Timeout for partial model semantics calculation in milliseconds.
96
97:arrow_right: Increase this if you have a slower machine and the editor times out before showing a preview of your partial model in the _Graph_ or _Table_ views.
98
99:warning: Increasing this timeout may increase server load. Excessively large timeout may allow users to overload you server by entering extremely complex partial models.
100
101**Default value:** `1000`
102
103#### `REFINERY_SEMANTICS_WARMUP_TIMEOUT_MS`
104
105Timeout for partial model semantics calculation in milliseconds when the server first start.
106
107Due to various initialization tasks, the first partial model semantics generation may take longer the `REFINERY_SEMANTICS_TIMEOUT_MS` and display a timeout error. This setting increases the timeout for the first generation, leading to seamless use even after server start (especially in auto-scaling setups).
108
109**Default value:** equal to 2 &times; `REFINERY_SEMANTICS_TIMEOUT`
110
111#### `REFINERY_MODEL_GENERATION_TIMEOUT_SEC`
112
113Timeout for model generation in seconds.
114
115:arrow_right: Adjust this value if you're generating very large models (> 10000 nodes) and need more time to complete a generation. Note that some _unsatisfiable_ model generation problems cannot be detected by Refinery and will result in model generation running for an arbitrarily long time without producing any solution.
116
117:warning: Long running model generation will block a [_model generation thread_](#refinery_model_generation_thread_count). Try to balance the number of threads and the timeout to avoid exhausting system resources, but keep the wait time for a free model generation thread for users reasonably short. Auto-scaling to multiple instances may help with bursty demand.
118
119**Default value:** `600` (10 minutes)
120
121### Threading
122
123:arrow_right: If you only run a single model generation task at a time, you don't need to adjust these settings.
124
125:warning: Excessively large thread counts may overload the server. Make sure that _all_ Refinery threads can run at the same time to avoid thread starvation.
126
127#### `REFINERY_XTEXT_THREAD_COUNT`
128
129Number of threads used for non-blocking text editing operations. A value of `0` allows an _unlimited_ number of threads by running each semantics calculation in a new thread.
130
131**Default value:** `1`
132
133#### `REFINERY_XTEXT_LOCKING_THREAD_COUNT`
134
135Number of threads used for text editing operations that lock the document. A value of `0` allows an _unlimited_ number of threads by running each semantics calculation in a new thread.
136
137**Default value:** equal to `REFINERY_XTEXT_THREAD_COUNT`
138
139#### `REFINERY_XTEXT_SEMANTICS_THREAD_COUNT`
140
141Number of threads used for model semantics calculation. A value of `0` allows an _unlimited_ number of threads by running each semantics calculation in a new thread.
142
143Must be at least as large as `REFINERY_XTEXT_THREAD_COUNT`.
144
145**Default value:** equal to `REFINERY_XTEXT_THREAD_COUNT`
146
147#### `REFINERY_MODEL_GENERATION_THREAD_COUNT`
148
149Number of threads used for model semantics calculation. A value of `0` allows an _unlimited_ number of threads by running each semantics calculation in a new thread.
150
151:warning: Each model generation task may also demand a large amount of memory in addition to CPU time.
152
153**Default value:** equal to `REFINERY_XTEXT_THREAD_COUNT`
154
155### Libraries
156
157#### `REFINERY_LIBRARY_PATH`
158
159Modules (`.refinery` files) in this directory or colon-separated list of directories will be exposed to user via Refinery's `import` mechanism.
160
161:arrow_right: Use this in conjunction with the [mount volume (-v)](https://docs.docker.com/reference/cli/docker/container/run/#volume) option of `docker run` to work with multi-file projects in Refinery.
162
163:warning: Only expose files that you want to make public. It's best to expose a directory that contains nothing other than `.refinery` files to minimize potential information leaks.
164
165**Default value:** _empty_ (no directories are exposed)
diff --git a/subprojects/docs/src/docs/learn/index.md b/subprojects/docs/src/docs/learn/index.md
new file mode 100644
index 00000000..7f67fd86
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/index.md
@@ -0,0 +1,11 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4sidebar_position: 0
5---
6
7# Introduction
8
9Various software and systems engineering scenarios rely on the systematic construction of consistent graph models. However, **automatically generating a diverse set of consistent graph models** for complex domain specifications is challenging. First, the graph generation problem must be specified with mathematical precision. Moreover, graph generation is a computationally complex task, which necessitates specialized logic solvers.
10
11**Refinery is an open-source software framework** for the automated synthesis of a diverse set of consistent domain-specific graph models. The framework offers an expressive high-level specification language using partial models to succinctly formulate a wide range of graph generation challenges. It also provides a modern cloud-based architecture for a scalable _Graph Solver as a Service,_ which uses logic reasoning rules to efficiently synthesize a diverse set of solutions to graph generation problems by partial model refinement. Applications include system-level architecture synthesis, test generation for modeling tools or traffic scenario synthesis for autonomous vehicles.
diff --git a/subprojects/docs/src/learn/language/_category_.yml b/subprojects/docs/src/docs/learn/language/_category_.yml
index f5a6f896..a261ebf6 100644
--- a/subprojects/docs/src/learn/language/_category_.yml
+++ b/subprojects/docs/src/docs/learn/language/_category_.yml
@@ -6,5 +6,5 @@ position: 2
6label: Language reference 6label: Language reference
7link: 7link:
8 type: generated-index 8 type: generated-index
9 slug: /language 9 slug: /learn/language
10 description: Learn more about the Refinery partial modeling language! 10 description: Learn more about the Refinery partial modeling language!
diff --git a/subprojects/docs/src/learn/language/classes/ContainmentInstance.svg b/subprojects/docs/src/docs/learn/language/classes/ContainmentInstance.svg
index 197f4b48..197f4b48 100644
--- a/subprojects/docs/src/learn/language/classes/ContainmentInstance.svg
+++ b/subprojects/docs/src/docs/learn/language/classes/ContainmentInstance.svg
diff --git a/subprojects/docs/src/learn/language/classes/ContainmentInstance.svg.license b/subprojects/docs/src/docs/learn/language/classes/ContainmentInstance.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/language/classes/ContainmentInstance.svg.license
+++ b/subprojects/docs/src/docs/learn/language/classes/ContainmentInstance.svg.license
diff --git a/subprojects/docs/src/learn/language/classes/InvalidInstance.svg b/subprojects/docs/src/docs/learn/language/classes/InvalidInstance.svg
index fb9dd37d..fb9dd37d 100644
--- a/subprojects/docs/src/learn/language/classes/InvalidInstance.svg
+++ b/subprojects/docs/src/docs/learn/language/classes/InvalidInstance.svg
diff --git a/subprojects/docs/src/learn/language/classes/InvalidInstance.svg.license b/subprojects/docs/src/docs/learn/language/classes/InvalidInstance.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/language/classes/InvalidInstance.svg.license
+++ b/subprojects/docs/src/docs/learn/language/classes/InvalidInstance.svg.license
diff --git a/subprojects/docs/src/learn/language/classes/MultiplicityConstraintsInstance.svg b/subprojects/docs/src/docs/learn/language/classes/MultiplicityConstraintsInstance.svg
index b28c295a..b28c295a 100644
--- a/subprojects/docs/src/learn/language/classes/MultiplicityConstraintsInstance.svg
+++ b/subprojects/docs/src/docs/learn/language/classes/MultiplicityConstraintsInstance.svg
diff --git a/subprojects/docs/src/learn/language/classes/MultiplicityConstraintsInstance.svg.license b/subprojects/docs/src/docs/learn/language/classes/MultiplicityConstraintsInstance.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/language/classes/MultiplicityConstraintsInstance.svg.license
+++ b/subprojects/docs/src/docs/learn/language/classes/MultiplicityConstraintsInstance.svg.license
diff --git a/subprojects/docs/src/learn/language/classes/NewObjectsSimple.svg b/subprojects/docs/src/docs/learn/language/classes/NewObjectsSimple.svg
index 95ba8def..95ba8def 100644
--- a/subprojects/docs/src/learn/language/classes/NewObjectsSimple.svg
+++ b/subprojects/docs/src/docs/learn/language/classes/NewObjectsSimple.svg
diff --git a/subprojects/docs/src/learn/language/classes/NewObjectsSimple.svg.license b/subprojects/docs/src/docs/learn/language/classes/NewObjectsSimple.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/language/classes/NewObjectsSimple.svg.license
+++ b/subprojects/docs/src/docs/learn/language/classes/NewObjectsSimple.svg.license
diff --git a/subprojects/docs/src/learn/language/classes/NewObjectsWithInheritance.svg b/subprojects/docs/src/docs/learn/language/classes/NewObjectsWithInheritance.svg
index cdf365f0..cdf365f0 100644
--- a/subprojects/docs/src/learn/language/classes/NewObjectsWithInheritance.svg
+++ b/subprojects/docs/src/docs/learn/language/classes/NewObjectsWithInheritance.svg
diff --git a/subprojects/docs/src/learn/language/classes/NewObjectsWithInheritance.svg.license b/subprojects/docs/src/docs/learn/language/classes/NewObjectsWithInheritance.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/language/classes/NewObjectsWithInheritance.svg.license
+++ b/subprojects/docs/src/docs/learn/language/classes/NewObjectsWithInheritance.svg.license
diff --git a/subprojects/docs/src/learn/language/classes/ReferencesOppositeInstance.svg b/subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeInstance.svg
index 56a4d956..56a4d956 100644
--- a/subprojects/docs/src/learn/language/classes/ReferencesOppositeInstance.svg
+++ b/subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeInstance.svg
diff --git a/subprojects/docs/src/learn/language/classes/ReferencesOppositeInstance.svg.license b/subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeInstance.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/language/classes/ReferencesOppositeInstance.svg.license
+++ b/subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeInstance.svg.license
diff --git a/subprojects/docs/src/learn/language/classes/ReferencesOppositeSelf.svg b/subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeSelf.svg
index 81ab4a0c..81ab4a0c 100644
--- a/subprojects/docs/src/learn/language/classes/ReferencesOppositeSelf.svg
+++ b/subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeSelf.svg
diff --git a/subprojects/docs/src/learn/language/classes/ReferencesOppositeSelf.svg.license b/subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeSelf.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/language/classes/ReferencesOppositeSelf.svg.license
+++ b/subprojects/docs/src/docs/learn/language/classes/ReferencesOppositeSelf.svg.license
diff --git a/subprojects/docs/src/learn/language/classes/ReferencesSimple.svg b/subprojects/docs/src/docs/learn/language/classes/ReferencesSimple.svg
index fac74815..fac74815 100644
--- a/subprojects/docs/src/learn/language/classes/ReferencesSimple.svg
+++ b/subprojects/docs/src/docs/learn/language/classes/ReferencesSimple.svg
diff --git a/subprojects/docs/src/learn/language/classes/ReferencesSimple.svg.license b/subprojects/docs/src/docs/learn/language/classes/ReferencesSimple.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/language/classes/ReferencesSimple.svg.license
+++ b/subprojects/docs/src/docs/learn/language/classes/ReferencesSimple.svg.license
diff --git a/subprojects/docs/src/learn/language/classes/index.md b/subprojects/docs/src/docs/learn/language/classes/index.md
index 73108039..18cbbf9f 100644
--- a/subprojects/docs/src/learn/language/classes/index.md
+++ b/subprojects/docs/src/docs/learn/language/classes/index.md
@@ -129,7 +129,7 @@ import ReferencesOppositeSelf from './ReferencesOppositeSelf.svg';
129 129
130### Multiplicity 130### Multiplicity
131 131
132_Multiplicity constrains_ can be provided after the reference type in square braces. 132_Multiplicity constraints_ can be provided after the reference type in square braces.
133They specify how many _outgoing_ references should exist for any given instance of the class. 133They specify how many _outgoing_ references should exist for any given instance of the class.
134 134
135:::info 135:::info
@@ -150,7 +150,7 @@ If the multiplicity constraint is omitted, the bound `[0..1]` is assumed.
150 150
151In the following model, the node `v1` satisfies all multiplicity constraints of `outgoingTransition`. 151In the following model, the node `v1` satisfies all multiplicity constraints of `outgoingTransition`.
152The node `v2` violates the lower bound constraint, while `v3` violates the upper bound constraint. 152The node `v2` violates the lower bound constraint, while `v3` violates the upper bound constraint.
153All `Transition` instances satisfy the multiplicity constrains associated with `source`. 153All `Transition` instances satisfy the multiplicity constraints associated with `source`.
154 154
155```refinery 155```refinery
156class Vertex { 156class Vertex {
@@ -209,4 +209,5 @@ import ContainmentInstance from './ContainmentInstance.svg';
209 209
210<ContainmentInstance /> 210<ContainmentInstance />
211 211
212Containment edges form trees, while non-containment references, such as `target`, may point across the containment hierarchy. 212Containment edges form must form a forest.
213In contrast, non-containment references, such as `target`, may cross the containment hierarchy.
diff --git a/subprojects/docs/src/learn/language/logic/AssertionsError.svg b/subprojects/docs/src/docs/learn/language/logic/AssertionsError.svg
index 8ddc65f3..8ddc65f3 100644
--- a/subprojects/docs/src/learn/language/logic/AssertionsError.svg
+++ b/subprojects/docs/src/docs/learn/language/logic/AssertionsError.svg
diff --git a/subprojects/docs/src/learn/language/logic/AssertionsError.svg.license b/subprojects/docs/src/docs/learn/language/logic/AssertionsError.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/language/logic/AssertionsError.svg.license
+++ b/subprojects/docs/src/docs/learn/language/logic/AssertionsError.svg.license
diff --git a/subprojects/docs/src/learn/language/logic/AssertionsExample.svg b/subprojects/docs/src/docs/learn/language/logic/AssertionsExample.svg
index 26b3d1ff..26b3d1ff 100644
--- a/subprojects/docs/src/learn/language/logic/AssertionsExample.svg
+++ b/subprojects/docs/src/docs/learn/language/logic/AssertionsExample.svg
diff --git a/subprojects/docs/src/learn/language/logic/AssertionsExample.svg.license b/subprojects/docs/src/docs/learn/language/logic/AssertionsExample.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/language/logic/AssertionsExample.svg.license
+++ b/subprojects/docs/src/docs/learn/language/logic/AssertionsExample.svg.license
diff --git a/subprojects/docs/src/learn/language/logic/DefaultAssertions.svg b/subprojects/docs/src/docs/learn/language/logic/DefaultAssertions.svg
index 2ab002bf..2ab002bf 100644
--- a/subprojects/docs/src/learn/language/logic/DefaultAssertions.svg
+++ b/subprojects/docs/src/docs/learn/language/logic/DefaultAssertions.svg
diff --git a/subprojects/docs/src/learn/language/logic/DefaultAssertions.svg.license b/subprojects/docs/src/docs/learn/language/logic/DefaultAssertions.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/language/logic/DefaultAssertions.svg.license
+++ b/subprojects/docs/src/docs/learn/language/logic/DefaultAssertions.svg.license
diff --git a/subprojects/docs/src/learn/language/logic/MultiObjects.svg b/subprojects/docs/src/docs/learn/language/logic/MultiObjects.svg
index a5232575..a5232575 100644
--- a/subprojects/docs/src/learn/language/logic/MultiObjects.svg
+++ b/subprojects/docs/src/docs/learn/language/logic/MultiObjects.svg
diff --git a/subprojects/docs/src/learn/language/logic/MultiObjects.svg.license b/subprojects/docs/src/docs/learn/language/logic/MultiObjects.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/language/logic/MultiObjects.svg.license
+++ b/subprojects/docs/src/docs/learn/language/logic/MultiObjects.svg.license
diff --git a/subprojects/docs/src/learn/language/logic/ObjectScopes.svg b/subprojects/docs/src/docs/learn/language/logic/ObjectScopes.svg
index 440dfb19..440dfb19 100644
--- a/subprojects/docs/src/learn/language/logic/ObjectScopes.svg
+++ b/subprojects/docs/src/docs/learn/language/logic/ObjectScopes.svg
diff --git a/subprojects/docs/src/learn/language/logic/ObjectScopes.svg.license b/subprojects/docs/src/docs/learn/language/logic/ObjectScopes.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/language/logic/ObjectScopes.svg.license
+++ b/subprojects/docs/src/docs/learn/language/logic/ObjectScopes.svg.license
diff --git a/subprojects/docs/src/learn/language/logic/StrongerObjectScopes.svg b/subprojects/docs/src/docs/learn/language/logic/StrongerObjectScopes.svg
index 6f988065..6f988065 100644
--- a/subprojects/docs/src/learn/language/logic/StrongerObjectScopes.svg
+++ b/subprojects/docs/src/docs/learn/language/logic/StrongerObjectScopes.svg
diff --git a/subprojects/docs/src/learn/language/logic/StrongerObjectScopes.svg.license b/subprojects/docs/src/docs/learn/language/logic/StrongerObjectScopes.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/language/logic/StrongerObjectScopes.svg.license
+++ b/subprojects/docs/src/docs/learn/language/logic/StrongerObjectScopes.svg.license
diff --git a/subprojects/docs/src/learn/language/logic/index.md b/subprojects/docs/src/docs/learn/language/logic/index.md
index e366e9b8..e366e9b8 100644
--- a/subprojects/docs/src/learn/language/logic/index.md
+++ b/subprojects/docs/src/docs/learn/language/logic/index.md
diff --git a/subprojects/docs/src/learn/language/predicates/DerivedFeature.svg b/subprojects/docs/src/docs/learn/language/predicates/DerivedFeature.svg
index be9465b8..be9465b8 100644
--- a/subprojects/docs/src/learn/language/predicates/DerivedFeature.svg
+++ b/subprojects/docs/src/docs/learn/language/predicates/DerivedFeature.svg
diff --git a/subprojects/docs/src/learn/language/predicates/DerivedFeature.svg.license b/subprojects/docs/src/docs/learn/language/predicates/DerivedFeature.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/language/predicates/DerivedFeature.svg.license
+++ b/subprojects/docs/src/docs/learn/language/predicates/DerivedFeature.svg.license
diff --git a/subprojects/docs/src/learn/language/predicates/index.md b/subprojects/docs/src/docs/learn/language/predicates/index.md
index 261054c1..261054c1 100644
--- a/subprojects/docs/src/learn/language/predicates/index.md
+++ b/subprojects/docs/src/docs/learn/language/predicates/index.md
diff --git a/subprojects/docs/src/learn/tutorials/_category_.yml b/subprojects/docs/src/docs/learn/tutorials/_category_.yml
index adf8293f..fd563704 100644
--- a/subprojects/docs/src/learn/tutorials/_category_.yml
+++ b/subprojects/docs/src/docs/learn/tutorials/_category_.yml
@@ -6,6 +6,6 @@ position: 1
6label: Tutorials 6label: Tutorials
7link: 7link:
8 type: generated-index 8 type: generated-index
9 slug: /tutorials 9 slug: /learn/tutorials
10 title: Tutorial overview 10 title: Tutorial overview
11 description: Try Refinery in practical partial modeling challenges! 11 description: Try Refinery in practical partial modeling challenges!
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/filterPanelDark.png b/subprojects/docs/src/docs/learn/tutorials/file-system/filterPanelDark.png
new file mode 100644
index 00000000..28d2b7b6
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/filterPanelDark.png
Binary files differ
diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig1.svg.license b/subprojects/docs/src/docs/learn/tutorials/file-system/filterPanelDark.png.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/tutorials/file-system/fig1.svg.license
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/filterPanelDark.png.license
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/filterPanelLight.png b/subprojects/docs/src/docs/learn/tutorials/file-system/filterPanelLight.png
new file mode 100644
index 00000000..fa7ae846
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/filterPanelLight.png
Binary files differ
diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig2.svg.license b/subprojects/docs/src/docs/learn/tutorials/file-system/filterPanelLight.png.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/tutorials/file-system/fig2.svg.license
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/filterPanelLight.png.license
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/generatedModel1.svg b/subprojects/docs/src/docs/learn/tutorials/file-system/generatedModel1.svg
new file mode 100644
index 00000000..4d7376ac
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/generatedModel1.svg
@@ -0,0 +1,254 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="399pt" height="358pt" viewBox="-6 -6 411 370" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-a18XnMFkI_RXh1dM6QtA1"><style>.refinery-a18XnMFkI_RXh1dM6QtA1 .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node .node-outline{stroke:#19202b;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node .node-header{fill:rgb(53, 161, 173);}.refinery-a18XnMFkI_RXh1dM6QtA1 .node .node-bg{fill:#fff;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-h .node-header{fill:#e06c75;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-i .node-header{fill:#98c379;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-j .node-header{fill:#c678dd;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-n .node-header{fill:#abcc94;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-a18XnMFkI_RXh1dM6QtA1 .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-a18XnMFkI_RXh1dM6QtA1 .edge .edge-line{stroke:#19202b;}.refinery-a18XnMFkI_RXh1dM6QtA1 .edge .edge-arrow{fill:#19202b;}.refinery-a18XnMFkI_RXh1dM6QtA1 .edge-UNKNOWN text{fill:#696c77;}.refinery-a18XnMFkI_RXh1dM6QtA1 .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-a18XnMFkI_RXh1dM6QtA1 .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-a18XnMFkI_RXh1dM6QtA1 .edge-ERROR text{fill:#ca1243;}.refinery-a18XnMFkI_RXh1dM6QtA1 .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-a18XnMFkI_RXh1dM6QtA1 .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-a18XnMFkI_RXh1dM6QtA1 .icon-TRUE{fill:#19202b;}.refinery-a18XnMFkI_RXh1dM6QtA1 .icon-UNKNOWN{fill:#696c77;}.refinery-a18XnMFkI_RXh1dM6QtA1 .icon-ERROR{fill:#ca1243;}.refinery-a18XnMFkI_RXh1dM6QtA1 text.label-UNKNOWN{fill:#696c77;}.refinery-a18XnMFkI_RXh1dM6QtA1 text.label-ERROR{fill:#ca1243;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-exists-FALSE text:not(.label-ERROR){fill:#696c77;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-exists-FALSE .node-outline{stroke:#696c77;stroke-dasharray:2 4;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-exists-FALSE .node-header{fill:#fff;}.refinery-a18XnMFkI_RXh1dM6QtA1 .node-exists-FALSE .icon-TRUE{fill:#696c77;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 text.label-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-exists-FALSE text:not(.label-ERROR){fill:#abb2bf;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-exists-FALSE .node-outline{stroke:#abb2bf;stroke-dasharray:2 4;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-exists-FALSE .node-header{fill:#282c34;}[data-theme="dark"] .refinery-a18XnMFkI_RXh1dM6QtA1 .node-exists-FALSE .icon-TRUE{fill:#abb2bf;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-a18XnMFkI_RXh1dM6QtA1-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-a18XnMFkI_RXh1dM6QtA1-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="scale(1 1) rotate(0) translate(4 354)">
4<!-- n4 -->
5<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-g">
6
7<rect stroke="none" x="31.19" y="-350" width="86.62" height="48.80000000000001" rx="12" ry="12" class="node-bg"/>
8<rect stroke="none" x="27" y="-354" width="94" height="27" clip-path="url(#refinery-a18XnMFkI_RXh1dM6QtA1-clip-0)" class="node-header"/>
9<text text-anchor="start" x="42.82" y="-334.2" font-size="12.00">filesystem1</text>
10<use x="37.1885" y="-320.40000000000003" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
11<g><text text-anchor="start" x="53.19" y="-310.8" font-size="12.00" class="label label-TRUE">Filesystem</text>
12</g>
13<polyline points="31.19,-326.6 117.81,-326.6" class="node-outline"/>
14<rect fill="none" x="31.19" y="-350" width="86.62" height="48.80000000000001" rx="12" ry="12" class="node-outline"/>
15<clipPath id="refinery-a18XnMFkI_RXh1dM6QtA1-clip-0"><rect stroke="none" x="31.19" y="-350" width="86.62" height="48.80000000000001" rx="12" ry="12" class="node-bg"/></clipPath></g>
16<!-- n8 -->
17<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-n">
18
19<rect stroke="none" x="38" y="-265.2" width="73" height="64.39999999999998" rx="12" ry="12" class="node-bg"/>
20<rect stroke="none" x="34" y="-269" width="81" height="27" clip-path="url(#refinery-a18XnMFkI_RXh1dM6QtA1-clip-1)" class="node-header"/>
21<text text-anchor="start" x="63.43" y="-249.4" font-size="12.00">dir2</text>
22<use x="44" y="-235.8" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
23<g><text text-anchor="start" x="59.74" y="-227" font-style="italic" font-size="12.00" class="label label-TRUE">FSObject</text>
24</g>
25<use x="44" y="-219.8" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
26<g><text text-anchor="start" x="60" y="-210" font-size="12.00" class="label label-TRUE">Dir</text>
27</g>
28<polyline points="38,-241.8 111,-241.8" class="node-outline"/>
29<rect fill="none" x="38" y="-265.2" width="73" height="64.39999999999998" rx="12" ry="12" class="node-outline"/>
30<clipPath id="refinery-a18XnMFkI_RXh1dM6QtA1-clip-1"><rect stroke="none" x="38" y="-265.2" width="73" height="64.39999999999998" rx="12" ry="12" class="node-bg"/></clipPath></g>
31<!-- n4&#45;&gt;n8 -->
32<g class="edge edge-TRUE">
33
34<path fill="none" stroke-width="2" d="M74.5,-301.27C74.5,-293.78 74.5,-285.25 74.5,-276.82" class="edge-line"/>
35<polygon stroke-width="2" points="77.56,-276.89 74.5,-268.14 71.44,-276.89 77.56,-276.89" class="edge-line edge-arrow"/>
36<text text-anchor="start" x="52.17" y="-287.69" font-weight="bold" font-size="10.50">root</text>
37</g>
38<!-- n5 -->
39<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-g">
40
41<rect stroke="none" x="175.19" y="-350" width="86.62" height="48.80000000000001" rx="12" ry="12" class="node-bg"/>
42<rect stroke="none" x="171" y="-354" width="94" height="27" clip-path="url(#refinery-a18XnMFkI_RXh1dM6QtA1-clip-2)" class="node-header"/>
43<text text-anchor="start" x="186.82" y="-334.2" font-size="12.00">filesystem2</text>
44<use x="181.188" y="-320.40000000000003" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
45<g><text text-anchor="start" x="197.19" y="-310.8" font-size="12.00" class="label label-TRUE">Filesystem</text>
46</g>
47<polyline points="175.19,-326.6 261.81,-326.6" class="node-outline"/>
48<rect fill="none" x="175.19" y="-350" width="86.62" height="48.80000000000001" rx="12" ry="12" class="node-outline"/>
49<clipPath id="refinery-a18XnMFkI_RXh1dM6QtA1-clip-2"><rect stroke="none" x="175.19" y="-350" width="86.62" height="48.80000000000001" rx="12" ry="12" class="node-bg"/></clipPath></g>
50<!-- n6 -->
51<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-n">
52
53<rect stroke="none" x="182" y="-265.2" width="73" height="64.39999999999998" rx="12" ry="12" class="node-bg"/>
54<rect stroke="none" x="178" y="-269" width="81" height="27" clip-path="url(#refinery-a18XnMFkI_RXh1dM6QtA1-clip-3)" class="node-header"/>
55<text text-anchor="start" x="207.43" y="-249.4" font-size="12.00">dir1</text>
56<use x="188" y="-235.8" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
57<g><text text-anchor="start" x="203.74" y="-227" font-style="italic" font-size="12.00" class="label label-TRUE">FSObject</text>
58</g>
59<use x="188" y="-219.8" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
60<g><text text-anchor="start" x="204" y="-210" font-size="12.00" class="label label-TRUE">Dir</text>
61</g>
62<polyline points="182,-241.8 255,-241.8" class="node-outline"/>
63<rect fill="none" x="182" y="-265.2" width="73" height="64.39999999999998" rx="12" ry="12" class="node-outline"/>
64<clipPath id="refinery-a18XnMFkI_RXh1dM6QtA1-clip-3"><rect stroke="none" x="182" y="-265.2" width="73" height="64.39999999999998" rx="12" ry="12" class="node-bg"/></clipPath></g>
65<!-- n5&#45;&gt;n6 -->
66<g class="edge edge-TRUE">
67
68<path fill="none" stroke-width="2" d="M218.5,-301.27C218.5,-293.78 218.5,-285.25 218.5,-276.82" class="edge-line"/>
69<polygon stroke-width="2" points="221.56,-276.89 218.5,-268.14 215.44,-276.89 221.56,-276.89" class="edge-line edge-arrow"/>
70<text text-anchor="start" x="196.17" y="-287.69" font-weight="bold" font-size="10.50">root</text>
71</g>
72<!-- n7 -->
73<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
74
75<rect stroke="none" x="182" y="-164.8" width="73" height="64.4" rx="12" ry="12" class="node-bg"/>
76<rect stroke="none" x="178" y="-168" width="81" height="27" clip-path="url(#refinery-a18XnMFkI_RXh1dM6QtA1-clip-4)" class="node-header"/>
77<text text-anchor="start" x="205.2" y="-149" font-size="12.00">link1</text>
78<use x="188" y="-135.4" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
79<g><text text-anchor="start" x="203.74" y="-126.6" font-style="italic" font-size="12.00" class="label label-TRUE">FSObject</text>
80</g>
81<use x="188" y="-119.4" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
82<g><text text-anchor="start" x="204" y="-109.6" font-size="12.00" class="label label-TRUE">Link</text>
83</g>
84<polyline points="182,-141.4 255,-141.4" class="node-outline"/>
85<rect fill="none" x="182" y="-164.8" width="73" height="64.4" rx="12" ry="12" class="node-outline"/>
86<clipPath id="refinery-a18XnMFkI_RXh1dM6QtA1-clip-4"><rect stroke="none" x="182" y="-164.8" width="73" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g>
87<!-- n6&#45;&gt;n7 -->
88<g class="edge edge-TRUE">
89
90<path fill="none" stroke-width="2" d="M205.84,-200.87C205.07,-192.98 204.83,-184.38 205.11,-176.04" class="edge-line"/>
91<polygon stroke-width="2" points="208.15,-176.48 205.67,-167.55 202.04,-176.08 208.15,-176.48" class="edge-line edge-arrow"/>
92<text text-anchor="start" x="158.76" y="-186.87" font-weight="bold" font-size="10.50">contents</text>
93</g>
94<!-- n9 -->
95<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-n">
96
97<rect stroke="none" x="273" y="-164.8" width="73" height="64.4" rx="12" ry="12" class="node-bg"/>
98<rect stroke="none" x="269" y="-168" width="81" height="27" clip-path="url(#refinery-a18XnMFkI_RXh1dM6QtA1-clip-5)" class="node-header"/>
99<text text-anchor="start" x="298.43" y="-149" font-size="12.00">dir3</text>
100<use x="279" y="-135.4" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
101<g><text text-anchor="start" x="294.74" y="-126.6" font-style="italic" font-size="12.00" class="label label-TRUE">FSObject</text>
102</g>
103<use x="279" y="-119.4" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
104<g><text text-anchor="start" x="295" y="-109.6" font-size="12.00" class="label label-TRUE">Dir</text>
105</g>
106<polyline points="273,-141.4 346,-141.4" class="node-outline"/>
107<rect fill="none" x="273" y="-164.8" width="73" height="64.4" rx="12" ry="12" class="node-outline"/>
108<clipPath id="refinery-a18XnMFkI_RXh1dM6QtA1-clip-5"><rect stroke="none" x="273" y="-164.8" width="73" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g>
109<!-- n6&#45;&gt;n9 -->
110<g class="edge edge-TRUE">
111
112<path fill="none" stroke-width="2" d="M240.96,-200.87C248.74,-191.99 257.7,-182.19 266.53,-172.89" class="edge-line"/>
113<polygon stroke-width="2" points="268.62,-175.14 272.48,-166.71 264.21,-170.9 268.62,-175.14" class="edge-line edge-arrow"/>
114<text text-anchor="start" x="211.19" y="-186.75" font-weight="bold" font-size="10.50">contents</text>
115</g>
116<!-- n7&#45;&gt;n6 -->
117<g class="edge edge-TRUE">
118
119<path fill="none" d="M218.5,-164.53C218.5,-172.49 218.5,-181.2 218.5,-189.63" class="edge-line"/>
120<polygon points="215,-189.35 218.5,-199.35 222,-189.35 215,-189.35" class="edge-line edge-arrow"/>
121<text text-anchor="middle" x="202.2" y="-173.02" font-size="10.50">parent</text>
122</g>
123<!-- n7&#45;&gt;n6 -->
124<g class="edge edge-TRUE">
125
126<path fill="none" d="M231.14,-164.53C231.92,-172.49 232.17,-181.2 231.88,-189.63" class="edge-line"/>
127<polygon points="228.41,-189.15 231.25,-199.36 235.39,-189.6 228.41,-189.15" class="edge-line edge-arrow"/>
128<text text-anchor="middle" x="246.59" y="-173.02" font-size="10.50">target</text>
129</g>
130<!-- n12 -->
131<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
132
133<rect stroke="none" x="0" y="-164.8" width="73" height="64.4" rx="12" ry="12" class="node-bg"/>
134<rect stroke="none" x="-4" y="-168" width="81" height="27" clip-path="url(#refinery-a18XnMFkI_RXh1dM6QtA1-clip-6)" class="node-header"/>
135<text text-anchor="start" x="24.63" y="-149" font-size="12.00">file3</text>
136<use x="6" y="-135.4" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
137<g><text text-anchor="start" x="21.74" y="-126.6" font-style="italic" font-size="12.00" class="label label-TRUE">FSObject</text>
138</g>
139<use x="6" y="-119.4" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
140<g><text text-anchor="start" x="22" y="-109.6" font-size="12.00" class="label label-TRUE">File</text>
141</g>
142<polyline points="0,-141.4 73,-141.4" class="node-outline"/>
143<rect fill="none" x="0" y="-164.8" width="73" height="64.4" rx="12" ry="12" class="node-outline"/>
144<clipPath id="refinery-a18XnMFkI_RXh1dM6QtA1-clip-6"><rect stroke="none" x="0" y="-164.8" width="73" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g>
145<!-- n8&#45;&gt;n12 -->
146<g class="edge edge-TRUE">
147
148<path fill="none" stroke-width="2" d="M56.15,-200.87C52.64,-192.8 49.12,-183.98 45.99,-175.47" class="edge-line"/>
149<polygon stroke-width="2" points="48.93,-174.62 43.13,-167.39 43.16,-176.66 48.93,-174.62" class="edge-line edge-arrow"/>
150<text text-anchor="start" x="2.47" y="-186.85" font-weight="bold" font-size="10.50">contents</text>
151</g>
152<!-- n13 -->
153<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
154
155<rect stroke="none" x="91" y="-164.8" width="73" height="64.4" rx="12" ry="12" class="node-bg"/>
156<rect stroke="none" x="87" y="-168" width="81" height="27" clip-path="url(#refinery-a18XnMFkI_RXh1dM6QtA1-clip-7)" class="node-header"/>
157<text text-anchor="start" x="115.63" y="-149" font-size="12.00">file4</text>
158<use x="97" y="-135.4" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
159<g><text text-anchor="start" x="112.74" y="-126.6" font-style="italic" font-size="12.00" class="label label-TRUE">FSObject</text>
160</g>
161<use x="97" y="-119.4" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
162<g><text text-anchor="start" x="113" y="-109.6" font-size="12.00" class="label label-TRUE">File</text>
163</g>
164<polyline points="91,-141.4 164,-141.4" class="node-outline"/>
165<rect fill="none" x="91" y="-164.8" width="73" height="64.4" rx="12" ry="12" class="node-outline"/>
166<clipPath id="refinery-a18XnMFkI_RXh1dM6QtA1-clip-7"><rect stroke="none" x="91" y="-164.8" width="73" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g>
167<!-- n8&#45;&gt;n13 -->
168<g class="edge edge-TRUE">
169
170<path fill="none" stroke-width="2" d="M84.94,-200.87C89.03,-192.53 93.84,-183.39 98.75,-174.61" class="edge-line"/>
171<polygon stroke-width="2" points="101.32,-176.27 103.02,-167.16 96.01,-173.23 101.32,-176.27" class="edge-line edge-arrow"/>
172<text text-anchor="start" x="94.42" y="-174.04" font-weight="bold" font-size="10.50">contents</text>
173</g>
174<!-- n9&#45;&gt;n6 -->
175<g class="edge edge-TRUE">
176
177<path fill="none" d="M287.21,-164.53C279.37,-173.49 270.32,-183.39 261.4,-192.78" class="edge-line"/>
178<polygon points="259.08,-190.14 254.67,-199.77 264.12,-194.99 259.08,-190.14" class="edge-line edge-arrow"/>
179<text text-anchor="middle" x="286.89" y="-186.12" font-size="10.50">parent</text>
180</g>
181<!-- n10 -->
182<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
183
184<rect stroke="none" x="227" y="-64.4" width="73" height="64.4" rx="12" ry="12" class="node-bg"/>
185<rect stroke="none" x="223" y="-68" width="81" height="27" clip-path="url(#refinery-a18XnMFkI_RXh1dM6QtA1-clip-8)" class="node-header"/>
186<text text-anchor="start" x="251.63" y="-48.6" font-size="12.00">file1</text>
187<use x="233" y="-35" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
188<g><text text-anchor="start" x="248.74" y="-26.2" font-style="italic" font-size="12.00" class="label label-TRUE">FSObject</text>
189</g>
190<use x="233" y="-19" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
191<g><text text-anchor="start" x="249" y="-9.2" font-size="12.00" class="label label-TRUE">File</text>
192</g>
193<polyline points="227,-41 300,-41" class="node-outline"/>
194<rect fill="none" x="227" y="-64.4" width="73" height="64.4" rx="12" ry="12" class="node-outline"/>
195<clipPath id="refinery-a18XnMFkI_RXh1dM6QtA1-clip-8"><rect stroke="none" x="227" y="-64.4" width="73" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g>
196<!-- n9&#45;&gt;n10 -->
197<g class="edge edge-TRUE">
198
199<path fill="none" stroke-width="2" d="M288.62,-100.47C284.41,-92.31 280.12,-83.39 276.26,-74.78" class="edge-line"/>
200<polygon stroke-width="2" points="279.14,-73.72 272.85,-66.91 273.52,-76.16 279.14,-73.72" class="edge-line edge-arrow"/>
201<text text-anchor="start" x="233.56" y="-86.65" font-weight="bold" font-size="10.50">contents</text>
202</g>
203<!-- n11 -->
204<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
205
206<rect stroke="none" x="318" y="-64.4" width="73" height="64.4" rx="12" ry="12" class="node-bg"/>
207<rect stroke="none" x="314" y="-68" width="81" height="27" clip-path="url(#refinery-a18XnMFkI_RXh1dM6QtA1-clip-9)" class="node-header"/>
208<text text-anchor="start" x="342.63" y="-48.6" font-size="12.00">file2</text>
209<use x="324" y="-35" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
210<g><text text-anchor="start" x="339.74" y="-26.2" font-style="italic" font-size="12.00" class="label label-TRUE">FSObject</text>
211</g>
212<use x="324" y="-19" width="12" height="12" href="#refinery-a18XnMFkI_RXh1dM6QtA1-icon-TRUE" class="icon icon-TRUE"/>
213<g><text text-anchor="start" x="340" y="-9.2" font-size="12.00" class="label label-TRUE">File</text>
214</g>
215<polyline points="318,-41 391,-41" class="node-outline"/>
216<rect fill="none" x="318" y="-64.4" width="73" height="64.4" rx="12" ry="12" class="node-outline"/>
217<clipPath id="refinery-a18XnMFkI_RXh1dM6QtA1-clip-9"><rect stroke="none" x="318" y="-64.4" width="73" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g>
218<!-- n9&#45;&gt;n11 -->
219<g class="edge edge-TRUE">
220
221<path fill="none" stroke-width="2" d="M317.41,-100.47C320.78,-92.22 324.79,-83.19 328.94,-74.49" class="edge-line"/>
222<polygon stroke-width="2" points="331.59,-76.05 332.7,-66.85 326.09,-73.35 331.59,-76.05" class="edge-line edge-arrow"/>
223<text text-anchor="start" x="325.3" y="-73.85" font-weight="bold" font-size="10.50">contents</text>
224</g>
225<!-- n10&#45;&gt;n9 -->
226<g class="edge edge-TRUE">
227
228<path fill="none" d="M284.28,-64.13C288.53,-72.36 292.87,-81.39 296.77,-90.09" class="edge-line"/>
229<polygon points="293.48,-91.3 300.67,-99.08 299.9,-88.51 293.48,-91.3" class="edge-line edge-arrow"/>
230<text text-anchor="middle" x="276.9" y="-72.84" font-size="10.50">parent</text>
231</g>
232<!-- n11&#45;&gt;n9 -->
233<g class="edge edge-TRUE">
234
235<path fill="none" d="M346.67,-64.13C343.28,-72.46 339.22,-81.59 335.02,-90.38" class="edge-line"/>
236<polygon points="332,-88.59 330.73,-99.11 338.28,-91.67 332,-88.59" class="edge-line edge-arrow"/>
237<text text-anchor="middle" x="322.41" y="-85.64" font-size="10.50">parent</text>
238</g>
239<!-- n12&#45;&gt;n8 -->
240<g class="edge edge-TRUE">
241
242<path fill="none" d="M54.76,-164.53C58.31,-172.67 61.88,-181.6 65.04,-190.21" class="edge-line"/>
243<polygon points="61.67,-191.17 68.3,-199.44 68.27,-188.84 61.67,-191.17" class="edge-line edge-arrow"/>
244<text text-anchor="middle" x="45.83" y="-173.03" font-size="10.50">parent</text>
245</g>
246<!-- n13&#45;&gt;n8 -->
247<g class="edge edge-TRUE">
248
249<path fill="none" d="M117.16,-164.53C113.04,-172.95 108.18,-182.19 103.21,-191.07" class="edge-line"/>
250<polygon points="100.28,-189.14 98.35,-199.55 106.36,-192.62 100.28,-189.14" class="edge-line edge-arrow"/>
251<text text-anchor="middle" x="91.29" y="-186.25" font-size="10.50">parent</text>
252</g>
253</g>
254</svg> \ No newline at end of file
diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig3.svg.license b/subprojects/docs/src/docs/learn/tutorials/file-system/generatedModel1.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/tutorials/file-system/fig3.svg.license
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/generatedModel1.svg.license
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/generatedModel1Simplified.svg b/subprojects/docs/src/docs/learn/tutorials/file-system/generatedModel1Simplified.svg
new file mode 100644
index 00000000..13dab2a1
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/generatedModel1Simplified.svg
@@ -0,0 +1,188 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="301pt" height="311pt" viewBox="-6 -6 313.2200012207031 323.20001220703125" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-83G8OR--ePj0Ssqa0Eja5"><style>.refinery-83G8OR--ePj0Ssqa0Eja5 .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node .node-outline{stroke:#19202b;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node .node-header{fill:rgb(53, 161, 173);}.refinery-83G8OR--ePj0Ssqa0Eja5 .node .node-bg{fill:#fff;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-h .node-header{fill:#e06c75;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-i .node-header{fill:#98c379;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-j .node-header{fill:#c678dd;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-n .node-header{fill:#abcc94;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-83G8OR--ePj0Ssqa0Eja5 .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-83G8OR--ePj0Ssqa0Eja5 .edge .edge-line{stroke:#19202b;}.refinery-83G8OR--ePj0Ssqa0Eja5 .edge .edge-arrow{fill:#19202b;}.refinery-83G8OR--ePj0Ssqa0Eja5 .edge-UNKNOWN text{fill:#696c77;}.refinery-83G8OR--ePj0Ssqa0Eja5 .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-83G8OR--ePj0Ssqa0Eja5 .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-83G8OR--ePj0Ssqa0Eja5 .edge-ERROR text{fill:#ca1243;}.refinery-83G8OR--ePj0Ssqa0Eja5 .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-83G8OR--ePj0Ssqa0Eja5 .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-83G8OR--ePj0Ssqa0Eja5 .icon-TRUE{fill:#19202b;}.refinery-83G8OR--ePj0Ssqa0Eja5 .icon-UNKNOWN{fill:#696c77;}.refinery-83G8OR--ePj0Ssqa0Eja5 .icon-ERROR{fill:#ca1243;}.refinery-83G8OR--ePj0Ssqa0Eja5 text.label-UNKNOWN{fill:#696c77;}.refinery-83G8OR--ePj0Ssqa0Eja5 text.label-ERROR{fill:#ca1243;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-exists-FALSE text:not(.label-ERROR){fill:#696c77;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-exists-FALSE .node-outline{stroke:#696c77;stroke-dasharray:2 4;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-exists-FALSE .node-header{fill:#fff;}.refinery-83G8OR--ePj0Ssqa0Eja5 .node-exists-FALSE .icon-TRUE{fill:#696c77;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 text.label-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-exists-FALSE text:not(.label-ERROR){fill:#abb2bf;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-exists-FALSE .node-outline{stroke:#abb2bf;stroke-dasharray:2 4;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-exists-FALSE .node-header{fill:#282c34;}[data-theme="dark"] .refinery-83G8OR--ePj0Ssqa0Eja5 .node-exists-FALSE .icon-TRUE{fill:#abb2bf;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-83G8OR--ePj0Ssqa0Eja5-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-83G8OR--ePj0Ssqa0Eja5-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-83G8OR--ePj0Ssqa0Eja5-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="translate(4, 307.20001220703125)">
4<!-- n4 -->
5<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-g">
6
7<rect stroke="none" x="9.41" y="-303.2" width="86.62" height="48.79999999999998" rx="12" ry="12" class="node-bg"/>
8<rect stroke="none" x="5" y="-307" width="94" height="27" clip-path="url(#refinery-83G8OR--ePj0Ssqa0Eja5-clip-0)" class="node-header"/>
9<text text-anchor="start" x="21.04" y="-287.4" font-size="12.00">filesystem1</text>
10<use x="15.4093" y="-273.6" width="12" height="12" href="#refinery-83G8OR--ePj0Ssqa0Eja5-icon-TRUE" class="icon icon-TRUE"/>
11<g><text text-anchor="start" x="31.41" y="-264" font-size="12.00" class="label label-TRUE">Filesystem</text>
12</g>
13<polyline points="9.41,-279.8 96.03,-279.8" class="node-outline"/>
14<rect fill="none" x="9.41" y="-303.2" width="86.62" height="48.79999999999998" rx="12" ry="12" class="node-outline"/>
15<clipPath id="refinery-83G8OR--ePj0Ssqa0Eja5-clip-0"><rect stroke="none" x="9.41" y="-303.2" width="86.62" height="48.79999999999998" rx="12" ry="12" class="node-bg"/></clipPath></g>
16<!-- n8 -->
17<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-n">
18
19<rect stroke="none" x="30.38" y="-218.4" width="44.68000000000001" height="48.80000000000001" rx="12" ry="12" class="node-bg"/>
20<rect stroke="none" x="26" y="-222" width="52" height="27" clip-path="url(#refinery-83G8OR--ePj0Ssqa0Eja5-clip-1)" class="node-header"/>
21<text text-anchor="start" x="41.65" y="-202.6" font-size="12.00">dir2</text>
22<use x="36.38" y="-188.8" width="12" height="12" href="#refinery-83G8OR--ePj0Ssqa0Eja5-icon-TRUE" class="icon icon-TRUE"/>
23<g><text text-anchor="start" x="52.38" y="-179.2" font-size="12.00" class="label label-TRUE">Dir</text>
24</g>
25<polyline points="30.38,-195 75.06,-195" class="node-outline"/>
26<rect fill="none" x="30.38" y="-218.4" width="44.68000000000001" height="48.80000000000001" rx="12" ry="12" class="node-outline"/>
27<clipPath id="refinery-83G8OR--ePj0Ssqa0Eja5-clip-1"><rect stroke="none" x="30.38" y="-218.4" width="44.68000000000001" height="48.80000000000001" rx="12" ry="12" class="node-bg"/></clipPath></g>
28<!-- n4&#45;&gt;n8 -->
29<g class="edge edge-TRUE">
30
31<path fill="none" stroke-width="2" d="M52.72,-254.74C52.72,-246.99 52.72,-238.18 52.72,-229.75" class="edge-line"/>
32<polygon stroke-width="2" points="55.78,-230 52.72,-221.25 49.66,-230.01 55.78,-230" class="edge-line edge-arrow"/>
33<text text-anchor="start" x="30.39" y="-240.67" font-weight="bold" font-size="10.50">root</text>
34</g>
35<!-- n5 -->
36<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-g">
37
38<rect stroke="none" x="128.41" y="-303.2" width="86.62" height="48.79999999999998" rx="12" ry="12" class="node-bg"/>
39<rect stroke="none" x="124" y="-307" width="94" height="27" clip-path="url(#refinery-83G8OR--ePj0Ssqa0Eja5-clip-2)" class="node-header"/>
40<text text-anchor="start" x="140.04" y="-287.4" font-size="12.00">filesystem2</text>
41<use x="134.409" y="-273.6" width="12" height="12" href="#refinery-83G8OR--ePj0Ssqa0Eja5-icon-TRUE" class="icon icon-TRUE"/>
42<g><text text-anchor="start" x="150.41" y="-264" font-size="12.00" class="label label-TRUE">Filesystem</text>
43</g>
44<polyline points="128.41,-279.8 215.03,-279.8" class="node-outline"/>
45<rect fill="none" x="128.41" y="-303.2" width="86.62" height="48.79999999999998" rx="12" ry="12" class="node-outline"/>
46<clipPath id="refinery-83G8OR--ePj0Ssqa0Eja5-clip-2"><rect stroke="none" x="128.41" y="-303.2" width="86.62" height="48.79999999999998" rx="12" ry="12" class="node-bg"/></clipPath></g>
47<!-- n6 -->
48<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-n">
49
50<rect stroke="none" x="149.38" y="-218.4" width="44.68000000000001" height="48.80000000000001" rx="12" ry="12" class="node-bg"/>
51<rect stroke="none" x="145" y="-222" width="52" height="27" clip-path="url(#refinery-83G8OR--ePj0Ssqa0Eja5-clip-3)" class="node-header"/>
52<text text-anchor="start" x="160.65" y="-202.6" font-size="12.00">dir1</text>
53<use x="155.38" y="-188.8" width="12" height="12" href="#refinery-83G8OR--ePj0Ssqa0Eja5-icon-TRUE" class="icon icon-TRUE"/>
54<g><text text-anchor="start" x="171.38" y="-179.2" font-size="12.00" class="label label-TRUE">Dir</text>
55</g>
56<polyline points="149.38,-195 194.06,-195" class="node-outline"/>
57<rect fill="none" x="149.38" y="-218.4" width="44.68000000000001" height="48.80000000000001" rx="12" ry="12" class="node-outline"/>
58<clipPath id="refinery-83G8OR--ePj0Ssqa0Eja5-clip-3"><rect stroke="none" x="149.38" y="-218.4" width="44.68000000000001" height="48.80000000000001" rx="12" ry="12" class="node-bg"/></clipPath></g>
59<!-- n5&#45;&gt;n6 -->
60<g class="edge edge-TRUE">
61
62<path fill="none" stroke-width="2" d="M171.72,-254.74C171.72,-246.99 171.72,-238.18 171.72,-229.75" class="edge-line"/>
63<polygon stroke-width="2" points="174.78,-230 171.72,-221.25 168.66,-230.01 174.78,-230" class="edge-line edge-arrow"/>
64<text text-anchor="start" x="149.39" y="-240.67" font-weight="bold" font-size="10.50">root</text>
65</g>
66<!-- n7 -->
67<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
68
69<rect stroke="none" x="146.26" y="-133.6" width="50.920000000000016" height="48.8" rx="12" ry="12" class="node-bg"/>
70<rect stroke="none" x="142" y="-137" width="58" height="27" clip-path="url(#refinery-83G8OR--ePj0Ssqa0Eja5-clip-4)" class="node-header"/>
71<text text-anchor="start" x="158.42" y="-117.8" font-size="12.00">link1</text>
72<use x="152.257" y="-104" width="12" height="12" href="#refinery-83G8OR--ePj0Ssqa0Eja5-icon-TRUE" class="icon icon-TRUE"/>
73<g><text text-anchor="start" x="168.26" y="-94.4" font-size="12.00" class="label label-TRUE">Link</text>
74</g>
75<polyline points="146.26,-110.2 197.18,-110.2" class="node-outline"/>
76<rect fill="none" x="146.26" y="-133.6" width="50.920000000000016" height="48.8" rx="12" ry="12" class="node-outline"/>
77<clipPath id="refinery-83G8OR--ePj0Ssqa0Eja5-clip-4"><rect stroke="none" x="146.26" y="-133.6" width="50.920000000000016" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
78<!-- n6&#45;&gt;n7 -->
79<g class="edge edge-TRUE">
80
81<path fill="none" stroke-width="2" d="M165.6,-169.94C165.03,-162.19 164.85,-153.38 165.05,-144.95" class="edge-line"/>
82<polygon stroke-width="2" points="168.1,-145.33 165.44,-136.45 161.98,-145.05 168.1,-145.33" class="edge-line edge-arrow"/>
83<text text-anchor="start" x="118.73" y="-155.87" font-weight="bold" font-size="10.50">contents</text>
84</g>
85<!-- n9 -->
86<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-n">
87
88<rect stroke="none" x="215.38" y="-133.6" width="44.68000000000001" height="48.8" rx="12" ry="12" class="node-bg"/>
89<rect stroke="none" x="211" y="-137" width="52" height="27" clip-path="url(#refinery-83G8OR--ePj0Ssqa0Eja5-clip-5)" class="node-header"/>
90<text text-anchor="start" x="226.65" y="-117.8" font-size="12.00">dir3</text>
91<use x="221.38" y="-104" width="12" height="12" href="#refinery-83G8OR--ePj0Ssqa0Eja5-icon-TRUE" class="icon icon-TRUE"/>
92<g><text text-anchor="start" x="237.38" y="-94.4" font-size="12.00" class="label label-TRUE">Dir</text>
93</g>
94<polyline points="215.38,-110.2 260.06,-110.2" class="node-outline"/>
95<rect fill="none" x="215.38" y="-133.6" width="44.68000000000001" height="48.8" rx="12" ry="12" class="node-outline"/>
96<clipPath id="refinery-83G8OR--ePj0Ssqa0Eja5-clip-5"><rect stroke="none" x="215.38" y="-133.6" width="44.68000000000001" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
97<!-- n6&#45;&gt;n9 -->
98<g class="edge edge-TRUE">
99
100<path fill="none" stroke-width="2" d="M190.11,-169.94C196.84,-161.48 204.6,-151.75 211.87,-142.63" class="edge-line"/>
101<polygon stroke-width="2" points="214.26,-144.55 217.32,-135.79 209.47,-140.73 214.26,-144.55" class="edge-line edge-arrow"/>
102<text text-anchor="start" x="204.61" y="-155.89" font-weight="bold" font-size="10.50">contents</text>
103</g>
104<!-- n7&#45;&gt;n6 -->
105<g class="edge edge-TRUE">
106
107<path fill="none" d="M177.86,-133.43C178.42,-141.27 178.6,-150.2 178.38,-158.72" class="edge-line"/>
108<polygon points="174.9,-158.27 177.92,-168.42 181.89,-158.6 174.9,-158.27" class="edge-line edge-arrow"/>
109<text text-anchor="middle" x="163.88" y="-142.02" font-size="10.50">target</text>
110</g>
111<!-- n7&#45;&gt;n6 -->
112<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
113
114<rect stroke="none" x="16.22" y="-133.6" width="47" height="48.8" rx="12" ry="12" class="node-bg"/>
115<rect stroke="none" x="12" y="-137" width="55" height="27" clip-path="url(#refinery-83G8OR--ePj0Ssqa0Eja5-clip-6)" class="node-header"/>
116<text text-anchor="start" x="27.86" y="-117.8" font-size="12.00">file3</text>
117<use x="22.2228" y="-104" width="12" height="12" href="#refinery-83G8OR--ePj0Ssqa0Eja5-icon-TRUE" class="icon icon-TRUE"/>
118<g><text text-anchor="start" x="38.22" y="-94.4" font-size="12.00" class="label label-TRUE">File</text>
119</g>
120<polyline points="16.22,-110.2 63.22,-110.2" class="node-outline"/>
121<rect fill="none" x="16.22" y="-133.6" width="47" height="48.8" rx="12" ry="12" class="node-outline"/>
122<clipPath id="refinery-83G8OR--ePj0Ssqa0Eja5-clip-6"><rect stroke="none" x="16.22" y="-133.6" width="47" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
123<!-- n12 -->
124<g class="edge edge-TRUE">
125
126<path fill="none" stroke-width="2" d="M49.1,-169.94C47.88,-162.19 46.5,-153.38 45.18,-144.95" class="edge-line"/>
127<polygon stroke-width="2" points="48.22,-144.59 43.84,-136.42 42.17,-145.54 48.22,-144.59" class="edge-line edge-arrow"/>
128<text text-anchor="start" x="0" y="-155.87" font-weight="bold" font-size="10.50">contents</text>
129</g>
130<!-- n8&#45;&gt;n12 -->
131<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
132
133<rect stroke="none" x="81.22" y="-133.6" width="47" height="48.8" rx="12" ry="12" class="node-bg"/>
134<rect stroke="none" x="77" y="-137" width="55" height="27" clip-path="url(#refinery-83G8OR--ePj0Ssqa0Eja5-clip-7)" class="node-header"/>
135<text text-anchor="start" x="92.86" y="-117.8" font-size="12.00">file4</text>
136<use x="87.2228" y="-104" width="12" height="12" href="#refinery-83G8OR--ePj0Ssqa0Eja5-icon-TRUE" class="icon icon-TRUE"/>
137<g><text text-anchor="start" x="103.22" y="-94.4" font-size="12.00" class="label label-TRUE">File</text>
138</g>
139<polyline points="81.22,-110.2 128.22,-110.2" class="node-outline"/>
140<rect fill="none" x="81.22" y="-133.6" width="47" height="48.8" rx="12" ry="12" class="node-outline"/>
141<clipPath id="refinery-83G8OR--ePj0Ssqa0Eja5-clip-7"><rect stroke="none" x="81.22" y="-133.6" width="47" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
142<!-- n13 -->
143<g class="edge edge-TRUE">
144
145<path fill="none" stroke-width="2" d="M67.21,-169.94C72.4,-161.66 78.37,-152.16 83.99,-143.21" class="edge-line"/>
146<polygon stroke-width="2" points="86.46,-145.03 88.52,-135.99 81.28,-141.77 86.46,-145.03" class="edge-line edge-arrow"/>
147<text text-anchor="start" x="32.41" y="-143.26" font-weight="bold" font-size="10.50">contents</text>
148</g>
149<!-- n8&#45;&gt;n13 -->
150<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
151
152<rect stroke="none" x="181.22" y="-48.8" width="47" height="48.8" rx="12" ry="12" class="node-bg"/>
153<rect stroke="none" x="177" y="-52" width="55" height="27" clip-path="url(#refinery-83G8OR--ePj0Ssqa0Eja5-clip-8)" class="node-header"/>
154<text text-anchor="start" x="192.86" y="-33" font-size="12.00">file1</text>
155<use x="187.223" y="-19.2" width="12" height="12" href="#refinery-83G8OR--ePj0Ssqa0Eja5-icon-TRUE" class="icon icon-TRUE"/>
156<g><text text-anchor="start" x="203.22" y="-9.6" font-size="12.00" class="label label-TRUE">File</text>
157</g>
158<polyline points="181.22,-25.4 228.22,-25.4" class="node-outline"/>
159<rect fill="none" x="181.22" y="-48.8" width="47" height="48.8" rx="12" ry="12" class="node-outline"/>
160<clipPath id="refinery-83G8OR--ePj0Ssqa0Eja5-clip-8"><rect stroke="none" x="181.22" y="-48.8" width="47" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
161<!-- n9&#45;&gt;n6 -->
162<g class="edge edge-TRUE">
163
164<path fill="none" stroke-width="2" d="M228.53,-85.14C225.37,-77.22 221.77,-68.18 218.34,-59.57" class="edge-line"/>
165<polygon stroke-width="2" points="221.18,-58.43 215.1,-51.44 215.49,-60.7 221.18,-58.43" class="edge-line edge-arrow"/>
166<text text-anchor="start" x="175.02" y="-71.05" font-weight="bold" font-size="10.50">contents</text>
167</g>
168<!-- n10 -->
169<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
170
171<rect stroke="none" x="246.22" y="-48.8" width="47.00000000000003" height="48.8" rx="12" ry="12" class="node-bg"/>
172<rect stroke="none" x="242" y="-52" width="55" height="27" clip-path="url(#refinery-83G8OR--ePj0Ssqa0Eja5-clip-9)" class="node-header"/>
173<text text-anchor="start" x="257.86" y="-33" font-size="12.00">file2</text>
174<use x="252.223" y="-19.2" width="12" height="12" href="#refinery-83G8OR--ePj0Ssqa0Eja5-icon-TRUE" class="icon icon-TRUE"/>
175<g><text text-anchor="start" x="268.22" y="-9.6" font-size="12.00" class="label label-TRUE">File</text>
176</g>
177<polyline points="246.22,-25.4 293.22,-25.4" class="node-outline"/>
178<rect fill="none" x="246.22" y="-48.8" width="47.00000000000003" height="48.8" rx="12" ry="12" class="node-outline"/>
179<clipPath id="refinery-83G8OR--ePj0Ssqa0Eja5-clip-9"><rect stroke="none" x="246.22" y="-48.8" width="47.00000000000003" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
180<!-- n9&#45;&gt;n10 -->
181<g class="edge edge-TRUE">
182
183<path fill="none" stroke-width="2" d="M246.63,-85.14C249.69,-77.22 253.19,-68.18 256.52,-59.57" class="edge-line"/>
184<polygon stroke-width="2" points="259.35,-60.72 259.65,-51.45 253.64,-58.51 259.35,-60.72" class="edge-line edge-arrow"/>
185<text text-anchor="start" x="207.44" y="-58.45" font-weight="bold" font-size="10.50">contents</text>
186</g>
187</g>
188</svg> \ No newline at end of file
diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig4.svg.license b/subprojects/docs/src/docs/learn/tutorials/file-system/generatedModel1Simplified.svg.license
index b80566a0..b80566a0 100644
--- a/subprojects/docs/src/learn/tutorials/file-system/fig4.svg.license
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/generatedModel1Simplified.svg.license
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/index.md b/subprojects/docs/src/docs/learn/tutorials/file-system/index.md
new file mode 100644
index 00000000..2a17a21b
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/index.md
@@ -0,0 +1,173 @@
1---
2SPDX-FileCopyrightText: 2023-2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4description: Introduction to classes, references, and error predicates
5sidebar_position: 0
6sidebar_label: File system
7---
8
9# File system tutorial
10
11This tutorial gives a brief overview of the partial modeling and model generation features of the Refinery framework.
12It follows the development and analysis of a simple Refinery problem specification for modeling file systems.
13We adapted the case study from [Chapter 1](https://alloytools.org/tutorials/online/frame-FS-1.html) of the [Alloy tutorial][alloy].
14
15[alloy]: https://alloytools.org/tutorials/online/index.html
16
17## Describing domain concepts
18
19The Refinery partial modeling language supports [metamodeling](../../language/classes/index.md) to describe desired structure of generated models.
20We may use [classes](../../language/classes/index.md#classes) and [references](../../language/classes/index.md#references) to describe domain concepts similarly to [object-oriented programming languages](https://en.wikipedia.org/wiki/Object-oriented_programming), such as C++ and Java.
21
22```refinery checkpoint=metamodel try
23class Filesystem {
24 contains Dir[1] root
25}
26
27abstract class FSObject {
28 container Dir parent opposite contents
29}
30
31class Dir extends FSObject {
32 contains FSObject[] contents opposite parent
33}
34
35class File extends FSObject.
36
37class Link extends FSObject {
38 FSObject[1] target
39}
40```
41
42Throughout this website, the _Try in Refinery_ button will always denote an interactive example.
43If you click it now, it'll take you to the [Refinery web UI](#refinery-web-ui).
44
45### Metamodel constraints
46
47Our specification not only lists the concepts (classes and relations) of [file system](#describing-domain-concepts) the domain, but also prescribes a set of **metamodel constraints** concisely.
48
49:::info
50
51Metamodel constraints are often left implicit in programming. For example, the Java runtime environment will always prevent us from instantiating an `abstract` class.
52However, in _logical_ languages like [Alloy][alloy], we have to [specify most of these constraints](https://alloytools.org/tutorials/online/frame-FS-1.html) manually.
53
54While Refinery has a rigorous [logical background](../../language/logic/index.md), you'll see that it still lets us define domains in high-level terms.
55
56:::
57
58Some constraints are about possible instances of classes:
59
60* The classes `Dir`, `File`, and `Link` are marked as [**subclasses**](../../language/classes/index.md#inheritance) of `FSObject` with the `extends` keyword. Instances of the classes must also be instances of `FSObject`.
61* Conversely, the class `FSObject` is marked as an **abstract class** with the `abstract` keyword. This means that any instance of `FSObject` must also be an instance of one of its subclasses.
62* Classes that do not have a common superclass[^multiple-inheritance] are **disjoint,** i.e., they can't have any instances in common.
63
64[^multiple-inheritance]: The Refinery language supports _multiple inheritance,_ where a class may extend multiple superclasses. However, in this tutorial, we'll rely on single inheritance only.
65
66Other constraints are about references:
67
68* References between classes must adhere to **[type constraints](../../language/classes/index.md#references).** For example, the source of a `parent` relationship must be an `FSObject` instance and its target must be a `Dir` instance.
69* There is an [**opposite constraint**](../../language/classes/index.md#opposite-constraints) between `parent` and `contents`. Every occurrence of a `parent` relationship must have a `contents` relationship in the other direction and vice versa.
70* All references must obey the corresponding **[multiplicity constrains](../../language/classes/index.md#multiplicity):**
71 * The notation `[]` means that multiple outgoing references are allowed, i.e., a `Dir` instance may have 0 or more `contents`. If we wanted to forbid empty `Dir`s, we could do so by writing `[1..*]` instead.
72 * The notation `[1]` means that there is _exactly_ one `root` for a `Filesystem` or `target` for a `Link`.
73 * If there is no specified multiplicity, such as in the case of `parent`, 0 or 1 outgoing references are assumed. This closely matches most object-oriented programming languages, where a reference by default may be `null`.
74* The references `root` and `contents` are marked with the keyword `contains` as **containment references** that form a **[containment hierarchy](../../language/classes/index.md#containment-hierarchy):**
75 * Instances of classes that appear as the _reference type_ of a containment reference, such as the instances of `FSObject` (and its subclasses), _must_ have an incoming containment relationship.
76 * Conversely, the instances of `Filesystem` are the **roots** of the containment hierarchy.
77
78Notice that we could use metamodel constraints to describe most of how our domain works. For example, we don't have to further elaborate that a single file system has a single root directory and forms a tree, or that a link points to exactly one target.
79
80You can read more about else what you can express with metamodel constraints by clicking on the links in the lists above. They'll take you to the relevant parts of the [Refinery language reference](../../language/).
81
82## Model generation
83
84Model generation automatically constructs possible instance models of your problem specification.
85You can use it to get _examples_ for reasoning about a domain, _candidate designs_ for an engineering problem, or _test cases_ for data-driven software.
86
87Before we can start generating models, we'll need to specify the desired model size[^model-size]. In this example, we'll generate an instance which has between 10 and 20 nodes (objects) by using the following [`scope`](../../language/logic/index.md#type-scopes) declaration:
88
89[^model-size]: If you don't specify the model size at all, Refinery will often return an _empty_ model if it can satisfy the domain constraints that way. On the other hand, you shouldn't be very strict with the desired model size (e.g., generate _exactly_ 10 nodes) either, because some constraints may be unsatisfiable for specific model sizes.
90
91```refinery continue try
92scope node = 10..20.
93```
94
95You should click the button labeled _Try in Refinery_ above to open this problem specification in Refinery.
96
97### Refinery web UI
98
99Since you've just opened the user interface of Refinery, this is a great time to familiarize yourself with it!
100We annotated the following screenshot to show your the various parts of the interface.
101
102![Screenshot of the Refinery interface with the file system problem specification opened. Parts of the user interface are annotated with numbered callouts.](./initialModelLight.png|./initialModelDark.png)
103
104import CloudIcon from '@material-icons/svg/svg/cloud/baseline.svg';
105import CloudOffIcon from '@material-icons/svg/svg/cloud_off/baseline.svg';
106import CodeIcon from '@material-icons/svg/svg/code/baseline.svg';
107import PlayArrowIcon from '@material-icons/svg/svg/play_arrow/baseline.svg';
108import SaveAltIcon from '@material-icons/svg/svg/save_alt/baseline.svg';
109import SchemaIcon from '@material-icons/svg/svg/schema/round.svg';
110import SyncProblemIcon from '@material-icons/svg/svg/sync_problem/baseline.svg';
111import TableChartIcon from '@material-icons/svg/svg/table_chart/baseline.svg';
112import TuneIcon from '@material-icons/svg/svg/tune/baseline.svg';
113
1141. The **code editor** appears on the left side of the window by default. It lets you edit your problem specification, and provides common helper functions like auto-complete (content assist), syntax highlighting, syntax checking, and semantic validation.
115
1162. The **toolbar** is located above the code editor, which includes buttons for common editing operations and settings.
117
118 Moreover, you can find the <CloudIcon className="inline-icon" aria-hidden="true" /> **connection** button here. If the button shows a <CloudOffIcon className="inline-icon" aria-hidden="true" /> **disconnected** state or an <SyncProblemIcon className="inline-icon" aria-hidden="true" /> **error,** you should check your internet connection. Clicking the button will attempt to reconnect. Clicking the button _again_ will disconnect from the server, but some code editing services and the model generator require an active connection[^refinery-server].
119
1203. The **graph view** shows a visualization of your problem specification. The visualization of generated models will also appear here. We'll discuss the notation used in the visualization [later in this tutorial](#partial-models).
121
1224. The <TuneIcon className="inline-icon" aria-hidden="true" /> **filter panel** lets you customize what should appear in the visualization. Click the button to open the panel.
123
1245. The <SaveAltIcon className="inline-icon" aria-hidden="true" /> **export panel** lets you save the diagram as an SVG, PDF, or PNG file. Click the button to open the panel.
125
1266. **Zoom controls** lat you adjust the size of the visualization and make it automatically fit the screen.
127
1287. The **view selector** lets you toggle the <CodeIcon className="inline-icon" aria-hidden="true" /> **code,** <SchemaIcon className="inline-icon" aria-hidden="true" /> **graph,** and <TableChartIcon className="inline-icon" aria-hidden="true" /> **table views.** You can have all three views open at the same time, or even just a single one to take a deeper look at the model.
129
1308. Finally, the <PlayArrowIcon className="inline-icon" aria-hidden="true" /> **generate** button initiates model generation. You may only press this button of you problem specification is valid. Otherwise, it'll jump to the validation errors in your specification in the code view. Pressing the button while model generation is running will cancel the generation.
131
132[^refinery-server]: This doesn't mean that you always need an internet connection to use Refinery! You can also download and run our [Docker container](../../docker/index.md) to host a Refinery server on your own machine for yourself or for your organization.
133
134### Running the generator
135
136You can initiate model generation by clicking the <PlayArrowIcon className="inline-icon" aria-hidden="true" /> **generate** button.
137It should return an instance model like this:
138
139![First model generated from the problem specification by Refinery](./generatedModel1.svg)
140
141Take a moment to verify that this model indeed satisfies the [metamodel constraints](#metamodel-constraints) and contains between 10 and 20 nodes as we [previously requested](#model-generation).
142
143You can use the <TuneIcon className="inline-icon" aria-hidden="true" /> **filter panel** to simplify this visualization.
144It is readily apparent from the [metamodel constraints](#metamodel-constraints) that all non-`Filesystem` nodes are `FSObject` instances, and the `parent` relationships always appear in `opposite` to the `contents` relationships. Thus, we can hide `FSObject` and `parent` from the visualization entirely without losing any information with the following filter settings:
145
146![Filter panel settings for simplified visualization. Both checkboxes near FSObject and parent are unchecked.](./filterPanelLight.png|./filterPanelDark.png)
147
148We end up with the following visualization:
149
150![Simplified visualization of the first generated model](./generatedModel1Simplified.svg)
151
152Clicking the <PlayArrowIcon className="inline-icon" aria-hidden="true" /> **generate** button will yield different models by selecting a different _random seed_ to control the model generator.
153This means that if you want to see multiple different instance models for your problem specification, you can just run the generation multiple times.
154
155import CloseIcon from '@material-icons/svg/svg/close/baseline.svg';
156
157Generated models will appear as _tabs_ in the Refinery web UI.
158You should also take the moment to explore the tabular representations of the generated model in the <TableChartIcon className="inline-icon" aria-hidden="true" /> **table view.**
159You can remove generated models that you no longer need by clicking the <CloseIcon className="inline-icon" aria-hidden="true" /> **close** button.
160
161At the end of this exercise, you should be looking at something like this in Refinery:
162
163![Refinery user interface with multiple generated models and the table view open](./modelGenerationLight.png|./modelGenerationDark.png)
164
165## Partial models
166
167:::warning
168
169This section of the tutorial is under construction.
170
171:::
172
173![Visualization corresponding to the file system metamodel](./metamodel.svg)
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.png b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.png
new file mode 100644
index 00000000..4cfa0812
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.png
Binary files differ
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.png.license b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.png.license
new file mode 100644
index 00000000..4265fd6c
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.png.license
@@ -0,0 +1,5 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
4
5This file was automatically generated from initialModelDark.svg.
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.svg b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.svg
new file mode 100644
index 00000000..ec5b1c93
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.svg
@@ -0,0 +1,216 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Created with Inkscape (http://www.inkscape.org/) -->
3
4<svg
5 version="1.1"
6 id="svg1"
7 width="1920"
8 height="1080"
9 viewBox="0 0 1920 1080"
10 sodipodi:docname="initialModelDark.svg"
11 inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
12 inkscape:export-filename="initialModelDark.png"
13 inkscape:export-xdpi="96"
14 inkscape:export-ydpi="96"
15 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
16 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
17 xmlns:xlink="http://www.w3.org/1999/xlink"
18 xmlns="http://www.w3.org/2000/svg"
19 xmlns:svg="http://www.w3.org/2000/svg">
20 <defs
21 id="defs1" />
22 <sodipodi:namedview
23 id="namedview1"
24 pagecolor="#ffffff"
25 bordercolor="#666666"
26 borderopacity="1.0"
27 inkscape:showpageshadow="2"
28 inkscape:pageopacity="0.0"
29 inkscape:pagecheckerboard="0"
30 inkscape:deskcolor="#d1d1d1"
31 showgrid="false"
32 inkscape:zoom="1.0733371"
33 inkscape:cx="932.60546"
34 inkscape:cy="334.93673"
35 inkscape:window-width="2560"
36 inkscape:window-height="1415"
37 inkscape:window-x="0"
38 inkscape:window-y="0"
39 inkscape:window-maximized="0"
40 inkscape:current-layer="layer1"
41 showguides="true" />
42 <g
43 inkscape:groupmode="layer"
44 inkscape:label="Image"
45 id="g1"
46 sodipodi:insensitive="true">
47 <image
48 width="1920"
49 height="1080"
50 preserveAspectRatio="none"
51 xlink:href="data:image/png;base64,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&#10;uWms3knB6n+x8JV32HEGKvoBQtVv8NDXfXzx3ru4aOIQkqMisRwz1hA1yx7m3vI1Xdc1OymaCEwC&#10;PheN1SVsWfMvXlq4hNKw/6JHRERERERERERETpYxevw0vdETkXNL5CU88tZPuchYzY9v+jrvKHEx&#10;cBnxJN/7INl5HTT99WEqtp9sDaIFx2XfYMRlGfg/fJKSxWdiaHsREREZSJob60lISg13GCIiIp+K&#10;MzaW1NS0ruUDB+ppa20NY0QiIiLSn6kCWERERERERERERKQfc7W14WprC3cYIiIiMkBYTtxERERE&#10;REREREREREREREQGAiWARURERERERERERERERETOEZoDWERERERERM55mgNYREQGshEjR3HB3Iu6&#10;lld/tJKSHcVhjEhERET6M80BLCIiIiIiIiIiItKPOZ2xDB2a17VcWLA5jNGIiIhIf6choEVERERE&#10;REREREREREREzhFKAIuIiIiIiIiIiIiIiIiInCM0BLSIiIiIiIiIiIhIP5CTO4jIyMge61PT0rot&#10;p6SmMnRYXo92gUCAivJ9Zyw+ERERGRiM0eOnmeEOQkRERERERORMam6sJyEpNdxhiIiIHNett93F&#10;hEn5n7r/tq1FvPTCc30YkYiIiAxEGgJaREREREREREREpB8oLNx8Wv23bNnUR5GIiIjIQKYEsIiI&#10;iIiIiIiIiEg/ULqzBI+n/VP19Xq9lJbs6OOIREREZCDSHMAiIiIiIiIiIiIi/UAwGGTr1kKmT5/Z&#10;tW737lLK9+7t0TZ38GCGDx/ZtVy8rYhAIHA2whQREZF+TglgERERERERERERkX6iaEtBtwSwgcHy&#10;ZUt7tPvM577UbblwS8EZj01EREQGBg0BLSIiIiIiIiIiItJP7N1ThsvV1rU8dFgezpjYbm2ioqIZ&#10;NnxE17LL1cae3aVnLUYRERHp386hCmCDmEm3c+/lgzG9rRyo2MHmNavZXufDDHdoIiIiIiIiIiIi&#10;IifBNE22FGxi9py5ABiGwYT8fNau/qirzcRJk7FaDtf2FBUWEDL1FlREREQ6nVMVwIY9lvjEZFIy&#10;hzJ6xpXcft9XuWSIAyPcgYmIiIiIiIiIiIicpMKC7sM5T5w0uftyfvdlDf8sIiIiRzqHEsAmrvXP&#10;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&#10;vIGDBjN33tm43W5eX/Syt8sRERGRPqz/BsDWZObeeC2To6vY8d7jfLrdQa3Lra2ARURERERERERE&#10;zkCF+XltAbBhGISGhhIaGtp2PSAwgJjYOEaOSqO52YWzrJzKqkqcznKqKivJzcmipKTYW+WflpCQ&#10;UK6/4WYMw+CTJR9QXOzwdkkiIiLSh/XbRlhL/BhGRVsxSzazenM+NQp/RUREREREREREzliFhYVd&#10;vtfPz0Z8YiKjRqcxe848LrnsCuz2oG49b/KUacydfw5BQd0b113Dho9gwXkXYjGMDq9bDIMbvnMr&#10;gXY7mZm7+Hr9ul6tR0RERPq/fhsAGzZ//A0wXU00KfkVERERERERERE5oxUW5p/y2H1795CVtb9b&#10;YyZMnMS5Cy4g0G4/5ed2xciRacyZdzbfveOHhISEHnd9wXkXkpSUTGVlJW+98Vqv1iIiIiLfDv13&#10;CehmF80mBPrZsBmg9l8REREREREREZEzV3FRIW6PB6vlYM9KWVkpjz/6f9jtQYRHRBAefvCfuPgE&#10;Ro1Ow2q1to1dvmxpt55lMQwSE5NxNbkoLSnp0dfR7jkWCyNGjwYgNXUg9/zoft568zX27d0DwNBh&#10;w5k1dz4tLa0sevkFml2uXqtFREREvj36bQew6WrCZYLhH3AwABYREREREREREZEzVktLK6VH7eEb&#10;HR2Dr48v9fV1FOTnsWP7Nr78YiWVlc524e/ePZk4Cgu69azkAQOxWCxkZx/osfo7fE5yCkH2ILKz&#10;DrD6y88JtNu55bbbOf/8hVgMgwXnLwRgyUfvad9fERER6TH9tgPYbGqkCTBsAdi8XYyIiIiIiIiI&#10;iIiclKMgn/j4hLbj5JQB7ZZ2DgwMZOq0me3GLOtm9y9ASsoAAHJzs0+x0q4ZOToNgPT0rWze+DU5&#10;WVlcff2NzJo7nwGDBvHm4lcZOTKNTRu/7tU6RERE5NulH3cAN+IyAT9//PvtqxQREREREREREek/&#10;Cgra7wOckJTU7nj27HnYbEfaPXZnZlDs6H7nbMqAVAByc3o3AB49egymaZK5awcAe/fu5p+PP0pR&#10;YSHJyQO44657cDi6170sIiIicjL9Nho1fHyPtDdrCWgREREREREREZEznqOwsN1xYuKRADgwMJCp&#10;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&#10;AAAAgIL4X5Ai0Ej9GSIDAAAAAElFTkSuQmCC&#10;"
52 id="image1"
53 x="0"
54 y="0" />
55 </g>
56 <g
57 inkscape:groupmode="layer"
58 id="layer1"
59 inkscape:label="Annotations"
60 transform="translate(-461.15282,-418.07992)">
61 <g
62 id="g13">
63 <rect
64 style="fill:#56b6c2;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
65 id="rect1"
66 width="80"
67 height="80"
68 x="1041.1528"
69 y="1093.08"
70 rx="6.4000001"
71 ry="6.4000001" />
72 <text
73 xml:space="preserve"
74 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
75 x="1081.1382"
76 y="1154.496"
77 id="text1"><tspan
78 sodipodi:role="line"
79 id="tspan1"
80 x="1081.1382"
81 y="1154.496"
82 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1">1</tspan></text>
83 </g>
84 <g
85 id="g14">
86 <path
87 id="rect1-7"
88 style="fill:#56b6c2;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
89 d="m 1107.5532,528.07992 c -3.5456,0 -6.4004,2.85479 -6.4004,6.40039 v 6.38867 l -24,13.85547 24,13.85742 v 33.09766 c 0,3.5456 2.8548,6.40039 6.4004,6.40039 h 67.1992 c 3.5456,0 6.4004,-2.85479 6.4004,-6.40039 v -67.19922 c 0,-3.5456 -2.8548,-6.40039 -6.4004,-6.40039 z" />
90 <text
91 xml:space="preserve"
92 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
93 x="1141.1382"
94 y="589.49591"
95 id="text1-0"><tspan
96 sodipodi:role="line"
97 id="tspan1-9"
98 x="1141.1382"
99 y="589.49591"
100 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1">2</tspan></text>
101 </g>
102 <g
103 id="g16">
104 <path
105 id="rect1-7-6"
106 style="fill:#56b6c2;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
107 d="m 1526.5532,534.07992 c -3.5456,0 -6.4004,2.85479 -6.4004,6.40039 v 6.38867 l -24,13.85547 24,13.85742 v 33.09766 c 0,3.5456 2.8548,6.40039 6.4004,6.40039 h 67.1992 c 3.5456,0 6.4004,-2.85479 6.4004,-6.40039 v -67.19922 c 0,-3.5456 -2.8548,-6.40039 -6.4004,-6.40039 z" />
108 <text
109 xml:space="preserve"
110 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
111 x="1560.1382"
112 y="595.49591"
113 id="text1-0-1"><tspan
114 sodipodi:role="line"
115 id="tspan1-9-8"
116 x="1560.1382"
117 y="595.49591"
118 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1">4</tspan></text>
119 </g>
120 <g
121 id="g19">
122 <path
123 id="rect1-7-6-5"
124 style="fill:#56b6c2;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
125 d="m 1656.5532,443.07992 c -3.5456,0 -6.4004,2.85479 -6.4004,6.40039 v 6.38867 l -24,13.85547 24,13.85742 v 33.09766 c 0,3.5456 2.8548,6.40039 6.4004,6.40039 h 67.1992 c 3.5456,0 6.4004,-2.85479 6.4004,-6.40039 v -67.19922 c 0,-3.5456 -2.8548,-6.40039 -6.4004,-6.40039 z" />
126 <text
127 xml:space="preserve"
128 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
129 x="1690.1382"
130 y="504.49591"
131 id="text1-0-1-0"><tspan
132 sodipodi:role="line"
133 id="tspan1-9-8-3"
134 x="1690.1382"
135 y="504.49591"
136 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1">7</tspan></text>
137 </g>
138 <g
139 id="g17">
140 <path
141 id="rect1-7-6-3-9"
142 style="fill:#56b6c2;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
143 d="m 2279.7524,534.07992 c 3.5456,0 6.4004,2.85479 6.4004,6.40039 v 6.38867 l 24,13.85547 -24,13.85742 v 33.09766 c 0,3.5456 -2.8548,6.40039 -6.4004,6.40039 h -67.1992 c -3.5456,0 -6.4004,-2.85479 -6.4004,-6.40039 v -67.19922 c 0,-3.5456 2.8548,-6.40039 6.4004,-6.40039 z" />
144 <text
145 xml:space="preserve"
146 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
147 x="2246.1382"
148 y="595.49591"
149 id="text1-0-1-7"><tspan
150 sodipodi:role="line"
151 id="tspan1-9-8-5"
152 x="2246.1382"
153 y="595.49591"
154 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1">5</tspan></text>
155 </g>
156 <g
157 id="g20">
158 <path
159 id="rect1-7-6-3-9-2"
160 style="fill:#56b6c2;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
161 d="m 2174.1608,528.48032 c 0,-3.5456 -2.8548,-6.4004 -6.4004,-6.4004 h -6.3887 l -13.8554,-24 -13.8574,24 h -33.0977 c -3.5456,0 -6.4004,2.8548 -6.4004,6.4004 v 67.1992 c 0,3.5456 2.8548,6.4004 6.4004,6.4004 h 67.1992 c 3.5456,0 6.4004,-2.8548 6.4004,-6.4004 z" />
162 <text
163 xml:space="preserve"
164 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
165 x="2134.1462"
166 y="583.49591"
167 id="text1-0-1-7-5"><tspan
168 sodipodi:role="line"
169 id="tspan1-9-8-5-69"
170 x="2134.1462"
171 y="583.49591"
172 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1">8</tspan></text>
173 </g>
174 <g
175 id="g18">
176 <path
177 id="rect1-7-6-3-9-9"
178 style="fill:#56b6c2;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
179 d="m 2279.7524,1395.7426 c 3.5456,0 6.4004,2.8548 6.4004,6.4004 v 6.3887 l 24,13.8555 -24,13.8574 v 33.0976 c 0,3.5456 -2.8548,6.4004 -6.4004,6.4004 h -67.1992 c -3.5456,0 -6.4004,-2.8548 -6.4004,-6.4004 v -67.1992 c 0,-3.5456 2.8548,-6.4004 6.4004,-6.4004 z" />
180 <text
181 xml:space="preserve"
182 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
183 x="2246.1382"
184 y="1457.1586"
185 id="text1-0-1-7-3"><tspan
186 sodipodi:role="line"
187 id="tspan1-9-8-5-1"
188 x="2246.1382"
189 y="1457.1586"
190 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1">6</tspan></text>
191 </g>
192 <g
193 id="g15">
194 <rect
195 style="fill:#56b6c2;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
196 id="rect1-3"
197 width="80"
198 height="80"
199 x="2111.1528"
200 y="918.0799"
201 rx="6.4000001"
202 ry="6.4000001" />
203 <text
204 xml:space="preserve"
205 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
206 x="2151.1382"
207 y="979.49591"
208 id="text1-5"><tspan
209 sodipodi:role="line"
210 id="tspan1-6"
211 x="2151.1382"
212 y="979.49591"
213 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1">3</tspan></text>
214 </g>
215 </g>
216</svg>
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.svg.license b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelDark.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.png b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.png
new file mode 100644
index 00000000..b9cb638f
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.png
Binary files differ
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.png.license b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.png.license
new file mode 100644
index 00000000..e2da67f5
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.png.license
@@ -0,0 +1,5 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
4
5This file was automatically generated from initialModelLight.svg.
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.svg b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.svg
new file mode 100644
index 00000000..25ced632
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.svg
@@ -0,0 +1,224 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Created with Inkscape (http://www.inkscape.org/) -->
3
4<svg
5 version="1.1"
6 id="svg1"
7 width="1920"
8 height="1080"
9 viewBox="0 0 1920 1080"
10 sodipodi:docname="initialModelLight.svg"
11 inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
12 inkscape:export-filename="initialModelLight.png"
13 inkscape:export-xdpi="96"
14 inkscape:export-ydpi="96"
15 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
16 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
17 xmlns:xlink="http://www.w3.org/1999/xlink"
18 xmlns="http://www.w3.org/2000/svg"
19 xmlns:svg="http://www.w3.org/2000/svg">
20 <defs
21 id="defs1" />
22 <sodipodi:namedview
23 id="namedview1"
24 pagecolor="#ffffff"
25 bordercolor="#666666"
26 borderopacity="1.0"
27 inkscape:showpageshadow="2"
28 inkscape:pageopacity="0.0"
29 inkscape:pagecheckerboard="0"
30 inkscape:deskcolor="#d1d1d1"
31 showgrid="false"
32 inkscape:zoom="0.53666853"
33 inkscape:cx="6.5217165"
34 inkscape:cy="630.74315"
35 inkscape:window-width="3840"
36 inkscape:window-height="2135"
37 inkscape:window-x="0"
38 inkscape:window-y="0"
39 inkscape:window-maximized="0"
40 inkscape:current-layer="layer1"
41 showguides="true" />
42 <g
43 inkscape:groupmode="layer"
44 inkscape:label="Image"
45 id="g1"
46 sodipodi:insensitive="true">
47 <image
48 width="1920"
49 height="1080"
50 preserveAspectRatio="none"
51 xlink:href="data:image/png;base64,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&#10;6ozmVwAjlTvZXJfE2PxFNV6n0fKEaaABAAAAoJe5956FRKRUqtIuZIjF4rUffXbg4JGI8NDBA/v7&#10;eHs6OTk6OTna29kSkZurS3BQoHmvnNy8svLyNju0trLuGxttXi4rr8jJvdjeoYfFDTYv1Nc3JJ1P&#10;aa9ZdFSEvZ2defl4wim+nX81+vv5enq4m5eTU9Lq6tq+/46ri0tI8KWzuJhXUKpQtNnMSmrVr2+M&#10;ebmiUpmVndPpWWg0mrNJ59trFhkR7uhwaYx5wskzJq7tr0r7+fh4eXmYl1PS0mtqatps5iyThYUG&#10;m5fz8gtLSkuJqKa2rqpKXVWlLi4pPXX6bEpa+qCB/V779/N6vZ6IFt+1oL3aOsYwjKen+9XtCwBw&#10;k2La+58NANzETHUZP67feEjFMXb9n1o+I6b7w797LUP2b6u/OVzNug2cvWxWX18HUe+eyR4AAG41&#10;CQkJQ4YMsXQVAHATSM/Iqq6uWffdTylpGfkFhVc2mD1z6po3VpmXX/3P2xs2bWmzn6CggL83/2pe&#10;3vTH1lWvr2nviGcT9ltZWRHRhYysOQvuba/ZT99+PmhgP/NyeJ+h7TX7v2cfv+/eReblOxc/kJyc&#10;2maz6VMmTZ483rx87PjJ3zb+0WYzP1/v3ds3mZe3bNvxwsv/ae+4p47+Y747X3bOxelz7m6v2bdf&#10;fTRs6KWouu+gMVqdrs1mTz/x8IPLL12KxctWnk5se3ruSRPGfvz+f83Lb7378Q8//XZlG1sbm36x&#10;MU8/8XB7JXWRp4e7j4/XNXYCAHBz6b0joAGg6wz5qcfPqjkiIp7T1ilSsnKKNRzPWMeOGBV9C6XP&#10;RCQKnDA1PGl9evmpP9459QeRsM/SVSsH4vtrAAAAANC7BPj7nU9Je+C+JUSkNxhycvJKFYqy8gqF&#10;olylVnM8Z2trc+FCprmxldQqMjKszX7kbq5NzbRaXXvNiCgv71LMXaoo76CZUqlq6jAmKsLEc202&#10;40xcUzMPudwYaWyzmbW19b59h83LNrbtnoWri0tTbw0Nmg7Ky8nNk4jFRFRRoeygmUpV1dRhRESo&#10;Tq9vsxnHNTsLd3l7HTo62Dc1k4pF5mbWUisbWxs7G2tHJ8eYyIjQkKD2iuk6a2vrphHZAAC3D4yA&#10;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&#10;bGzs+bw0ATQAAAAA4GIRGBiYmBiYmBhfYbOVlpSWlZeXlJSVl5f7uq9mwGg0ms0mU2Cg2RxkNBp9&#10;3Q4AoHEqKioOHDjgeXGeL00ADQAAAAC46BgDAowBARG+bgMAgAseDyEEAAAAAAAAAKiCABoAAAAA&#10;AAAAoAoCaAAAAAAAAACAKgigAQAAAAAAAACq4CGEAAAAAAAAAHCBOHHiREVFRY2DJ0+erPGiOqPR&#10;GBsbq1I/BNAAAAAAAAAAcIFYuHDhgQMH6nn37IPJyckTJkxQqR9GcAAAAAAAAAAAVMEOaAAAAAAA&#10;AAC4QIwYMaLWERyevc8jRoyIiYmp8a7RaFSvHwJoAAAAAAAAALhA1D/NOSYmJiUl5bw1IxjBAQAA&#10;AAAAAABQCQE0AAAAAAAAAEAVBNAAAAAAAAAAAFUQQAMAAAAAAAAAVEEADQAAAAAAAABQhdbXDQAA&#10;AAAAAAAAVGQ0GpOTkz0vzvOlJUVRzvMlAQAAgGYqIyMjPT3d110AAAAAzQYjOAAAAAAAAAAAqiCA&#10;BgAAAAAAAACoggAaAAAAAAAAAKAKAmgAAAAAAAAAgCoIoAEAAAAAAAAAqiCABgAAAAAAAACoggAa&#10;AAAAAAAAAKAKAmgAAAAAAAAAgCoIoAEAAAAAAAAAqiCABgAAAAAAAACoggAaAAAAAAAAAKAKAmgA&#10;AAAAAAAAgCoIoAEAAAAAAAAAqiCABgAAAAAAAACoggAaAAAAAAAAAKAKAmgAAAAAAAAAgCoIoAEA&#10;AAAAAAAAqiCABgAAAAAAAACoggAaAAAAAAAAAKAKAmgAAAAAAAAAgCoIoAEAAAAAAAAAqiCABgAA&#10;AAAAAACoggAaAAAAAAAAAKAKAmgAAAAAAAAAgCoIoAEAAAAAAAAAqiCABgAAAAAAAACoggAaAAAA&#10;AAAAAKAKAmgAAAAAAAAAgCoIoAEAAAAAAAAAqiCABgAAAAAAAACoggAaAAAAAAAAAKAKAmgAAAAA&#10;AAAAgCoIoAEAAAAAAAAAqiCABgAAAAAAAACoggAaAAAAAAAAAKAKAmgAAAAAAAAAgCoIoAEAAAAA&#10;AAAAqiCABgAAAAAAAACoggAaAAAAAAAAAKAKAmgAAAAAAAAAgCoIoAEAAAAAAAAAqiCABgAAAAAA&#10;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&#10;/D+F2M33yoQJewAAAABJRU5ErkJggg==&#10;"
52 id="image1"
53 x="0"
54 y="0" />
55 </g>
56 <g
57 inkscape:groupmode="layer"
58 id="layer1"
59 inkscape:label="Annotations"
60 transform="translate(-461.15282,-418.07992)">
61 <g
62 id="g2"
63 transform="translate(136.86058,478.49221)">
64 <rect
65 style="fill:#038a99;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
66 id="rect1"
67 width="80"
68 height="80"
69 x="904.29224"
70 y="614.58771"
71 rx="6.4000001"
72 ry="6.4000001" />
73 <text
74 xml:space="preserve"
75 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#f9f9f9;fill-opacity:1;stroke:none"
76 x="944.27759"
77 y="676.00372"
78 id="text1"><tspan
79 sodipodi:role="line"
80 id="tspan1"
81 x="944.27759"
82 y="676.00372"
83 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle">1</tspan></text>
84 </g>
85 <g
86 id="g4"
87 transform="translate(0,-10)">
88 <path
89 id="rect1-7"
90 style="fill:#038a99;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
91 d="m 1107.5532,538.07992 c -3.5456,0 -6.4004,2.85479 -6.4004,6.40039 v 6.38867 l -24,13.85547 24,13.85742 v 33.09766 c 0,3.5456 2.8548,6.40039 6.4004,6.40039 h 67.1992 c 3.5456,0 6.4004,-2.85479 6.4004,-6.40039 v -67.19922 c 0,-3.5456 -2.8548,-6.40039 -6.4004,-6.40039 z" />
92 <text
93 xml:space="preserve"
94 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#f9f9f9;fill-opacity:1;stroke:none"
95 x="1141.1382"
96 y="599.49591"
97 id="text1-0"><tspan
98 sodipodi:role="line"
99 id="tspan1-9"
100 x="1141.1382"
101 y="599.49591"
102 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle">2</tspan></text>
103 </g>
104 <g
105 id="g4-2"
106 transform="translate(419.00002,-4)">
107 <path
108 id="rect1-7-6"
109 style="fill:#038a99;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
110 d="m 1107.5532,538.07992 c -3.5456,0 -6.4004,2.85479 -6.4004,6.40039 v 6.38867 l -24,13.85547 24,13.85742 v 33.09766 c 0,3.5456 2.8548,6.40039 6.4004,6.40039 h 67.1992 c 3.5456,0 6.4004,-2.85479 6.4004,-6.40039 v -67.19922 c 0,-3.5456 -2.8548,-6.40039 -6.4004,-6.40039 z" />
111 <text
112 xml:space="preserve"
113 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#f9f9f9;fill-opacity:1;stroke:none"
114 x="1141.1382"
115 y="599.49591"
116 id="text1-0-1"><tspan
117 sodipodi:role="line"
118 id="tspan1-9-8"
119 x="1141.1382"
120 y="599.49591"
121 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle">4</tspan></text>
122 </g>
123 <g
124 id="g4-2-4"
125 transform="translate(549.00002,-95)">
126 <path
127 id="rect1-7-6-5"
128 style="fill:#038a99;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
129 d="m 1107.5532,538.07992 c -3.5456,0 -6.4004,2.85479 -6.4004,6.40039 v 6.38867 l -24,13.85547 24,13.85742 v 33.09766 c 0,3.5456 2.8548,6.40039 6.4004,6.40039 h 67.1992 c 3.5456,0 6.4004,-2.85479 6.4004,-6.40039 v -67.19922 c 0,-3.5456 -2.8548,-6.40039 -6.4004,-6.40039 z" />
130 <text
131 xml:space="preserve"
132 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#f9f9f9;fill-opacity:1;stroke:none"
133 x="1141.1382"
134 y="599.49591"
135 id="text1-0-1-0"><tspan
136 sodipodi:role="line"
137 id="tspan1-9-8-3"
138 x="1141.1382"
139 y="599.49591"
140 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle">7</tspan></text>
141 </g>
142 <g
143 id="g5"
144 transform="translate(-13.99998,6)">
145 <path
146 id="rect1-7-6-3-9"
147 style="fill:#038a99;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
148 d="m 2293.7524,528.07992 c 3.5456,0 6.4004,2.85479 6.4004,6.40039 v 6.38867 l 24,13.85547 -24,13.85742 v 33.09766 c 0,3.5456 -2.8548,6.40039 -6.4004,6.40039 h -67.1992 c -3.5456,0 -6.4004,-2.85479 -6.4004,-6.40039 v -67.19922 c 0,-3.5456 2.8548,-6.40039 6.4004,-6.40039 z" />
149 <text
150 xml:space="preserve"
151 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#f9f9f9;fill-opacity:1;stroke:none"
152 x="2260.1382"
153 y="589.49591"
154 id="text1-0-1-7"><tspan
155 sodipodi:role="line"
156 id="tspan1-9-8-5"
157 x="2260.1382"
158 y="589.49591"
159 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle">5</tspan></text>
160 </g>
161 <g
162 id="g6"
163 transform="translate(-82.508524,-188)">
164 <path
165 id="rect1-7-6-3-9-2"
166 style="fill:#038a99;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
167 d="m 2256.6693,716.48032 c 0,-3.5456 -2.8548,-6.4004 -6.4004,-6.4004 h -6.3887 l -13.8554,-24 -13.8574,24 h -33.0977 c -3.5456,0 -6.4004,2.8548 -6.4004,6.4004 v 67.1992 c 0,3.5456 2.8548,6.4004 6.4004,6.4004 h 67.1992 c 3.5456,0 6.4004,-2.8548 6.4004,-6.4004 z" />
168 <text
169 xml:space="preserve"
170 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#f9f9f9;fill-opacity:1;stroke:none"
171 x="2216.6548"
172 y="771.49591"
173 id="text1-0-1-7-5"><tspan
174 sodipodi:role="line"
175 id="tspan1-9-8-5-69"
176 x="2216.6548"
177 y="771.49591"
178 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle">8</tspan></text>
179 </g>
180 <g
181 id="g5-2"
182 transform="translate(-13.99998,867.6627)">
183 <path
184 id="rect1-7-6-3-9-9"
185 style="fill:#038a99;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
186 d="m 2293.7524,528.07992 c 3.5456,0 6.4004,2.85479 6.4004,6.40039 v 6.38867 l 24,13.85547 -24,13.85742 v 33.09766 c 0,3.5456 -2.8548,6.40039 -6.4004,6.40039 h -67.1992 c -3.5456,0 -6.4004,-2.85479 -6.4004,-6.40039 v -67.19922 c 0,-3.5456 2.8548,-6.40039 6.4004,-6.40039 z" />
187 <text
188 xml:space="preserve"
189 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#f9f9f9;fill-opacity:1;stroke:none"
190 x="2260.1382"
191 y="589.49591"
192 id="text1-0-1-7-3"><tspan
193 sodipodi:role="line"
194 id="tspan1-9-8-5-1"
195 x="2260.1382"
196 y="589.49591"
197 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle">6</tspan></text>
198 </g>
199 <g
200 id="g3"
201 transform="translate(47.332508)">
202 <rect
203 style="fill:#038a99;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-miterlimit:1.45;paint-order:stroke fill markers"
204 id="rect1-3"
205 width="80"
206 height="80"
207 x="2063.8203"
208 y="918.0799"
209 rx="6.4000001"
210 ry="6.4000001" />
211 <text
212 xml:space="preserve"
213 style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:60px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:#f9f9f9;fill-opacity:1;stroke:none"
214 x="2103.8057"
215 y="979.49591"
216 id="text1-5"><tspan
217 sodipodi:role="line"
218 id="tspan1-6"
219 x="2103.8057"
220 y="979.49591"
221 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle">3</tspan></text>
222 </g>
223 </g>
224</svg>
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.svg.license b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/initialModelLight.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/metamodel.svg b/subprojects/docs/src/docs/learn/tutorials/file-system/metamodel.svg
new file mode 100644
index 00000000..0cf39cd3
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/metamodel.svg
@@ -0,0 +1,132 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="202pt" height="358pt" viewBox="-6 -6 214.1699981689453 370" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-3QBf1eGyrSuIh9K81Q93C"><style>.refinery-3QBf1eGyrSuIh9K81Q93C .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-3QBf1eGyrSuIh9K81Q93C .node .node-outline{stroke:#19202b;}.refinery-3QBf1eGyrSuIh9K81Q93C .node .node-header{fill:rgb(53, 161, 173);}.refinery-3QBf1eGyrSuIh9K81Q93C .node .node-bg{fill:#fff;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-h .node-header{fill:#e06c75;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-i .node-header{fill:#98c379;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-j .node-header{fill:#c678dd;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-n .node-header{fill:#abcc94;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-3QBf1eGyrSuIh9K81Q93C .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-3QBf1eGyrSuIh9K81Q93C .edge .edge-line{stroke:#19202b;}.refinery-3QBf1eGyrSuIh9K81Q93C .edge .edge-arrow{fill:#19202b;}.refinery-3QBf1eGyrSuIh9K81Q93C .edge-UNKNOWN text{fill:#696c77;}.refinery-3QBf1eGyrSuIh9K81Q93C .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-3QBf1eGyrSuIh9K81Q93C .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-3QBf1eGyrSuIh9K81Q93C .edge-ERROR text{fill:#ca1243;}.refinery-3QBf1eGyrSuIh9K81Q93C .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-3QBf1eGyrSuIh9K81Q93C .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-3QBf1eGyrSuIh9K81Q93C .icon-TRUE{fill:#19202b;}.refinery-3QBf1eGyrSuIh9K81Q93C .icon-UNKNOWN{fill:#696c77;}.refinery-3QBf1eGyrSuIh9K81Q93C .icon-ERROR{fill:#ca1243;}.refinery-3QBf1eGyrSuIh9K81Q93C text.label-UNKNOWN{fill:#696c77;}.refinery-3QBf1eGyrSuIh9K81Q93C text.label-ERROR{fill:#ca1243;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-exists-FALSE text:not(.label-ERROR){fill:#696c77;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-exists-FALSE .node-outline{stroke:#696c77;stroke-dasharray:2 4;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-exists-FALSE .node-header{fill:#fff;}.refinery-3QBf1eGyrSuIh9K81Q93C .node-exists-FALSE .icon-TRUE{fill:#696c77;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C text.label-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-exists-FALSE text:not(.label-ERROR){fill:#abb2bf;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-exists-FALSE .node-outline{stroke:#abb2bf;stroke-dasharray:2 4;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-exists-FALSE .node-header{fill:#282c34;}[data-theme="dark"] .refinery-3QBf1eGyrSuIh9K81Q93C .node-exists-FALSE .icon-TRUE{fill:#abb2bf;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-3QBf1eGyrSuIh9K81Q93C-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-3QBf1eGyrSuIh9K81Q93C-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-3QBf1eGyrSuIh9K81Q93C-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="scale(1 1) rotate(0) translate(4 354)">
4<!-- n0 -->
5<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-g"><rect stroke="none" x="29.5" y="-344.5" width="99" height="49" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
6
7<rect stroke="none" x="24.28" y="-350" width="98.44" height="48.80000000000001" rx="12" ry="12" class="node-bg"/>
8<rect stroke="none" x="20" y="-354" width="106" height="27" clip-path="url(#refinery-3QBf1eGyrSuIh9K81Q93C-clip-0)" class="node-header"/>
9<text text-anchor="start" x="29.28" y="-334.2" font-size="12.00">Filesystem::new</text>
10<use x="30.2793" y="-320.40000000000003" width="12" height="12" href="#refinery-3QBf1eGyrSuIh9K81Q93C-icon-TRUE" class="icon icon-TRUE"/>
11<g><text text-anchor="start" x="46.28" y="-310.8" font-size="12.00" class="label label-TRUE">Filesystem</text>
12</g>
13<polyline points="24.28,-326.6 122.72,-326.6" class="node-outline"/>
14<rect fill="none" x="24.28" y="-350" width="98.44" height="48.80000000000001" rx="12" ry="12" class="node-outline"/>
15<clipPath id="refinery-3QBf1eGyrSuIh9K81Q93C-clip-0"><rect stroke="none" x="24.28" y="-350" width="98.44" height="48.80000000000001" rx="12" ry="12" class="node-bg"/></clipPath></g>
16<!-- n1 -->
17<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-n"><rect stroke="none" x="42.5" y="-259.5" width="74" height="65" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
18
19<rect stroke="none" x="37" y="-265.2" width="73" height="64.39999999999998" rx="12" ry="12" class="node-bg"/>
20<rect stroke="none" x="33" y="-269" width="81" height="27" clip-path="url(#refinery-3QBf1eGyrSuIh9K81Q93C-clip-1)" class="node-header"/>
21<text text-anchor="start" x="50.25" y="-249.4" font-size="12.00">Dir::new</text>
22<use x="43" y="-235.8" width="12" height="12" href="#refinery-3QBf1eGyrSuIh9K81Q93C-icon-TRUE" class="icon icon-TRUE"/>
23<g><text text-anchor="start" x="58.74" y="-227" font-style="italic" font-size="12.00" class="label label-TRUE">FSObject</text>
24</g>
25<use x="43" y="-219.8" width="12" height="12" href="#refinery-3QBf1eGyrSuIh9K81Q93C-icon-TRUE" class="icon icon-TRUE"/>
26<g><text text-anchor="start" x="59" y="-210" font-size="12.00" class="label label-TRUE">Dir</text>
27</g>
28<polyline points="37,-241.8 110,-241.8" class="node-outline"/>
29<rect fill="none" x="37" y="-265.2" width="73" height="64.39999999999998" rx="12" ry="12" class="node-outline"/>
30<clipPath id="refinery-3QBf1eGyrSuIh9K81Q93C-clip-1"><rect stroke="none" x="37" y="-265.2" width="73" height="64.39999999999998" rx="12" ry="12" class="node-bg"/></clipPath></g>
31<!-- n0&#45;&gt;n1 -->
32<g class="edge edge-UNKNOWN">
33
34<path fill="none" stroke-width="2" stroke-dasharray="5,2" d="M73.5,-301.27C73.5,-293.78 73.5,-285.25 73.5,-276.82" class="edge-line"/>
35<polygon stroke-width="2" points="76.56,-276.89 73.5,-268.14 70.44,-276.89 76.56,-276.89" class="edge-line edge-arrow"/>
36<text text-anchor="start" x="51.17" y="-287.69" font-weight="bold" font-size="10.50">root</text>
37</g>
38<!-- n1&#45;&gt;n1 -->
39<g class="edge edge-UNKNOWN">
40
41<path fill="none" stroke-dasharray="5,2" d="M109.92,-241.64C120.15,-241.26 128,-238.38 128,-233 128,-229.89 125.38,-227.61 121.19,-226.18" class="edge-line"/>
42<polygon points="121.85,-222.74 111.42,-224.6 120.73,-229.65 121.85,-222.74" class="edge-line edge-arrow"/>
43<text text-anchor="middle" x="126.7" y="-244.77" font-size="10.50">parent</text>
44</g>
45<!-- n1&#45;&gt;n1 -->
46<g class="edge edge-UNKNOWN">
47
48<path fill="none" stroke-width="2" stroke-dasharray="5,2" d="M109.68,-249.7C128.74,-252.4 146,-246.84 146,-233 146,-222.08 135.25,-216.31 121.36,-215.69" class="edge-line"/>
49<polygon stroke-width="2" points="121.29,-212.63 112.71,-216.14 121.6,-218.75 121.29,-212.63" class="edge-line edge-arrow"/>
50<text text-anchor="start" x="109.74" y="-253.86" font-weight="bold" font-size="10.50">contents</text>
51</g>
52<!-- n2 -->
53<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-i"><rect stroke="none" x="5.5" y="-58.5" width="74" height="65" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
54
55<rect stroke="none" x="0" y="-64.4" width="73" height="64.4" rx="12" ry="12" class="node-bg"/>
56<rect stroke="none" x="-4" y="-68" width="81" height="27" clip-path="url(#refinery-3QBf1eGyrSuIh9K81Q93C-clip-2)" class="node-header"/>
57<text text-anchor="start" x="12.09" y="-48.6" font-size="12.00">File::new</text>
58<use x="6" y="-35" width="12" height="12" href="#refinery-3QBf1eGyrSuIh9K81Q93C-icon-TRUE" class="icon icon-TRUE"/>
59<g><text text-anchor="start" x="21.74" y="-26.2" font-style="italic" font-size="12.00" class="label label-TRUE">FSObject</text>
60</g>
61<use x="6" y="-19" width="12" height="12" href="#refinery-3QBf1eGyrSuIh9K81Q93C-icon-TRUE" class="icon icon-TRUE"/>
62<g><text text-anchor="start" x="22" y="-9.2" font-size="12.00" class="label label-TRUE">File</text>
63</g>
64<polyline points="0,-41 73,-41" class="node-outline"/>
65<rect fill="none" x="0" y="-64.4" width="73" height="64.4" rx="12" ry="12" class="node-outline"/>
66<clipPath id="refinery-3QBf1eGyrSuIh9K81Q93C-clip-2"><rect stroke="none" x="0" y="-64.4" width="73" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g>
67<!-- n1&#45;&gt;n2 -->
68<g class="edge edge-UNKNOWN">
69
70<path fill="none" stroke-width="2" stroke-dasharray="5,2" d="M62.66,-200.94C54.37,-167.34 44.16,-113.54 38.8,-75.96" class="edge-line"/>
71<polygon stroke-width="2" points="41.84,-75.63 37.64,-67.37 35.77,-76.45 41.84,-75.63" class="edge-line edge-arrow"/>
72<text text-anchor="start" x="2.11" y="-137.27" font-weight="bold" font-size="10.50">contents</text>
73</g>
74<!-- n3 -->
75<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-h"><rect stroke="none" x="79.5" y="-158.5" width="74" height="65" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
76
77<rect stroke="none" x="74" y="-164.8" width="73" height="64.4" rx="12" ry="12" class="node-bg"/>
78<rect stroke="none" x="70" y="-168" width="81" height="27" clip-path="url(#refinery-3QBf1eGyrSuIh9K81Q93C-clip-3)" class="node-header"/>
79<text text-anchor="start" x="84.13" y="-149" font-size="12.00">Link::new</text>
80<use x="80" y="-135.4" width="12" height="12" href="#refinery-3QBf1eGyrSuIh9K81Q93C-icon-TRUE" class="icon icon-TRUE"/>
81<g><text text-anchor="start" x="95.74" y="-126.6" font-style="italic" font-size="12.00" class="label label-TRUE">FSObject</text>
82</g>
83<use x="80" y="-119.4" width="12" height="12" href="#refinery-3QBf1eGyrSuIh9K81Q93C-icon-TRUE" class="icon icon-TRUE"/>
84<g><text text-anchor="start" x="96" y="-109.6" font-size="12.00" class="label label-TRUE">Link</text>
85</g>
86<polyline points="74,-141.4 147,-141.4" class="node-outline"/>
87<rect fill="none" x="74" y="-164.8" width="73" height="64.4" rx="12" ry="12" class="node-outline"/>
88<clipPath id="refinery-3QBf1eGyrSuIh9K81Q93C-clip-3"><rect stroke="none" x="74" y="-164.8" width="73" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g>
89<!-- n1&#45;&gt;n3 -->
90<g class="edge edge-UNKNOWN">
91
92<path fill="none" stroke-width="2" stroke-dasharray="5,2" d="M72.55,-200.87C74.82,-192.71 77.94,-183.79 81.51,-175.18" class="edge-line"/>
93<polygon stroke-width="2" points="84.26,-176.54 85.01,-167.3 78.66,-174.06 84.26,-176.54" class="edge-line edge-arrow"/>
94<text text-anchor="start" x="32.38" y="-186.64" font-weight="bold" font-size="10.50">contents</text>
95</g>
96<!-- n2&#45;&gt;n1 -->
97<g class="edge edge-UNKNOWN">
98
99<path fill="none" stroke-dasharray="5,2" d="M47.37,-64.37C55.69,-98.16 65.95,-152.28 71.29,-189.85" class="edge-line"/>
100<polygon points="67.78,-189.99 72.58,-199.44 74.72,-189.06 67.78,-189.99" class="edge-line edge-arrow"/>
101<text text-anchor="middle" x="45.44" y="-123.1" font-size="10.50">parent</text>
102</g>
103<!-- n3&#45;&gt;n1 -->
104<g class="edge edge-UNKNOWN">
105
106<path fill="none" stroke-dasharray="5,2" d="M98.87,-164.53C95.81,-172.67 92.45,-181.6 89.22,-190.21" class="edge-line"/>
107<polygon points="85.98,-188.86 85.74,-199.45 92.54,-191.32 85.98,-188.86" class="edge-line edge-arrow"/>
108<text text-anchor="middle" x="108.27" y="-173.44" font-size="10.50">parent</text>
109</g>
110<!-- n3&#45;&gt;n1 -->
111<g class="edge edge-UNKNOWN">
112
113<path fill="none" stroke-dasharray="5,2" d="M111.51,-164.53C109.22,-172.76 106.07,-181.79 102.46,-190.49" class="edge-line"/>
114<polygon points="99.33,-188.92 98.48,-199.48 105.73,-191.76 99.33,-188.92" class="edge-line edge-arrow"/>
115<text text-anchor="middle" x="119.98" y="-186.25" font-size="10.50">target</text>
116</g>
117<!-- n3&#45;&gt;n2 -->
118<g class="edge edge-UNKNOWN">
119
120<path fill="none" stroke-dasharray="5,2" d="M87.09,-100.47C80.54,-91.77 73.34,-82.19 66.48,-73.06" class="edge-line"/>
121<polygon points="69.48,-71.23 60.67,-65.34 63.88,-75.44 69.48,-71.23" class="edge-line edge-arrow"/>
122<text text-anchor="middle" x="58.72" y="-85.3" font-size="10.50">target</text>
123</g>
124<!-- n3&#45;&gt;n3 -->
125<g class="edge edge-UNKNOWN">
126
127<path fill="none" stroke-dasharray="5,2" d="M146.92,-151.33C157.15,-150.51 165,-144.27 165,-132.6 165,-125.49 162.08,-120.39 157.49,-117.31" class="edge-line"/>
128<polygon points="158.95,-114.11 148.36,-114.34 156.78,-120.76 158.95,-114.11" class="edge-line edge-arrow"/>
129<text text-anchor="middle" x="179.58" y="-135.09" font-size="10.50">target</text>
130</g>
131</g>
132</svg> \ No newline at end of file
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/metamodel.svg.license b/subprojects/docs/src/docs/learn/tutorials/file-system/metamodel.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/metamodel.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationDark.png b/subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationDark.png
new file mode 100644
index 00000000..18c16832
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationDark.png
Binary files differ
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationDark.png.license b/subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationDark.png.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationDark.png.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationLight.png b/subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationLight.png
new file mode 100644
index 00000000..4882c2a4
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationLight.png
Binary files differ
diff --git a/subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationLight.png.license b/subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationLight.png.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/src/docs/learn/tutorials/file-system/modelGenerationLight.png.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/src/learn/index.md b/subprojects/docs/src/learn/index.md
deleted file mode 100644
index bb28df57..00000000
--- a/subprojects/docs/src/learn/index.md
+++ /dev/null
@@ -1,11 +0,0 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4sidebar_position: 0
5---
6
7# Introduction
8
9Various software and systems engineering scenarios rely on the systematic construction of consistent graph models. However, **automatically generating a diverse set of consistent graph models** for complex domain specifications is challenging. First, the graph generation problem must be specified with mathematical precision. Moreover, graph generation is a computationally complex task, which necessitates specialized logic solvers.
10
11**Refinery is a novel open-source software framework** to automatically synthesize a diverse set of consistent domain-specific graph models. The framework offers an expressive high-level specification language using partial models to succinctly formulate a wide range of graph generation challenges. It also provides a modern cloud-based architecture for a scalable _Graph Solver as a Service,_ which uses logic reasoning rules to efficiently synthesize a diverse set of solutions to graph generation problems by partial model refinement. Applications include system-level architecture synthesis, test generation for modeling tools or traffic scenario synthesis for autonomous vehicles.
diff --git a/subprojects/docs/src/plugins/remarkImage.ts b/subprojects/docs/src/plugins/remarkImage.ts
new file mode 100644
index 00000000..49fa5305
--- /dev/null
+++ b/subprojects/docs/src/plugins/remarkImage.ts
@@ -0,0 +1,249 @@
1/*
2 * Copyright (c) 2024 The Refinery Authors
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import type { Image } from 'mdast';
8import type {
9 MdxjsEsm,
10 MdxJsxAttribute,
11 MdxJsxFlowElement,
12} from 'mdast-util-mdx';
13import type { Transformer } from 'unified';
14import type { Node } from 'unist';
15import { visit } from 'unist-util-visit';
16
17import {
18 isImport,
19 isLiteral,
20 isParent,
21 replaceChildrenRecursively,
22} from './remarkPluginUtils';
23
24function isImage(node: Node): node is Image {
25 return node.type === 'image';
26}
27
28function createImport(componentName: string, url: string): MdxjsEsm {
29 const urlString = JSON.stringify(url);
30 return {
31 type: 'mdxjsEsm',
32 value: `import ${componentName} from ${urlString}`,
33 data: {
34 estree: {
35 type: 'Program',
36 body: [
37 {
38 type: 'ImportDeclaration',
39 specifiers: [
40 {
41 type: 'ImportDefaultSpecifier',
42 local: { type: 'Identifier', name: componentName },
43 },
44 ],
45 source: {
46 type: 'Literal',
47 value: url,
48 raw: urlString,
49 },
50 },
51 ],
52 sourceType: 'module',
53 },
54 },
55 };
56}
57
58function addCommonAttributes(
59 image: Image,
60 attributes: MdxJsxAttribute[],
61): void {
62 const { alt, title } = image;
63 if (alt) {
64 attributes.push({
65 type: 'mdxJsxAttribute',
66 name: 'alt',
67 value: alt,
68 });
69 }
70 if (title) {
71 attributes.push({
72 type: 'mdxJsxAttribute',
73 name: 'title',
74 value: title,
75 });
76 }
77}
78
79function getOriginalURL(url: string) {
80 const index = url.indexOf('?');
81 if (index < 0) {
82 return url;
83 }
84 return url.substring(0, index);
85}
86
87function getResponsiveURL(url: string) {
88 const separator = url.indexOf('?') < 0 ? '?' : '&';
89 const quality = /\.png$/.test(url) ? 100 : 85;
90 return `${url}${separator}quality=${quality}&sizes[]=2640,sizes[]=1928,sizes[]=1320,sizes[]=964,sizes[]=640,sizes[]=320&placeholder=true&rl`;
91}
92
93function getExpressionAttribute(name: string, value: string): MdxJsxAttribute {
94 return {
95 type: 'mdxJsxAttribute',
96 name,
97 value: {
98 type: 'mdxJsxAttributeValueExpression',
99 value,
100 data: {
101 estree: {
102 type: 'Program',
103 body: [
104 {
105 type: 'ExpressionStatement',
106 expression: {
107 type: 'Identifier',
108 name: value,
109 },
110 },
111 ],
112 sourceType: 'module',
113 },
114 },
115 },
116 };
117}
118
119class ImageTransformer {
120 requiredImports = new Map<string, MdxjsEsm>();
121
122 transformImage(image: Image, index: number): Node[] {
123 const { url } = image;
124 if (/\.svg$/.test(url)) {
125 return this.transformSVGImage(image, index);
126 }
127 if (url.indexOf('|') >= 0) {
128 return this.transformThemedImage(image, index);
129 }
130 return this.transformResponsiveImage(image, index);
131 }
132
133 private transformSVGImage(image: Image, index: number): Node[] {
134 const { url } = image;
135 const componentName = `Image__${index}`;
136 const attributes = [getExpressionAttribute('Component', componentName)];
137 addCommonAttributes(image, attributes);
138 this.requireImport('SVGImage', '@site/src/components/ResponsiveImage/SVG');
139
140 return [
141 createImport(componentName, url),
142 {
143 type: 'mdxJsxFlowElement',
144 name: 'SVGImage',
145 attributes,
146 } as MdxJsxFlowElement,
147 ];
148 }
149
150 private transformThemedImage(image: Image, index: number): Node[] {
151 const { url } = image;
152 const [urlLight, urlDark] = url.split('|');
153 if (urlLight === undefined || urlDark === undefined) {
154 throw new Error(`Invalid themed image: ${url}`);
155 }
156 const componentNameLight = `ImageLight__${index}`;
157 const componentNameDark = `ImageDark__${index}`;
158 const originalLight = `originalImageLight__${index}`;
159 const originalDark = `originalImageDark${index}`;
160 this.requireImport(
161 'ThemedImage',
162 '@site/src/components/ResponsiveImage/Themed',
163 );
164
165 const attributes: MdxJsxAttribute[] = [
166 getExpressionAttribute('light', componentNameLight),
167 getExpressionAttribute('dark', componentNameDark),
168 getExpressionAttribute('originalLight', originalLight),
169 getExpressionAttribute('originalDark', originalDark),
170 ];
171 addCommonAttributes(image, attributes);
172
173 return [
174 createImport(componentNameLight, getResponsiveURL(urlLight)),
175 createImport(componentNameDark, getResponsiveURL(urlDark)),
176 createImport(originalLight, getOriginalURL(urlLight)),
177 createImport(originalDark, getOriginalURL(urlDark)),
178 {
179 type: 'mdxJsxFlowElement',
180 name: 'ThemedImage',
181 attributes,
182 } as MdxJsxFlowElement,
183 ];
184 }
185
186 private transformResponsiveImage(image: Image, index: number): Node[] {
187 const { url } = image;
188 const componentName = `Image__${index}`;
189 const original = `originalImage__${index}`;
190 this.requireImport(
191 'ResponsiveImage',
192 '@site/src/components/ResponsiveImage',
193 );
194
195 const attributes: MdxJsxAttribute[] = [
196 getExpressionAttribute('image', componentName),
197 getExpressionAttribute('original', original),
198 ];
199 addCommonAttributes(image, attributes);
200
201 return [
202 createImport(componentName, getResponsiveURL(url)),
203 createImport(original, getOriginalURL(url)),
204 {
205 type: 'mdxJsxFlowElement',
206 name: 'ResponsiveImage',
207 attributes,
208 } as MdxJsxFlowElement,
209 ];
210 }
211
212 private requireImport(componentName: string, url: string) {
213 if (!this.requiredImports.has(url)) {
214 this.requiredImports.set(url, createImport(componentName, url));
215 }
216 }
217}
218
219export default function remarkImage(): Transformer {
220 return (root) => {
221 let counter = 0;
222 const transformer = new ImageTransformer();
223 replaceChildrenRecursively(root, isImage, (image) => {
224 const result = transformer.transformImage(image, counter);
225 counter += 1;
226 return result;
227 });
228 const { requiredImports } = transformer;
229 const imported = new Set<string>();
230 visit(root, (node) => {
231 if (isLiteral(node)) {
232 requiredImports.forEach((_, key) => {
233 if (isImport(node, key)) {
234 imported.add(key);
235 }
236 });
237 }
238 });
239 const imports: MdxjsEsm[] = [];
240 requiredImports.forEach((node, key) => {
241 if (!imported.has(key)) {
242 imports.push(node);
243 }
244 });
245 if (isParent(root)) {
246 root.children.unshift(...imports);
247 }
248 };
249}
diff --git a/subprojects/docs/src/plugins/remarkPluginUtils.ts b/subprojects/docs/src/plugins/remarkPluginUtils.ts
new file mode 100644
index 00000000..1dabcd11
--- /dev/null
+++ b/subprojects/docs/src/plugins/remarkPluginUtils.ts
@@ -0,0 +1,58 @@
1/*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 * Copyright (c) 2024 The Refinery Authors
4 *
5 * SPDX-License-Identifier: MIT AND EPL-2.0
6 *
7 * This file is based on
8 * https://github.com/facebook/docusaurus/blob/e4ecffe41878728acff55a8370bd7440706c02f7/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts
9 */
10
11import type { Code, Literal } from 'mdast';
12import type { Node, Parent } from 'unist';
13
14export function isParent(node: Node): node is Parent {
15 return 'children' in node && Array.isArray(node.children);
16}
17
18export function replaceChildrenRecursively<T extends Node>(
19 node: Node,
20 shoulReplace: (node: Node) => node is T,
21 replacement: (node: T) => Node[],
22): boolean {
23 if (!isParent(node)) {
24 return false;
25 }
26 let didReplace = false;
27 let index = 0;
28 while (index < node.children.length) {
29 const child = node.children[index];
30 if (child !== undefined && shoulReplace(child)) {
31 const result = replacement(child);
32 node.children.splice(index, 1, ...result);
33 index += result.length;
34 didReplace = true;
35 } else {
36 if (
37 child !== undefined &&
38 replaceChildrenRecursively(child, shoulReplace, replacement)
39 ) {
40 didReplace = true;
41 }
42 index += 1;
43 }
44 }
45 return didReplace;
46}
47
48export function isCode(node: Node): node is Code {
49 return node.type === 'code';
50}
51
52export function isLiteral(node: Node): node is Literal {
53 return node.type === 'mdxjsEsm';
54}
55
56export function isImport(node: Node, importedPath: string): boolean {
57 return isLiteral(node) && node.value.includes(importedPath);
58}
diff --git a/subprojects/docs/src/plugins/remarkPosix2Windows.ts b/subprojects/docs/src/plugins/remarkPosix2Windows.ts
index 784802f2..418869f3 100644
--- a/subprojects/docs/src/plugins/remarkPosix2Windows.ts
+++ b/subprojects/docs/src/plugins/remarkPosix2Windows.ts
@@ -2,33 +2,27 @@
2 * Copyright (c) Facebook, Inc. and its affiliates. 2 * Copyright (c) Facebook, Inc. and its affiliates.
3 * Copyright (c) 2024 The Refinery Authors 3 * Copyright (c) 2024 The Refinery Authors
4 * 4 *
5 * SPDX-License-Identifier: EPL-2.0 5 * SPDX-License-Identifier: MIT AND EPL-2.0
6 * 6 *
7 * This file is based on 7 * This file is based on
8 * https://github.com/facebook/docusaurus/blob/e4ecffe41878728acff55a8370bd7440706c02f7/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts 8 * https://github.com/facebook/docusaurus/blob/e4ecffe41878728acff55a8370bd7440706c02f7/packages/docusaurus-remark-plugin-npm2yarn/src/index.ts
9 * but was changed to conver shell commands to POSIX to Windows syntax. 9 * but was changed to convert shell commands to POSIX to Windows syntax.
10 */ 10 */
11 11
12import type { Code, Literal } from 'mdast'; 12import type { Code } from 'mdast';
13import type { MdxjsEsm, MdxJsxFlowElement } from 'mdast-util-mdx'; 13import type { MdxjsEsm, MdxJsxFlowElement } from 'mdast-util-mdx';
14import type { Transformer } from 'unified'; 14import type { Transformer } from 'unified';
15import type { Node, Parent } from 'unist'; 15import type { Node } from 'unist';
16import { visit } from 'unist-util-visit';
17 16
18function isLiteral(node: Node): node is Literal { 17import {
19 return node.type === 'mdxjsEsm'; 18 isCode,
20} 19 isImport,
20 isParent,
21 replaceChildrenRecursively,
22} from './remarkPluginUtils';
21 23
22function isTabImport(node: Node): boolean { 24function isTabImport(node: Node): boolean {
23 return isLiteral(node) && node.value.includes('@theme/Tabs'); 25 return isImport(node, '@theme/Tabs');
24}
25
26function isParent(node: Node): node is Parent {
27 return 'children' in node && Array.isArray(node.children);
28}
29
30function isCode(node: Node): node is Code {
31 return node.type === 'code';
32} 26}
33 27
34function isPosix2Windows(node: Node): node is Code { 28function isPosix2Windows(node: Node): node is Code {
@@ -137,27 +131,17 @@ function createImportNode(): MdxjsEsm {
137 131
138export default function remarkPosix2Windows(): Transformer { 132export default function remarkPosix2Windows(): Transformer {
139 return (root) => { 133 return (root) => {
140 let transformed = false;
141 let alreadyImported = false; 134 let alreadyImported = false;
142 visit(root, (node) => { 135 const transformed = replaceChildrenRecursively(
143 if (isTabImport(node)) { 136 root,
144 alreadyImported = true; 137 (node) => {
145 } 138 if (isTabImport(node)) {
146 if (isParent(node)) { 139 alreadyImported = true;
147 let index = 0;
148 while (index < node.children.length) {
149 const child = node.children[index];
150 if (child !== undefined && isPosix2Windows(child)) {
151 const result = transformNode(child);
152 node.children.splice(index, 1, ...result);
153 index += result.length;
154 transformed = true;
155 } else {
156 index += 1;
157 }
158 } 140 }
159 } 141 return isPosix2Windows(node);
160 }); 142 },
143 transformNode,
144 );
161 if (transformed && !alreadyImported) { 145 if (transformed && !alreadyImported) {
162 if (isParent(root)) { 146 if (isParent(root)) {
163 root.children.unshift(createImportNode()); 147 root.children.unshift(createImportNode());
diff --git a/subprojects/docs/src/plugins/remarkRefinery.ts b/subprojects/docs/src/plugins/remarkRefinery.ts
new file mode 100644
index 00000000..c8668dc7
--- /dev/null
+++ b/subprojects/docs/src/plugins/remarkRefinery.ts
@@ -0,0 +1,164 @@
1/*
2 * Copyright (c) 2024 The Refinery Authors
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import { Zstd } from '@hpcc-js/wasm-zstd';
8import type { Code } from 'mdast';
9import type { MdxjsEsm, MdxJsxFlowElement } from 'mdast-util-mdx';
10import type { Transformer } from 'unified';
11import type { Node } from 'unist';
12
13import {
14 isCode,
15 isImport,
16 isParent,
17 replaceChildrenRecursively,
18} from './remarkPluginUtils';
19
20const componentName = 'TryInRefinery';
21const componentPath = `@site/src/components/${componentName}`;
22
23function isTryInRefineryImport(node: Node): boolean {
24 return isImport(node, componentPath);
25}
26
27function createImportNode(): MdxjsEsm {
28 const componentPathString = JSON.stringify(componentPath);
29 return {
30 type: 'mdxjsEsm',
31 value: `import ${componentName} from ${componentPathString}`,
32 data: {
33 estree: {
34 type: 'Program',
35 body: [
36 {
37 type: 'ImportDeclaration',
38 specifiers: [
39 {
40 type: 'ImportDefaultSpecifier',
41 local: { type: 'Identifier', name: componentName },
42 },
43 ],
44 source: {
45 type: 'Literal',
46 value: componentPath,
47 raw: componentPathString,
48 },
49 },
50 ],
51 sourceType: 'module',
52 },
53 },
54 };
55}
56
57function isRefineryCode(node: Node): node is Code {
58 return isCode(node) && node.lang === 'refinery';
59}
60
61class LiterateTransformer {
62 needsImport = false;
63
64 private saved = new Map<string, string>();
65
66 private last: string | undefined;
67
68 constructor(private readonly zstd: Zstd) {}
69
70 transform(code: Code): Node[] {
71 const { meta } = code;
72 if (meta === undefined || meta === null) {
73 return [code];
74 }
75 let value = `${code.value.trim()}\n`;
76
77 const continueMatch = meta.match(/\bcontinue(?:=(\w+))?\b/);
78 if (continueMatch !== null) {
79 let prefix: string;
80 const continueID = continueMatch[1];
81 if (continueID === undefined) {
82 if (this.last === undefined) {
83 throw new Error('No code block to continue');
84 }
85 prefix = this.last;
86 } else {
87 const savedPrefix = this.saved.get(continueID);
88 if (savedPrefix === undefined) {
89 throw new Error(
90 `Checkpoint to continue '${continueID}' was not found`,
91 );
92 }
93 prefix = savedPrefix;
94 }
95 value = `${prefix}\n${value}`;
96 }
97
98 this.last = value;
99
100 const checkpointMatch = meta.match(/\bcheckpoint=(\w+)\b/);
101 if (checkpointMatch !== null && checkpointMatch[1] !== undefined) {
102 if (this.saved.has(checkpointMatch[1])) {
103 throw new Error(`Duplicate checkpoint ID ${checkpointMatch[1]}`);
104 }
105 this.saved.set(checkpointMatch[1], value);
106 }
107
108 const result: Node[] = [];
109
110 if (!/\bhidden\b/.test(meta)) {
111 result.push(code);
112 }
113
114 if (/\btry\b/.test(meta)) {
115 this.needsImport = true;
116 result.push({
117 type: 'mdxJsxFlowElement',
118 name: componentName,
119 attributes: [
120 {
121 type: 'mdxJsxAttribute',
122 name: 'href',
123 value: this.compressURL(value),
124 },
125 ],
126 } as MdxJsxFlowElement);
127 }
128
129 return result;
130 }
131
132 private compressURL(value: string): string {
133 const encoder = new TextEncoder();
134 const encodedBuffer = encoder.encode(value);
135 const compressedBuffer = this.zstd.compress(encodedBuffer, 20);
136 const base64 = Buffer.from(compressedBuffer).toString('base64url');
137 return `https://refinery.services/#/1/${base64}`;
138 }
139}
140
141export default async function loadRemarkRefineryPlugin(): Promise<
142 () => Transformer
143> {
144 const zstd = await Zstd.load();
145 return () => (root) => {
146 const transformer = new LiterateTransformer(zstd);
147 let alreadyImported = false;
148 replaceChildrenRecursively(
149 root,
150 (node) => {
151 if (isTryInRefineryImport(node)) {
152 alreadyImported = true;
153 }
154 return isRefineryCode(node);
155 },
156 (node) => transformer.transform(node),
157 );
158 if (transformer.needsImport && !alreadyImported) {
159 if (isParent(root)) {
160 root.children.unshift(createImportNode());
161 }
162 }
163 };
164}
diff --git a/subprojects/docs/src/plugins/remarkReplaceVariables.ts b/subprojects/docs/src/plugins/remarkReplaceVariables.ts
new file mode 100644
index 00000000..5c0ae725
--- /dev/null
+++ b/subprojects/docs/src/plugins/remarkReplaceVariables.ts
@@ -0,0 +1,49 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import type { PropertiesFile } from 'java-properties';
8import type { Transformer } from 'unified';
9import { visit } from 'unist-util-visit';
10
11const TEMPLATE_REGEXP = /@@@([a-zA-Z\d._-]*)@@@/g;
12
13export default function remarkReplaceVariables({
14 properties,
15}: {
16 properties: PropertiesFile;
17}): Transformer {
18 if (properties === undefined) {
19 throw new Error('propertiesPath is required');
20 }
21
22 function substitution(substring: string, name: string): string {
23 if (name === '') {
24 // Escape sequence.
25 return '@@@';
26 }
27 const value = properties.get(name);
28 if (value !== undefined) {
29 return String(value);
30 }
31 return substring;
32 }
33
34 return (root) => {
35 visit(root, (node) => {
36 if (!('value' in node)) {
37 return;
38 }
39 const { value } = node;
40 if (typeof value !== 'string') {
41 return;
42 }
43 /* eslint-disable-next-line no-param-reassign --
44 * Here we are transforming the mdast `node` in-place.
45 */
46 node.value = value.replace(TEMPLATE_REGEXP, substitution);
47 });
48 };
49}
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/commands.md b/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/commands.md
new file mode 100644
index 00000000..7ffe2a6c
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/commands.md
@@ -0,0 +1,158 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4sidebar_position: 1
5title: Build commands
6---
7
8# Building from the command line
9
10## Gradle commands
11
12We use [Gradle](https://gradle.org/) to manage the compilation and tests of Refinery.
13
14Java code is built directly by Gradle.
15We use the [frontend-gradle-plugin](https://siouan.github.io/frontend-gradle-plugin/) to manage a [Node.js](https://nodejs.org/en) and [Yarn](https://yarnpkg.com/) installation, which in turn is used to build TypeScript code (including this documentation website).
16Typically, Yarn commands are issued by Gradle and you don't need to work with the TypeScript build system directly if you're only working on the Java parts of Refinery.
17
18### `build`
19
20```bash posix2windows
21./gradlew build
22```
23
24Compile all code, run all tests, and produce all build artifacts.
25
26You should run this command before submitting a [Pull request](https://github.com/graphs4value/refinery/pulls) to make sure that all code builds and tests pass on your local machine.
27This will also be run by GitHub Actions for each commit or pull requests.
28
29### `publishToMavenLocal`
30
31```bash posix2windows
32./gradlew publishToMavenLocal
33```
34
35Publishes the Refinery Java artifacts to the [Maven local repository](https://www.baeldung.com/maven-local-repository).
36
37Build tools, such as Gradle, will be able to consume such artifacts, which enables you to use the latest version of Refinery -- possibly including your own modifications -- in other Java projects.
38For more information, see our [programming guide](/snapshot/develop/java).
39
40### `serve`
41
42```bash posix2windows
43./gradlew serve
44```
45
46Starts the Refinery backend and web interface on port 1312.
47
48This task is ideal for running the Refinery backend if you don't intend to work on the frontend.
49The Refinery frontend TypeScript projects is automatically built before the server starts.
50The server will use the latest build output of the frontend as static assets.
51
52The behavior of this task is influenced by the same [environmental variables](../../../learn/docker#environmental-variables) as the Refinery [Docker container](../../../learn/docker).
53However, the default value of `REFINERY_LISTEN_PORT` is `1312`.
54
55### `serveBackend`
56
57```bash posix2windows
58./gradlew serveBackend
59```
60
61Starts the Refinery backend on port 1312.
62
63This task is ideal for running the Refinery backend if you're working on the frontend.
64No static assets will be build.
65You'll need to use [`yarnw frontend dev`](#frontend-dev)
66
67Like [`./gradlew serve`](#serve), the behavior of this task is influenced by the same [environmental variables](../../../learn/docker#environmental-variables) as the Refinery [Docker container](../../../learn/docker).
68However, the default value of `REFINERY_LISTEN_PORT` is `1312`.
69
70## Yarn commands
71
72We provide a `yarnw` wrapper script to invoke the Yarn distribution installed by frontend-gradle-plugin directly.
73The following commands can only be run once [`./gradlew build`](#build) has installed the necessary Node.js and Yarn packages.
74
75### `docs dev`
76
77```bash posix2windows
78./yarnw docs dev
79```
80
81Builds and serves this documentation in development mode on port 3000.
82Saved changes to most documentation sources are immediately reflected in the browse without reloading.
83
84You can set the port with the `-p` option, e.g. to use port 1313, use
85
86```bash posix2windows
87./yarnw docs dev -p 1313
88```
89
90:::note
91
92Running this command for the first time may generate error messages like
93```
94ERROR failed to read input source map: failed to parse inline source map url
95```
96which can be safely ignored.
97
98:::
99
100### `frontend dev`
101
102```bash posix2windows
103./yarnw frontend dev
104```
105
106Builds and serves the refinery frontend on port 1313.
107Saved changes to most source files are immediately reflected in the browser without reload.
108
109Before running this command, you need to start [`./gradlew serveBackend`](#servebackend) to provide a backend for the frontend to connect to.
110The development server of the frontend will proxy all WebSocket connections to the backend.
111
112The following environmental variables influence the behavior of this command:
113
114#### `REFINERY_LISTEN_HOST`
115
116Hostname to listen at for incoming HTTP connections.
117
118**Default value:** `localhost`
119
120#### `REFINERY_LISTEN_PORT`
121
122TCP port to listen at for incoming HTTP connections.
123
124**Default value:** `1313`
125
126#### `REFINERY_BACKEND_HOST`
127
128Hostname of the Refinery backend.
129
130This should match the `REFINERY_LISTEN_HOST` passed to [`./gradlew serveBackend`](#servebackend).
131
132**Default value:** `127.0.0.1` (connect to `localhost` over IPv4 only)
133
134#### `REFINERY_LISTEN_PORT`
135
136TCP port of the Refinery backend.
137
138This should match the `REFINERY_LISTEN_PORT` passed to [`./gradlew serveBackend`](#servebackend).
139
140**Default value:** `1312`
141
142#### `REFINERY_PUBLIC_HOST`
143
144Publicly visible hostname of the Refinery instance.
145
146If you use a reverse proxy in front of the development server, you must set this variable.
147Otherwise, connections to the development server will fail due to cross-origin protection.
148
149**Default value:** equal to `REFINERY_LISTEN_HOST`
150
151#### `REFINERY_PUBLIC_PORT`
152
153Publicly visible port of the Refinery instance.
154
155If you use a reverse proxy in front of the development server, you must set this variable.
156Otherwise, connections to the development server will fail due to cross-origin protection.
157
158**Default value:** equal to `REFINERY_LISTEN_PORT`
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/ide-setup.md b/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/ide-setup.md
new file mode 100644
index 00000000..d5dd4eb5
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/ide-setup.md
@@ -0,0 +1,96 @@
1---
2SPDX-FileCopyrightText: 2021-2023 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4sidebar_position: 2
5title: IDE setup
6---
7
8# Setting up the development environment
9
10## IntelliJ IDEA
11
12We prefer [IntelliJ IDEA](https://www.jetbrains.com/idea/) as a Java development environment.
13No special preparations should be necessary for importing the project as a Gradle project into IDEA:
14
151. See the [required tools](/develop/contributing#required-tools) for compiling Refinery on obtaining the required JDK version. You'll also need a version of IntelliJ IDEA that supports **Java 21** (version **2023.3** or later).
16
172. Clone the project git repository and open it in IntelliJ IDEA. Make sure to _open_ the project instead of creating a _new_ one in the same directory.
18
193. IntelliJ IDEA should build and index the project. If there are errors, it is likely that the `JAVA_HOME` was incorrectly set:
20 * In _Project Structure > Project settings > Project > SDK_, a Java 21 compatible JDK should be selected.
21 * In _Project Structure > Project settings > Project > Language level_, either _SDK default_ or _21_ should be selected.
22 * Make sure that each module in _Project Structure > Project settings > Module_ uses the _Project default_ language level in _Sources > Language level_ and the _Project SDK_ in _Dependencies > Module SDK._
23 * In _Settings > Gradle settings > Gradle Projects > Gradle_, the _Distribution_ should be set to _Wrapper_ and the _Gradle JVM_ should be set to _Project SDK._
24
254. We recommend installing the latest _SonarLint_ plugin in _Settings > Plugins_ to get real-time code quality analysis in your IDE.
26
27:::note
28
29You'll need [Eclipse](#eclipse) to edit Xtext (`*.xtext`) and MWE2 (`*.mwe2`) files and Ecore class diagrams (`*.aird`, `*.ecore`, `*.genmodel`).
30If you do not plan on making changes to such files, feel free to skip the Eclipse installation steps below.
31
32You'll also need [VS Code](#vs-code) to edit the TypeScript code in Refinery.
33
34:::
35
36## Eclipse
37
381. See the [required tools](/develop/contributing#required-tools) for compiling Refinery on obtaining the required JDK version.
39
402. Download and extract the [Eclipse IDE for Java and DSL Developers 2023-12](https://www.eclipse.org/downloads/packages/release/2023-12/r/eclipse-ide-java-and-dsl-developers) package.
41
423. Launch Eclipse and create a new workspace.
43
444. Open _Help > Eclipse Marketplace_ and install the following software:
45 * _EclEmma Java Code Coverage_
46 * _EcoreTools : Ecore Diagram Editor_
47 * _Sirius_ (ignore the warning during installation about the solution _Sirius_ not being available)
48 * _SonarLint_
49
505. Open _Window > Preferences_ and set the following preferences:
51 * _General > Workspace > Text file encoding_ should be _UTF-8_.
52 * _General > Workspace > New text file line delimiter_ should be _Unix_.
53 * Add the JDK 21 to _Java > Installed JREs_.
54 * Make sure JDK 21 is selected for _JavaSE-21_ at _Java > Installed JREs > Execution Environments_.
55 * Set _Gradle > Java home_ to the `JAVA_HOME` directory (the directory which contains the `bin` directory) of JDK 21. Here, Buildship will show a yellow warning sign, which can be safely ignored.
56 * Set _Java > Compiler > JDK Compliance > Compiler compliance level_ to _21_.
57
586. Clone the project Git repository but _do not_ import it into Eclipse yet.
59
607. Open a new terminal and run
61 ```bash posix2windows
62 ./gradlew prepareEclipse
63 ```
64 in the cloned repository.
65 * This should complete without any compilation errors.
66 * To troubleshoot any error, see the [instructions for compiling Refinery](/develop/contributing#compiling).
67
688. Select _File > Import... > Gradle > Existing Gradle Project_ and import the cloned repository in Eclipse.
69 * Make sure to select the root of the repository (containing this file) as the _Project root directory_ and that the _Gradle distribution_ is _Gradle wrapper_.
70 * If you have previously imported the project into Eclipse, this step will likely fail. In that case, you should remove the projects from Eclipse, run `git clean -fxd` in the repository, and start over from step 8.
71
72## VS Code
73
74We recommend [VSCodium](https://github.com/VSCodium/vscodium) or [Visual Studio Code](https://code.visualstudio.com/) to work with the parts of Refinery that are written is TypeScript.
75
761. See the [required tools](/develop/contributing#required-tools) for compiling Refinery on obtaining the required JDK version.
77
782. Install the following VS Code extensions:
79 * _EditorConfig for VS Code_ [[Open VSX](https://open-vsx.org/extension/EditorConfig/EditorConfig)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig)]
80 * _ESLint_ [[Open VSX](https://open-vsx.org/extension/dbaeumer/vscode-eslint)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)]
81 * _MDX_ [[Open VSX](https://open-vsx.org/extension/unifiedjs/vscode-mdx)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=unifiedjs.vscode-mdx)]
82 * _Prettier - Code formatter_ [[Open VSX](https://open-vsx.org/extension/esbenp/prettier-vscode)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)]
83 * _XState VSCode_ [[Open VSX](https://open-vsx.org/extension/statelyai/stately-vscode)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=statelyai.stately-vscode)]
84 * _ZipFS - a zip file system_ [[Open VSX](https://open-vsx.org/extension/arcanis/vscode-zipfs)] [[Extension Marketplace](https://marketplace.visualstudio.com/items?itemName=arcanis.vscode-zipfs)]
85
863. Clone the project Git repository but _do not_ import it into VS Code yet.
87
884. Run
89 ```bash posix2windows
90 ./gradlew installFrontend
91 ```
92 to install all required Node.js tooling.
93
945. Open the repository with _Open Folder&hellip;_ in VS Code.
95 * When asked, select that you _Trust_ the folder.
96 * When asked, enable using the TypeScript and ESLint tooling specified in the repository.
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/index.md b/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/index.md
new file mode 100644
index 00000000..aa0bdb2f
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/develop/contributing/index.md
@@ -0,0 +1,59 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4sidebar_position: 1
5title: Contributing
6---
7
8import TabItem from '@theme/TabItem';
9import Tabs from '@theme/Tabs';
10
11# Contributing to Refinery
12
13You can clone the refinery repository from GitHub at https://github.com/graphs4value/refinery.
14If you want to contribute code, we recommend [forking](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) the repository on GitHub so that you can submit a [pull request](https://github.com/graphs4value/refinery/pulls) later.
15
16## Required tools
17
18Refinery is written in Java and TypeScript. To build Refinery, you'll need a **Java 21** compatible **Java Development Kit (JDK).** We recommend the [Adoptium Java 21 JDK](https://adoptium.net/) or the [Amazon Corretto Java 21 JDK](https://aws.amazon.com/corretto/).
19
20## Compiling Refinery {#compiling}
21
22To build Refinery, run the command
23```bash posix2windows
24./gradlew build
25```
26in the cloned repository.
27
28This should complete without any compilation errors.
29
30If you get any errors about the JVM version, check whether the `JAVA_HOME` environment variable is set to the location of **JDK 21**. You can query the variable with
31<Tabs groupId="posix2windows">
32 <TabItem value="posix" label="Linux or macOS">
33 ```bash
34 echo $JAVA_HOME
35 ```
36 </TabItem>
37 <TabItem value="windows" label="Windows (PowerShell)">
38 ```bash
39 echo $Env:JAVA_HOME
40 ```
41 </TabItem>
42</Tabs>
43To set the `JAVA_HOME` environmental variable, use
44<Tabs groupId="posix2windows">
45 <TabItem value="posix" label="Linux or macOS">
46 ```bash
47 export JAVA_HOME=/java/path/here
48 ```
49 </TabItem>
50 <TabItem value="windows" label="Windows (PowerShell)">
51 ```bash
52 $Env:JAVA_HOME="C:\java\path\here"
53 ```
54 </TabItem>
55</Tabs>
56
57If the build fails with a `Host name must not be empty` error, you [might need to remove the empty proxy configuration from your global `gradle.properties` file](https://stackoverflow.com/a/62128323).
58
59For further information, see the [supported build commands](/develop/contributing/commands) and the [instructions for setting up an IDE](/develop/contributing/ide-setup).
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/develop/java.md b/subprojects/docs/versioned_docs/version-0.1.0/develop/java.md
new file mode 100644
index 00000000..26ba89f5
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/develop/java.md
@@ -0,0 +1,351 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4sidebar_position: 0
5---
6
7# Programming guide
8
9This guide is aimed at developers who wish to create Java applications that leverage Refinery as a library.
10We also recommend browsing the [Javadoc documentation](../javadoc) associated with Refinery components.
11See the [contributor's guide](../contributing) for information on building and modifying Refinery itself.
12
13:::note
14
15Refinery can run as a cloud-based [_Graph Solver as a Service_](https://refinery.services/) without local installation.
16You can also run a compiled version as a [Docker container](../../learn/docker).
17
18:::
19
20Below, you can find instructions on using [Gradle](#gradle) or [Apache Maven](#maven) to create applications that use Refinery as a Java library.
21
22## Working with Gradle {#gradle}
23
24We recommend [Gradle](https://gradle.org/) as a build system for creating Java programs that use Refinery as a library.
25We created a [Gradle plugin](pathname://../javadoc/refinery-gradle-plugins/) to simplify project configuration.
26
27To find out the configuration for using our artifacts, select whether you use a Kotlin-based (`.gradle.kts`) or a Groovy-based (`.gradle`) configuration format for your Gradle build. You should add this code to your Gradle *settings* file, which is named `settings.gradle.kts` or `settings.gradle`.
28
29import TabItem from '@theme/TabItem';
30import Tabs from '@theme/Tabs';
31
32<Tabs groupId="gradleLanguage">
33 <TabItem value="kotlin" label="Kotlin">
34 ```kotlin title="settings.gradle.kts"
35 plugins {
36 id("tools.refinery.settings") version "0.1.0"
37 }
38 ```
39 </TabItem>
40 <TabItem value="groovy" label="Groovy">
41 ```groovy title="settings.gradle"
42 plugins {
43 id 'tools.refinery.settings' version '0.1.0'
44 }
45 ```
46 </TabItem>
47</Tabs>
48
49This plugin will perform the following actions automatically:
50* Add a [version catalog](https://docs.gradle.org/current/userguide/platforms.html#sec:sharing-catalogs) to your build to enable easy access to Refinery artifacts and their [dependencies](#declaring-dependencies).
51* Lock refinery artifacts and their dependencies to a [platform](https://docs.gradle.org/current/userguide/platforms.html#sub:using-platform-to-control-transitive-deps) (Maven BOM) of tested versions.
52* Configure a logger based on [Log4J over SLF4J](https://www.slf4j.org/legacy.html) and [SLF4J Simple](https://www.slf4j.org/apidocs/org/slf4j/simple/SimpleLogger.html) that is free from vulnerabilities and works out of the box for most use-cases.
53* Generate [application](#building-applications) artifacts, if any, according to best practices used in the Refinery project.
54* Add common dependencies for writing [unit tests](#writing-tests) for your Java code.
55
56See the [multi-module projects](#multi-module-projects) section of this tutorial on how to disable some of these automated actions for a part of your build.
57
58### Declaring dependencies
59
60The Refinery Gradle plugins adds a [version catalog](https://docs.gradle.org/current/userguide/platforms.html#sec:sharing-catalogs) named `refinery` that you can use to quickly access dependencies.
61For example, to add a dependency to the [`tools.refinery:refinery-generator`](pathname://../javadoc/refinery-generator/) library, you add the following to your `build.gradle.kts` or `build.gradle` file:
62
63<Tabs groupId="gradleLanguage">
64 <TabItem value="kotlin" label="Kotlin">
65 ```kotlin title="build.gradle.kts"
66 depndencies {
67 implementation(refinery.generator)
68 }
69 ```
70 </TabItem>
71 <TabItem value="groovy" label="Groovy">
72 ```groovy title="build.gradle"
73 dependencies {
74 implementation refinery.generator
75 }
76 ```
77 </TabItem>
78</Tabs>
79
80The version catalog also contains the external dependencies used by the Refinery framework.
81For example, you may add [GSON](https://google.github.io/gson/) for JSON parsing and [JCommander](https://jcommander.org/) for command-line argument parsing as follows:
82
83<Tabs groupId="gradleLanguage">
84 <TabItem value="kotlin" label="Kotlin">
85 ```kotlin title="build.gradle.kts"
86 depndencies {
87 implementation(refinery.gson)
88 implementation(refinery.jcommander)
89 }
90 ```
91 </TabItem>
92 <TabItem value="groovy" label="Groovy">
93 ```groovy title="build.gradle"
94 dependencies {
95 implementation refinery.gson
96 implementation refinery.jcommander
97 }
98 ```
99 </TabItem>
100</Tabs>
101
102### Building applications
103
104You can use the built-in [`application`](https://docs.gradle.org/current/userguide/application_plugin.html) to build stand-alone Java applications.
105
106When developing you main application code in the `src/main/java` directory of you project, you can use the [`StandaloneRefinery`](pathname://../javadoc/refinery-generator/tools/refinery/generator/standalone/StandaloneRefinery.html) class from [`tools.refinery:refinery-generator`](pathname://../javadoc/refinery-generator/) to access Refinery generator components. See the tutorial on Xtext's [dependency injection](https://eclipse.dev/Xtext/documentation/302_configuration.html#dependency-injection) for more advanced use-cases.
107
108```java
109package org.example;
110
111import tools.refinery.generator.standalone.StandaloneRefinery;
112
113import java.io.IOException;
114
115public class ExampleMain {
116 public static void main(String[] args) throws IOException {
117 var problem = StandaloneRefinery.getProblemLoader().loadString("""
118 class Filesystem {
119 contains Directory[1] root
120 }
121
122 class File.
123
124 class Directory extends File {
125 contains Directory[] children
126 }
127
128 scope Filesystem = 1, File = 20.
129 """);
130 var generator = StandaloneRefinery.getGeneratorFactory().createGenerator(problem);
131 generator.generate();
132 var trace = generator.getProblemTrace();
133 var childrenRelation = trace.getPartialRelation("Directory::children");
134 var childrenInterpretation = generator.getPartialInterpretation(childrenRelation);
135 var cursor = childrenInterpretation.getAll();
136 while (cursor.move()) {
137 System.out.printf("%s: %s%n", cursor.getKey(), cursor.getValue());
138 }
139 }
140}
141```
142
143If you want to produce a "fat JAR" that embeds all dependencies (e.g., for invoking from the command line or from Python with a single command), you should also add the [shadow](https://github.com/Goooler/shadow) plugin.
144The recommended version of the shadow plugin is set in our [version catalog](#declaring-dependencies). You can add it to your build script as follows:
145
146<Tabs groupId="gradleLanguage">
147 <TabItem value="kotlin" label="Kotlin">
148 ```kotlin title="build.gradle.kts"
149 plugins {
150 application
151 alias(refinery.plugins.shadow)
152 }
153
154 application {
155 mainClass = "org.example.ExampleMain"
156 }
157 ```
158 </TabItem>
159 <TabItem value="groovy" label="Groovy">
160 ```groovy title="build.gradle"
161 plugins {
162 application
163 alias refinery.plugins.shadow
164 }
165
166 application {
167 mainClass 'org.example.ExampleMain'
168 }
169 ```
170 </TabItem>
171</Tabs>
172
173After building your project with `./gradlew build`, you may find the produced "fat JAR" in the `build/libs` directory.
174Its file name will be suffixed with `-all.jar`.
175In you have Java 21 installed, you'll be able to run the application with the command
176
177<Tabs groupId="posix2windows">
178 <TabItem value="posix" label="Linux or macOS">
179 ```bash
180 java -jar ./build/libs/example-0.0.0-SNAPSHOT-all.jar
181 ```
182 </TabItem>
183 <TabItem value="windows" label="Windows (PowerShell)">
184 ```bash
185 java -jar .\build\libs\example-0.0.0-SNAPSHOT-all.jar
186 ```
187 </TabItem>
188</Tabs>
189
190Be sure to replace `example-0.0.0-SNAPSHOT` with the name and version of your project.
191
192### Writing tests
193
194Our Gradle plugin automatically sets up [JUnit 5](https://junit.org/junit5/) for writing tests and [parameterized tests](https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests).
195It also sets up [Hamcrest](https://hamcrest.org/JavaHamcrest/) for writing assertions.
196You should put your test files into the `src/test/java` directory in your projects.
197You may run test with the commands `./gradlew test` or `./gradlew build`.
198
199To ensure that your tests are properly isolated, you should *not* rely on the [`StandaloneRefinery`](pathname://../javadoc/refinery-generator/tools/refinery/generator/standalone/StandaloneRefinery.html) class from [`tools.refinery:refinery-generator`](pathname://../javadoc/refinery-generator/) when accessing Refinery generator components.
200Instead, you should use Xtext's [dependency injection](https://eclipse.dev/Xtext/documentation/302_configuration.html#dependency-injection) and [unit testing](https://eclipse.dev/Xtext/documentation/103_domainmodelnextsteps.html#tutorial-unit-tests) support to instantiate the components. You'll need to add a dependency to Refinery's Xtext testing support library to your project.
201
202<Tabs groupId="gradleLanguage">
203 <TabItem value="kotlin" label="Kotlin">
204 ```kotlin title="build.gradle.kts"
205 depndencies {
206 implementation(refinery.generator)
207 // highlight-next-line
208 testImplementation(testFixtures(refinery.language))
209 }
210 ```
211 </TabItem>
212 <TabItem value="groovy" label="Groovy">
213 ```groovy title="build.gradle"
214 dependencies {
215 implementation refinery.generator
216 // highlight-next-line
217 testImplementation testFixtures(refinery.language)
218 }
219 ```
220 </TabItem>
221</Tabs>
222
223Afterwards, you can use the `@ExtendWith`, `@InjectWith`, and `@Inject` annotations to set up your unit test.
224
225```java
226package org.example;
227
228import com.google.inject.Inject;
229import org.eclipse.xtext.testing.InjectWith;
230import org.eclipse.xtext.testing.extensions.InjectionExtension;
231import org.junit.jupiter.api.Test;
232import org.junit.jupiter.api.extension.ExtendWith;
233import tools.refinery.generator.GeneratorResult;
234import tools.refinery.generator.ModelGeneratorFactory;
235import tools.refinery.generator.ProblemLoader;
236import tools.refinery.language.tests.ProblemInjectorProvider;
237
238import java.io.IOException;
239
240import static org.hamcrest.MatcherAssert.assertThat;
241import static org.hamcrest.Matchers.is;
242
243// highlight-start
244@ExtendWith(InjectionExtension.class)
245@InjectWith(ProblemInjectorProvider.class)
246// highlight-end
247class ExampleTest {
248 // highlight-start
249 @Inject
250 private ProblemLoader problemLoader;
251
252 @Inject
253 private ModelGeneratorFactory generatorFactory;
254 // highlight-end
255
256 @Test
257 void testModelGeneration() throws IOException {
258 var problem = problemLoader.loadString("""
259 class Filesystem {
260 contains Directory[1] root
261 }
262
263 class File.
264
265 class Directory extends File {
266 contains Directory[] children
267 }
268
269 scope Filesystem = 1, File = 20.
270 """);
271 var generator = generatorFactory.createGenerator(problem);
272 var result = generator.tryGenerate();
273 assertThat(result, is(GeneratorResult.SUCCESS));
274 }
275}
276```
277
278### Multi-module projects
279
280By default, the `tools.refinery.settings` plugin will apply our `tools.refinery.java` plugin to all Java projects in your build and configure them for use with Refinery. This is sufficient for single-module Java projects, and multi-module projects where all of your Java modules use Refinery.
281
282If you wish to use Refinery in only some modules in your multi-module project, you can disable this behavior by adding
283
284```ini title="gradle.properties"
285tools.refinery.gradle.auto-apply=false
286```
287
288to the `gradle.properties` file in the root directory of your project.
289
290If you use this setting, you'll need to add the `tools.refinery.java` plugin manually to any Java projects where you want to use Refinery like this:
291
292<Tabs groupId="gradleLanguage">
293 <TabItem value="kotlin" label="Kotlin">
294 ```kotlin title="build.gradle.kts"
295 plugins {
296 id("tools.refinery.java")
297 }
298 ```
299 </TabItem>
300 <TabItem value="groovy" label="Groovy">
301 ```groovy title="build.gradle"
302 plugins {
303 id 'tools.refinery.java'
304 }
305 ```
306 </TabItem>
307</Tabs>
308
309Do *not* attempt to set a `version` for this plugin, because versioning is already managed by the `tools.refinery.settings` plugin. Trying to set a version for the `tools.refinery.java` plugin separately will result in a Gradle error.
310
311## Working with Maven {#maven}
312
313You may also develop applications based on Refiney using [Apache Maven](https://maven.apache.org/) as the build system.
314Although we don't provide a Maven plugin for simplified configuration, you can still use our [platform](https://docs.gradle.org/current/userguide/platforms.html#sub:using-platform-to-control-transitive-deps) (Maven BOM) to lock the versions of Refinery and its dependencies to tested versions.
315
316You should add the following configuration to your `pom.xml` file. If you use multi-module projects, we recommend that you add this to your parent POM.
317
318```xml title="pom.xml"
319<project>
320 ...
321 <dependencyManagement>
322 <dependencies>
323 <dependency>
324 <groupId>tools.refinery</groupId>
325 <artifactId>refinery-bom</artifactId>
326 <version>0.1.0</version>
327 <type>pom</type>
328 <scope>import</scope>
329 </dependency>
330 </dependencies>
331 </dependencyManagement>
332 ...
333</project>
334```
335
336You'll be able to add dependencies to Refinery components without an explicit reference to the dependency version, since version numbers are managed by the BOM:
337
338```xml title="pom.xml"
339<project>
340 ...
341 <dependencies>
342 <dependency>
343 <groupId>tools.refinery</groupId>
344 <artifactId>refinery-generator</artifactId>
345 </dependency>
346 </dependencies>
347 ...
348</project>
349```
350
351However, since the Maven BOM doesn't offer additional configuration, you'll have to take care of tasks such as configuring logging and testing, as well as building applications yourself.
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/develop/javadoc.md b/subprojects/docs/versioned_docs/version-0.1.0/develop/javadoc.md
new file mode 100644
index 00000000..9a488bd7
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/develop/javadoc.md
@@ -0,0 +1,41 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4description: API documentation for Refinery components automatically generated by Javadoc
5sidebar_position: 998
6---
7
8# Javadoc
9
10Here you can find API documentation for Refinery components automatically generated by Javadoc. We recommend reading the [Programming guide](../java/) first to understand how to use these components.
11
12# Refinery
13
14* [`tools.refinery:refinery-generator:0.1.0`](pathname://refinery-generator/)
15* [`tools.refinery:refinery-gradle-plugins:0.1.0`](pathname://refinery-gradle-plugins/)
16* [`tools.refinery:refinery-language:0.1.0`](pathname://refinery-language/)
17* [`tools.refinery:refinery-language-ide:0.1.0`](pathname://refinery-language-ide/)
18* [`tools.refinery:refinery-language-model:0.1.0`](pathname://refinery-language-model/)
19* [`tools.refinery:refinery-language-semantics:0.1.0`](pathname://refinery-language-semantics/)
20* [`tools.refinery:refinery-logic:0.1.0`](pathname://refinery-logic/)
21* [`tools.refinery:refinery-store:0.1.0`](pathname://refinery-store/)
22* [`tools.refinery:refinery-store-dse:0.1.0`](pathname://refinery-store-dse/)
23* [`tools.refinery:refinery-store-dse-visualization:0.1.0`](pathname://refinery-store-dse-visualization/)
24* [`tools.refinery:refinery-store-query:0.1.0`](pathname://refinery-store-query/)
25* [`tools.refinery:refinery-store-query-interpreter:0.1.0`](pathname://refinery-store-query-interpreter/)
26* [`tools.refinery:refinery-store-reasoning:0.1.0`](pathname://refinery-store-reasoning/)
27* [`tools.refinery:refinery-store-reasoning-scope:0.1.0`](pathname://refinery-store-reasoning-scope/)
28* [`tools.refinery:refinery-store-reasoning-smt:0.1.0`](pathname://refinery-store-reasoning-smt/)
29
30# Interpreter
31
32:::note
33
34The _Refinery Interpreter_ is modified version of [VIATRA&trade;](https://eclipse.dev/viatra/) specifically for use in Refinery. If you're interested in learning about [VIATRA&trade;](https://eclipse.dev/viatra/), we recommend the [VIATRA&trade; documentation](https://eclipse.dev/viatra/documentation/index.html) and [source code](https://github.com/eclipse-viatra/org.eclipse.viatra) instead. Eclipse&reg;, VIATRA&trade; and &lsquo;Eclipse VIATRA&trade;&rsquo; are trademarks of Eclipse Foundation, Inc.
35
36:::
37
38* [`tools.refinery.interpreter:refinery-interpreter:0.28.1`](pathname://refinery-interpreter/)
39* [`tools.refinery.interpreter:refinery-interpreter-localsearch:0.28.1`](pathname://refinery-interpreter-localsearch/)
40* [`tools.refinery.interpreter:refinery-interpreter-rete:0.28.1`](pathname://refinery-interpreter-rete/)
41* [`tools.refinery.interpreter:refinery-interpreter-rete-recipes:0.28.1`](pathname://refinery-interpreter-rete-recipes/)
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/docker/cli.md b/subprojects/docs/versioned_docs/version-0.1.0/learn/docker/cli.md
new file mode 100644
index 00000000..325ae7e7
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/docker/cli.md
@@ -0,0 +1,145 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4sidebar_position: 1
5sidebar_label: CLI
6---
7
8# Command-line interface
9
10You can run Refinery as a command-line applications via our [Docker container](https://github.com/graphs4value/refinery/pkgs/container/refinery-cli) on either `amd64` or `arm64` machines:
11
12```shell
13docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:0.1.0
14```
15
16This will let you read input files and generate models in the current directory (`${PWD}`) of your terminal session.
17Module imports (e.g., `import some::module.` to import `some/module.refinery`) relative to the current directory are also supported.
18
19For example, to generate a model based on the file named `input.problem` in the current directory and write the results into the file named `output.refinery`, you may run the [`generate` subcommand](#generate) with
20
21```shell
22docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:0.1.0 generate -o output.refinery input.problem
23```
24
25If you want Refinery CLI to print its documentation, run
26
27```shell
28docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:0.1.0 -help
29```
30
31## The `generate` subcommand {#generate}
32
33The `generate` subcommand generates a consistent concrete model from a partial model.
34
35```shell
36docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:0.1.0 generate [options] input path
37```
38
39The `input path` should be a path to a `.problem` file relative to the current directory.
40Due to Docker containerization, paths _outside_ the current directory (e.g., `../input.problem`) are not supported.
41
42Passing `-` as the `input path` will read a partial model from the standard input.
43
44By default, the generator is _deterministic_ and always outputs the same concrete model. See the [`-random-seed`](#generate-random-seed) option to customize this behavior.
45
46See below for the list of supported `[options]`.
47
48### `-output`, `-o` {#generate-output}
49
50The output path for the generated model.
51Passing `-o -` will write the generated model to the standard output.
52
53When generating multiple models with [`-solution-number`](#generate-solution-number), the value `-` is not supported and individual solutions will be saved to numbered files.
54For example, if you pass `-o output.refinery -n 10`, solutions will be saved as `output_001.refinery`, `output_002.refinery`, ..., `output_010.refinery`.
55
56**Default value:** `-`, i.e., the solution is written to the standard output.
57
58### `-random-seed`, `-r` {#generate-random-seed}
59
60Random seed to control the behavior of model generation.
61
62The same random seed value and Refinery release will produce the same output model for an input problem.
63Models generated with different values of `-random-seed` are highly likely (but are not guaranteed) to be _substantially_ different.
64
65**Default value:** `1`
66
67### `-scope`, `-s` {#generate-scope}
68
69Add [scope constraints](../../language/logic#type-scopes) to the input problem.
70
71This option is especially useful if you want to generate models of multiple sizes from the same partial model.
72
73For example, the command
74
75```shell
76docker run --rm -it -v ${PWD}:/data ghcr.io/graphs4value/refinery-cli:0.1.0 generate -s File=20..25 input.problem
77```
78
79is equivalent to appending
80
81```refinery title="input.problem"
82scope File = 20..25.
83```
84
85to `input.problem`.
86The syntax of the argument is equivalent to the [`scope`](../../language/logic#type-scopes) declaration, but you be careful with the handling of spaces in your shell.
87Any number of `-s` arguments are supported. For example, the following argument lists are equivalent:
88
89```shell
90-scope File=20..25,Directory=3
91-s File=20..25,Directory=3
92-s File=20..25 -s Directory=3
93-s "File = 20..25, Directory = 3"
94-s "File = 20..25" -s "Directory = 3"
95```
96
97The `*` opeator also has to be quoted to avoid shell expansion:
98
99```shell
100-s "File=20..*"
101```
102
103### `-scope-override`, `-S` {#generate-scope-override}
104
105Override [scope constraints](../../language/logic#type-scopes) to the input problem.
106
107This argument is similar to [`-scope`](#generate-scope), but has higher precedence than the [`scope`](../../language/logic#type-scopes) declarations already present in the input file.
108However, you can't override `scope` declarations in modules imported in the input file using the `import` statement.
109
110For example, if we have
111
112```refinery title="input.problem"
113scope File = 20..25, Directory = 3.
114```
115
116in the input file, the arguments `-s File=10..12 input.problem` will be interpreted as
117
118```refinery
119scope File = 20..25, Directory = 3.
120scope File = 10..12.
121```
122
123which results in an _unsatisfiable_ problem. If the use `-S File=10..12 input.problem` instead, the type scope for `File` is overridden as
124
125```refinery
126scope Directory = 3.
127scope File = 10..12.
128```
129
130and model generation can proceed as requested. Since we had specified no override for `Directory`, its type scope declared in `input.problem` was preserved.
131
132Scope overrides do not override additional scopes, i.e., `-s File=20..30 -S File=10..25` is interpreted as `-S File=20..25`.
133
134### `-solution-number`, `-n` {#generate-solution-number}
135
136The number of distinct solutions to generate.
137
138Generated solutions are always different, but are frequently not _substantially_ different, i.e., the differences between generated solutions comprise only a few model elements.
139You'll likely generate substantially different models by calling the generator multiple times with different [`-random-seed`](#generate-random-seed) values instead.
140
141The generator will create [numbered output files](#generate-output) for each solution found.
142The generation is considered successful if it finds at least one solution, but may find less than the requested number of solutions if no more exist.
143In this case, there will be fewer output files than requested.
144
145**Default value:** `1`
diff --git a/subprojects/docs/src/learn/docker.md b/subprojects/docs/versioned_docs/version-0.1.0/learn/docker/index.md
index 0df87da8..5120095d 100644
--- a/subprojects/docs/src/learn/docker.md
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/docker/index.md
@@ -1,6 +1,7 @@
1--- 1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors 2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0 3SPDX-License-Identifier: EPL-2.0
4autogenerated_sidebar_hidden: true
4sidebar_position: 100 5sidebar_position: 100
5sidebar_label: Docker 6sidebar_label: Docker
6--- 7---
@@ -23,27 +24,19 @@ Installing Refinery as a Docker container can support more advanced use cases, s
23To generate larger models with a longer timeout, you can use our [Docker container](https://github.com/graphs4value/refinery/pkgs/container/refinery) on either `amd64` or `arm64` machines: 24To generate larger models with a longer timeout, you can use our [Docker container](https://github.com/graphs4value/refinery/pkgs/container/refinery) on either `amd64` or `arm64` machines:
24 25
25```shell 26```shell
26docker run --rm -it -p 8888:8888 ghcr.io/graphs4value/refinery 27docker run --rm -it -p 8888:8888 ghcr.io/graphs4value/refinery:0.1.0
27``` 28```
28 29
29Once Docker pulls and starts the container, you can navigate to http://localhost:8888 to open the model generation interface and start editing. 30Once Docker pulls and starts the container, you can navigate to http://localhost:8888 to open the model generation interface and start editing.
30 31
31Alternatively, you can follow the [instructions to set up a local development environment](/develop/contributing) and compile and run Refinery from source. 32A [command-line interface (CLI)](cli) version of Refinery is also available as a Docker container.
32
33## Updating
34
35To take advantage of the latest updates, you can simply re-pull our Docker container from the GitHub Container Registry:
36 33
37```shell 34Alternatively, you can follow the [instructions to set up a local development environment](/develop/contributing) and compile and run Refinery from source.
38docker pull ghcr.io/graphs4value/refinery
39```
40
41Restart the container to make sure that you're running the last pulled version.
42 35
43## Environmental variables 36## Environmental variables
44 37
45The Docker container supports the following environmental variables to customize its behavior. 38The Docker container supports the following environmental variables to customize its behavior.
46Customizing these variable should only be needed if you want to _increase resource limits_ or _expose you Refinery instance over the network_ for others. 39Customizing these variables should only be needed if you want to _increase resource limits_ or _expose your Refinery instance over the network_ for others.
47 40
48Notes for **local-only instances** are highlighted with the :arrow_right: arrow emoji. 41Notes for **local-only instances** are highlighted with the :arrow_right: arrow emoji.
49 42
@@ -127,21 +120,20 @@ Timeout for model generation in seconds.
127 120
128### Threading 121### Threading
129 122
130:warning: Excessively large values may overload the server. Make sure that _all_ Refinery threads can run at the same time to avoid thread starvation. 123:arrow_right: If you only run a single model generation task at a time, you don't need to adjust these settings.
124
125:warning: Excessively large thread counts may overload the server. Make sure that _all_ Refinery threads can run at the same time to avoid thread starvation.
131 126
132#### `REFINERY_XTEXT_THREAD_COUNT` 127#### `REFINERY_XTEXT_THREAD_COUNT`
133 128
134Number of threads used for non-blocking text editing operations. A value of `0` allows an _unlimited_ number of threads by running each semantics calculation in a new thread. 129Number of threads used for non-blocking text editing operations. A value of `0` allows an _unlimited_ number of threads by running each semantics calculation in a new thread.
135 130
136:warning: Excessively large values may overload the server. Make sure that _all_ Refinery threads can run at the same time to avoid thread starvation.
137
138**Default value:** `1` 131**Default value:** `1`
139 132
140#### `REFINERY_XTEXT_LOCKING_THREAD_COUNT` 133#### `REFINERY_XTEXT_LOCKING_THREAD_COUNT`
141 134
142Number of threads used for text editing operations that lock the document. A value of `0` allows an _unlimited_ number of threads by running each semantics calculation in a new thread. 135Number of threads used for text editing operations that lock the document. A value of `0` allows an _unlimited_ number of threads by running each semantics calculation in a new thread.
143 136
144
145**Default value:** equal to `REFINERY_XTEXT_THREAD_COUNT` 137**Default value:** equal to `REFINERY_XTEXT_THREAD_COUNT`
146 138
147#### `REFINERY_XTEXT_SEMANTICS_THREAD_COUNT` 139#### `REFINERY_XTEXT_SEMANTICS_THREAD_COUNT`
@@ -150,15 +142,13 @@ Number of threads used for model semantics calculation. A value of `0` allows an
150 142
151Must be at least as large as `REFINERY_XTEXT_THREAD_COUNT`. 143Must be at least as large as `REFINERY_XTEXT_THREAD_COUNT`.
152 144
153:warning: Excessively large values may overload the server. Make sure that _all_ Refinery threads can run at the same time to avoid thread starvation.
154
155**Default value:** equal to `REFINERY_XTEXT_THREAD_COUNT` 145**Default value:** equal to `REFINERY_XTEXT_THREAD_COUNT`
156 146
157#### `REFINERY_MODEL_GENERATION_THREAD_COUNT` 147#### `REFINERY_MODEL_GENERATION_THREAD_COUNT`
158 148
159Number of threads used for model semantics calculation. A value of `0` allows an _unlimited_ number of threads by running each semantics calculation in a new thread. 149Number of threads used for model semantics calculation. A value of `0` allows an _unlimited_ number of threads by running each semantics calculation in a new thread.
160 150
161:warning: Excessively large values may overload the server. Make sure that _all_ Refinery threads can run at the same time to avoid thread starvation. Each model generation task may also demand a large amount of memory in addition to CPU time. 151:warning: Each model generation task may also demand a large amount of memory in addition to CPU time.
162 152
163**Default value:** equal to `REFINERY_XTEXT_THREAD_COUNT` 153**Default value:** equal to `REFINERY_XTEXT_THREAD_COUNT`
164 154
@@ -170,6 +160,15 @@ Modules (`.refinery` files) in this directory or colon-separated list of directo
170 160
171:arrow_right: Use this in conjunction with the [mount volume (-v)](https://docs.docker.com/reference/cli/docker/container/run/#volume) option of `docker run` to work with multi-file projects in Refinery. 161:arrow_right: Use this in conjunction with the [mount volume (-v)](https://docs.docker.com/reference/cli/docker/container/run/#volume) option of `docker run` to work with multi-file projects in Refinery.
172 162
173:warning: Make sure you only expose files that you want to make public. It's best to expose a directory that contains nothing other that `.refinery` files to minimize potential information leaks. 163:warning: Only expose files that you want to make public. It's best to expose a directory that contains nothing other than `.refinery` files to minimize potential information leaks.
174 164
175**Default value:** _empty_ (no directories are exposed) 165**Default value:** _empty_ (no directories are exposed)
166
167## Pre-release versions
168
169You can take advantage of the most recent code submitted to our repository by using the `latest` tag instead.
170
171
172```shell
173docker run --pull always --rm -it -p 8888:8888 ghcr.io/graphs4value/refinery:latest
174```
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/index.md b/subprojects/docs/versioned_docs/version-0.1.0/learn/index.md
new file mode 100644
index 00000000..7f67fd86
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/index.md
@@ -0,0 +1,11 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4sidebar_position: 0
5---
6
7# Introduction
8
9Various software and systems engineering scenarios rely on the systematic construction of consistent graph models. However, **automatically generating a diverse set of consistent graph models** for complex domain specifications is challenging. First, the graph generation problem must be specified with mathematical precision. Moreover, graph generation is a computationally complex task, which necessitates specialized logic solvers.
10
11**Refinery is an open-source software framework** for the automated synthesis of a diverse set of consistent domain-specific graph models. The framework offers an expressive high-level specification language using partial models to succinctly formulate a wide range of graph generation challenges. It also provides a modern cloud-based architecture for a scalable _Graph Solver as a Service,_ which uses logic reasoning rules to efficiently synthesize a diverse set of solutions to graph generation problems by partial model refinement. Applications include system-level architecture synthesis, test generation for modeling tools or traffic scenario synthesis for autonomous vehicles.
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/_category_.yml b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/_category_.yml
new file mode 100644
index 00000000..a261ebf6
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/_category_.yml
@@ -0,0 +1,10 @@
1# SPDX-FileCopyrightText: 2024 The Refinery Authors
2#
3# SPDX-License-Identifier: EPL-2.0
4
5position: 2
6label: Language reference
7link:
8 type: generated-index
9 slug: /learn/language
10 description: Learn more about the Refinery partial modeling language!
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg
new file mode 100644
index 00000000..197f4b48
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg
@@ -0,0 +1,227 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="395pt" height="226pt" viewBox="-6 -6 407.4700012207031 238.39999389648438" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-sdYDAL2PsHukjJUpNyUhU"><style>.refinery-sdYDAL2PsHukjJUpNyUhU .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-sdYDAL2PsHukjJUpNyUhU .node .node-outline{stroke:#19202b;}.refinery-sdYDAL2PsHukjJUpNyUhU .node .node-header{fill:rgb(53, 161, 173);}.refinery-sdYDAL2PsHukjJUpNyUhU .node .node-bg{fill:#fff;}.refinery-sdYDAL2PsHukjJUpNyUhU .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-sdYDAL2PsHukjJUpNyUhU .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-sdYDAL2PsHukjJUpNyUhU .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-h .node-header{fill:#e06c75;}.refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-i .node-header{fill:#98c379;}.refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-j .node-header{fill:#c678dd;}.refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-n .node-header{fill:#abcc94;}.refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-sdYDAL2PsHukjJUpNyUhU .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-sdYDAL2PsHukjJUpNyUhU .edge .edge-line{stroke:#19202b;}.refinery-sdYDAL2PsHukjJUpNyUhU .edge .edge-arrow{fill:#19202b;}.refinery-sdYDAL2PsHukjJUpNyUhU .edge-UNKNOWN text{fill:#696c77;}.refinery-sdYDAL2PsHukjJUpNyUhU .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-sdYDAL2PsHukjJUpNyUhU .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-sdYDAL2PsHukjJUpNyUhU .edge-ERROR text{fill:#ca1243;}.refinery-sdYDAL2PsHukjJUpNyUhU .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-sdYDAL2PsHukjJUpNyUhU .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-sdYDAL2PsHukjJUpNyUhU .icon-TRUE{fill:#19202b;}.refinery-sdYDAL2PsHukjJUpNyUhU .icon-UNKNOWN{fill:#696c77;}.refinery-sdYDAL2PsHukjJUpNyUhU .icon-ERROR{fill:#ca1243;}.refinery-sdYDAL2PsHukjJUpNyUhU text.label-UNKNOWN{fill:#696c77;}.refinery-sdYDAL2PsHukjJUpNyUhU text.label-ERROR{fill:#ca1243;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-sdYDAL2PsHukjJUpNyUhU text.label-ERROR{fill:#e06c75;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-sdYDAL2PsHukjJUpNyUhU-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-sdYDAL2PsHukjJUpNyUhU-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-sdYDAL2PsHukjJUpNyUhU-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="scale(1 1) rotate(0) translate(4 222.4)">
4<!-- n3 -->
5<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
6
7<rect stroke="none" x="155.95" y="-133.6" width="64.03" height="48.8" rx="12" ry="12" class="node-bg"/>
8<rect stroke="none" x="151" y="-137" width="72" height="27" clip-path="url(#refinery-sdYDAL2PsHukjJUpNyUhU-clip-0)" class="node-header"/>
9<text text-anchor="start" x="181.53" y="-117.8" font-size="12.00">v1</text>
10<use x="161.952" y="-104" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-sdYDAL2PsHukjJUpNyUhU-icon-TRUE"/>
11<g><text text-anchor="start" x="177.95" y="-94.4" font-size="12.00" class="label label-TRUE">Vertex</text>
12</g>
13<polyline points="155.95,-110.2 219.98,-110.2" class="node-outline"/>
14<rect fill="none" x="155.95" y="-133.6" width="64.03" height="48.8" rx="12" ry="12" class="node-outline"/>
15<clipPath id="refinery-sdYDAL2PsHukjJUpNyUhU-clip-0"><rect stroke="none" x="155.95" y="-133.6" width="64.03" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
16<!-- n4 -->
17<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-k">
18
19<rect stroke="none" x="113.78" y="-218.4" width="66.37" height="48.80000000000001" rx="12" ry="12" class="node-bg"/>
20<rect stroke="none" x="109" y="-222" width="74" height="27" clip-path="url(#refinery-sdYDAL2PsHukjJUpNyUhU-clip-1)" class="node-header"/>
21<text text-anchor="start" x="141.09" y="-202.6" font-size="12.00">r1</text>
22<use x="119.78" y="-188.8" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-sdYDAL2PsHukjJUpNyUhU-icon-TRUE"/>
23<g><text text-anchor="start" x="135.78" y="-179.2" font-size="12.00" class="label label-TRUE">Region</text>
24</g>
25<polyline points="113.78,-195 180.15,-195" class="node-outline"/>
26<rect fill="none" x="113.78" y="-218.4" width="66.37" height="48.80000000000001" rx="12" ry="12" class="node-outline"/>
27<clipPath id="refinery-sdYDAL2PsHukjJUpNyUhU-clip-1"><rect stroke="none" x="113.78" y="-218.4" width="66.37" height="48.80000000000001" rx="12" ry="12" class="node-bg"/></clipPath></g>
28<!-- n3&#45;&gt;n4 -->
29<g class="edge edge-TRUE">
30
31<path fill="none" d="M182.6,-133.43C179.13,-141.63 174.65,-151.02 170,-159.88" class="edge-line"/>
32<polygon points="166.95,-158.15 165.24,-168.61 173.1,-161.5 166.95,-158.15" class="edge-line edge-arrow"/>
33<text text-anchor="middle" x="158.39" y="-155.04" font-size="10.50">region</text>
34</g>
35<!-- n8 -->
36<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
37
38<rect stroke="none" x="53.86" y="-48.8" width="84.22000000000001" height="48.8" rx="12" ry="12" class="node-bg"/>
39<rect stroke="none" x="49" y="-52" width="92" height="27" clip-path="url(#refinery-sdYDAL2PsHukjJUpNyUhU-clip-2)" class="node-header"/>
40<text text-anchor="start" x="90.42" y="-33" font-size="12.00">t1</text>
41<use x="59.8559" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-sdYDAL2PsHukjJUpNyUhU-icon-TRUE"/>
42<g><text text-anchor="start" x="75.86" y="-9.6" font-size="12.00" class="label label-TRUE">Transition</text>
43</g>
44<polyline points="53.86,-25.4 138.08,-25.4" class="node-outline"/>
45<rect fill="none" x="53.86" y="-48.8" width="84.22000000000001" height="48.8" rx="12" ry="12" class="node-outline"/>
46<clipPath id="refinery-sdYDAL2PsHukjJUpNyUhU-clip-2"><rect stroke="none" x="53.86" y="-48.8" width="84.22000000000001" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
47<!-- n3&#45;&gt;n8 -->
48<g class="edge edge-TRUE">
49
50<path fill="none" stroke-width="2" d="M155.95,-84.92C145.63,-76.18 134.29,-66.11 124.25,-56.77" class="edge-line"/>
51<polygon stroke-width="2" points="126.48,-54.66 118.02,-50.88 122.27,-59.11 126.48,-54.66" class="edge-line edge-arrow"/>
52<text text-anchor="start" x="35.36" y="-71.18" font-weight="bold" font-size="10.50">outgoingTransition</text>
53</g>
54<!-- n3&#45;&gt;n8 -->
55
56<!-- n9 -->
57<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
58
59<rect stroke="none" x="155.86" y="-48.8" width="84.22" height="48.8" rx="12" ry="12" class="node-bg"/>
60<rect stroke="none" x="151" y="-52" width="92" height="27" clip-path="url(#refinery-sdYDAL2PsHukjJUpNyUhU-clip-3)" class="node-header"/>
61<text text-anchor="start" x="192.42" y="-33" font-size="12.00">t2</text>
62<use x="161.856" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-sdYDAL2PsHukjJUpNyUhU-icon-TRUE"/>
63<g><text text-anchor="start" x="177.86" y="-9.6" font-size="12.00" class="label label-TRUE">Transition</text>
64</g>
65<polyline points="155.86,-25.4 240.08,-25.4" class="node-outline"/>
66<rect fill="none" x="155.86" y="-48.8" width="84.22" height="48.8" rx="12" ry="12" class="node-outline"/>
67<clipPath id="refinery-sdYDAL2PsHukjJUpNyUhU-clip-3"><rect stroke="none" x="155.86" y="-48.8" width="84.22" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
68<!-- n3&#45;&gt;n9 -->
69<g class="edge edge-TRUE">
70
71<path fill="none" stroke-width="2" d="M172.38,-85.14C171.61,-77.31 172.15,-68.38 173.81,-59.86" class="edge-line"/>
72<polygon stroke-width="2" points="176.73,-60.8 175.99,-51.56 170.81,-59.24 176.73,-60.8" class="edge-line edge-arrow"/>
73<text text-anchor="start" x="72.62" y="-58.26" font-weight="bold" font-size="10.50">outgoingTransition</text>
74</g><g class="edge edge-TRUE">
75
76<path fill="none" d="M184.63,-85.14C185,-77.31 185.9,-68.38 187.14,-59.86" class="edge-line"/>
77<polygon points="190.57,-60.56 188.77,-50.12 183.67,-59.4 190.57,-60.56" class="edge-line edge-arrow"/>
78<text text-anchor="middle" x="233.31" y="-70.26" font-size="10.50">incomingTransition</text>
79</g>
80<!-- n3&#45;&gt;n9 -->
81
82<!-- n10 -->
83<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
84
85<rect stroke="none" x="257.86" y="-48.8" width="84.21999999999997" height="48.8" rx="12" ry="12" class="node-bg"/>
86<rect stroke="none" x="253" y="-52" width="92" height="27" clip-path="url(#refinery-sdYDAL2PsHukjJUpNyUhU-clip-4)" class="node-header"/>
87<text text-anchor="start" x="294.42" y="-33" font-size="12.00">t3</text>
88<use x="263.856" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-sdYDAL2PsHukjJUpNyUhU-icon-TRUE"/>
89<g><text text-anchor="start" x="279.86" y="-9.6" font-size="12.00" class="label label-TRUE">Transition</text>
90</g>
91<polyline points="257.86,-25.4 342.08,-25.4" class="node-outline"/>
92<rect fill="none" x="257.86" y="-48.8" width="84.21999999999997" height="48.8" rx="12" ry="12" class="node-outline"/>
93<clipPath id="refinery-sdYDAL2PsHukjJUpNyUhU-clip-4"><rect stroke="none" x="257.86" y="-48.8" width="84.21999999999997" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
94<!-- n3&#45;&gt;n10 -->
95
96<!-- n4&#45;&gt;n3 -->
97<g class="edge edge-TRUE">
98
99<path fill="none" stroke-width="2" d="M152.26,-169.94C155.72,-161.75 160.2,-152.37 164.84,-143.5" class="edge-line"/>
100<polygon stroke-width="2" points="167.39,-145.24 168.88,-136.09 162.01,-142.31 167.39,-145.24" class="edge-line edge-arrow"/>
101<text text-anchor="start" x="119.24" y="-143.04" font-weight="bold" font-size="10.50">vertices</text>
102</g>
103<!-- n5 -->
104<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
105
106<rect stroke="none" x="73.95" y="-133.6" width="64.02999999999999" height="48.8" rx="12" ry="12" class="node-bg"/>
107<rect stroke="none" x="69" y="-137" width="72" height="27" clip-path="url(#refinery-sdYDAL2PsHukjJUpNyUhU-clip-5)" class="node-header"/>
108<text text-anchor="start" x="99.53" y="-117.8" font-size="12.00">v2</text>
109<use x="79.9516" y="-104" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-sdYDAL2PsHukjJUpNyUhU-icon-TRUE"/>
110<g><text text-anchor="start" x="95.95" y="-94.4" font-size="12.00" class="label label-TRUE">Vertex</text>
111</g>
112<polyline points="73.95,-110.2 137.98,-110.2" class="node-outline"/>
113<rect fill="none" x="73.95" y="-133.6" width="64.02999999999999" height="48.8" rx="12" ry="12" class="node-outline"/>
114<clipPath id="refinery-sdYDAL2PsHukjJUpNyUhU-clip-5"><rect stroke="none" x="73.95" y="-133.6" width="64.02999999999999" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
115<!-- n4&#45;&gt;n5 -->
116<g class="edge edge-TRUE">
117
118<path fill="none" stroke-width="2" d="M129.42,-169.94C124.87,-161.93 120.16,-152.77 116.09,-144.08" class="edge-line"/>
119<polygon stroke-width="2" points="118.93,-142.93 112.57,-136.19 113.34,-145.43 118.93,-142.93" class="edge-line edge-arrow"/>
120<text text-anchor="start" x="78.34" y="-156.05" font-weight="bold" font-size="10.50">vertices</text>
121</g>
122<!-- n5&#45;&gt;n4 -->
123<g class="edge edge-TRUE">
124
125<path fill="none" d="M123.6,-133.43C128.21,-141.54 132.96,-150.81 137.06,-159.59" class="edge-line"/>
126<polygon points="133.79,-160.84 141.05,-168.55 140.18,-157.99 133.79,-160.84" class="edge-line edge-arrow"/>
127<text text-anchor="middle" x="117.57" y="-142.24" font-size="10.50">region</text>
128</g>
129<!-- n5&#45;&gt;n8 -->
130<g class="edge edge-TRUE">
131
132<path fill="none" d="M97.06,-85.14C95.54,-77.31 94.28,-68.38 93.46,-59.86" class="edge-line"/>
133<polygon points="96.97,-59.85 92.75,-50.14 89.99,-60.37 96.97,-59.85" class="edge-line edge-arrow"/>
134<text text-anchor="middle" x="47.13" y="-57.66" font-size="10.50">incomingTransition</text>
135</g>
136<!-- n5&#45;&gt;n9 -->
137
138<!-- n5&#45;&gt;n10 -->
139
140<!-- n6 -->
141<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
142
143<rect stroke="none" x="267.95" y="-133.6" width="64.03000000000003" height="48.8" rx="12" ry="12" class="node-bg"/>
144<rect stroke="none" x="263" y="-137" width="72" height="27" clip-path="url(#refinery-sdYDAL2PsHukjJUpNyUhU-clip-6)" class="node-header"/>
145<text text-anchor="start" x="293.53" y="-117.8" font-size="12.00">v3</text>
146<use x="273.952" y="-104" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-sdYDAL2PsHukjJUpNyUhU-icon-TRUE"/>
147<g><text text-anchor="start" x="289.95" y="-94.4" font-size="12.00" class="label label-TRUE">Vertex</text>
148</g>
149<polyline points="267.95,-110.2 331.98,-110.2" class="node-outline"/>
150<rect fill="none" x="267.95" y="-133.6" width="64.03000000000003" height="48.8" rx="12" ry="12" class="node-outline"/>
151<clipPath id="refinery-sdYDAL2PsHukjJUpNyUhU-clip-6"><rect stroke="none" x="267.95" y="-133.6" width="64.03000000000003" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g><g class="edge edge-TRUE">
152
153<path fill="none" d="M293.84,-85.14C293.27,-77.31 293.09,-68.38 293.3,-59.86" class="edge-line"/>
154<polygon points="296.78,-60.29 293.76,-50.14 289.79,-59.96 296.78,-60.29" class="edge-line edge-arrow"/>
155<text text-anchor="middle" x="340.34" y="-70.26" font-size="10.50">incomingTransition</text>
156</g>
157<!-- n7 -->
158<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-k">
159
160<rect stroke="none" x="266.78" y="-218.4" width="66.37" height="48.80000000000001" rx="12" ry="12" class="node-bg"/>
161<rect stroke="none" x="262" y="-222" width="74" height="27" clip-path="url(#refinery-sdYDAL2PsHukjJUpNyUhU-clip-7)" class="node-header"/>
162<text text-anchor="start" x="294.09" y="-202.6" font-size="12.00">r2</text>
163<use x="272.78" y="-188.8" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-sdYDAL2PsHukjJUpNyUhU-icon-TRUE"/>
164<g><text text-anchor="start" x="288.78" y="-179.2" font-size="12.00" class="label label-TRUE">Region</text>
165</g>
166<polyline points="266.78,-195 333.15,-195" class="node-outline"/>
167<rect fill="none" x="266.78" y="-218.4" width="66.37" height="48.80000000000001" rx="12" ry="12" class="node-outline"/>
168<clipPath id="refinery-sdYDAL2PsHukjJUpNyUhU-clip-7"><rect stroke="none" x="266.78" y="-218.4" width="66.37" height="48.80000000000001" rx="12" ry="12" class="node-bg"/></clipPath></g>
169<!-- n6&#45;&gt;n7 -->
170<g class="edge edge-TRUE">
171
172<path fill="none" d="M306.1,-133.43C306.67,-141.27 306.84,-150.2 306.63,-158.72" class="edge-line"/>
173<polygon points="303.14,-158.27 306.16,-168.42 310.14,-158.6 303.14,-158.27" class="edge-line edge-arrow"/>
174<text text-anchor="middle" x="291.03" y="-142.02" font-size="10.50">region</text>
175</g>
176<!-- n6&#45;&gt;n8 -->
177
178<!-- n6&#45;&gt;n9 -->
179
180<!-- n6&#45;&gt;n10 -->
181<g class="edge edge-TRUE">
182
183<path fill="none" d="M213.57,-48.63C214.33,-56.56 213.75,-65.61 212.03,-74.21" class="edge-line"/>
184<polygon points="208.7,-73.11 209.51,-83.67 215.47,-74.91 208.7,-73.11" class="edge-line edge-arrow"/>
185<text text-anchor="middle" x="198.62" y="-70.03" font-size="10.50">target</text>
186</g>
187<!-- n6&#45;&gt;n10 -->
188
189<!-- n7&#45;&gt;n6 -->
190<g class="edge edge-TRUE">
191
192<path fill="none" stroke-width="2" d="M293.84,-169.94C293.28,-162.19 293.09,-153.38 293.29,-144.95" class="edge-line"/>
193<polygon stroke-width="2" points="296.34,-145.33 293.69,-136.45 290.22,-145.05 296.34,-145.33" class="edge-line edge-arrow"/>
194<text text-anchor="start" x="251.69" y="-155.87" font-weight="bold" font-size="10.50">vertices</text>
195</g><g class="edge edge-TRUE">
196
197<path fill="none" stroke-width="2" d="M281.6,-85.14C279.9,-77.39 279.35,-68.58 279.95,-60.15" class="edge-line"/>
198<polygon stroke-width="2" points="282.96,-60.72 281.14,-51.63 276.9,-59.87 282.96,-60.72" class="edge-line edge-arrow"/>
199<text text-anchor="start" x="179.61" y="-58.47" font-weight="bold" font-size="10.50">outgoingTransition</text>
200</g><g class="edge edge-TRUE">
201
202<path fill="none" d="M318.37,-48.63C320.07,-56.47 320.6,-65.4 319.95,-73.92" class="edge-line"/>
203<polygon points="316.51,-73.24 318.55,-83.64 323.44,-74.24 316.51,-73.24" class="edge-line edge-arrow"/>
204<text text-anchor="middle" x="305.62" y="-57.22" font-size="10.50">target</text>
205</g>
206<g class="edge edge-TRUE">
207
208<path fill="none" d="M127.91,-48.63C138.46,-57.54 150.06,-67.86 160.27,-77.38" class="edge-line"/>
209<polygon points="157.7,-79.76 167.36,-84.09 162.51,-74.68 157.7,-79.76" class="edge-line edge-arrow"/>
210<text text-anchor="middle" x="165.07" y="-69.83" font-size="10.50">source</text>
211</g><g class="edge edge-TRUE">
212
213<path fill="none" d="M104.91,-48.63C106.42,-56.47 107.67,-65.4 108.49,-73.92" class="edge-line"/>
214<polygon points="104.98,-73.91 109.19,-83.63 111.96,-73.4 104.98,-73.91" class="edge-line edge-arrow"/>
215<text text-anchor="middle" x="122.29" y="-69.82" font-size="10.50">target</text>
216</g><g class="edge edge-TRUE">
217
218<path fill="none" d="M201.3,-48.63C200.91,-56.47 200.01,-65.4 198.77,-73.92" class="edge-line"/>
219<polygon points="195.34,-73.2 197.13,-83.64 202.24,-74.36 195.34,-73.2" class="edge-line edge-arrow"/>
220<text text-anchor="middle" x="183.25" y="-57.22" font-size="10.50">source</text>
221</g><g class="edge edge-TRUE">
222
223<path fill="none" d="M306.1,-48.63C306.67,-56.47 306.84,-65.4 306.63,-73.92" class="edge-line"/>
224<polygon points="303.14,-73.47 306.16,-83.62 310.14,-73.8 303.14,-73.47" class="edge-line edge-arrow"/>
225<text text-anchor="middle" x="323.2" y="-57.22" font-size="10.50">source</text>
226</g></g>
227</svg> \ No newline at end of file
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ContainmentInstance.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg
new file mode 100644
index 00000000..fb9dd37d
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg
@@ -0,0 +1,20 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="74pt" height="72pt" viewBox="-6 -6 86 84.4000015258789" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-S3CluI8WDJspDI9OUqv4H"><style>.refinery-S3CluI8WDJspDI9OUqv4H .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-S3CluI8WDJspDI9OUqv4H .node .node-outline{stroke:#19202b;}.refinery-S3CluI8WDJspDI9OUqv4H .node .node-header{fill:rgb(53, 161, 173);}.refinery-S3CluI8WDJspDI9OUqv4H .node .node-bg{fill:#fff;}.refinery-S3CluI8WDJspDI9OUqv4H .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-S3CluI8WDJspDI9OUqv4H .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-S3CluI8WDJspDI9OUqv4H .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-h .node-header{fill:#e06c75;}.refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-i .node-header{fill:#98c379;}.refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-j .node-header{fill:#c678dd;}.refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-n .node-header{fill:#abcc94;}.refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-S3CluI8WDJspDI9OUqv4H .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-S3CluI8WDJspDI9OUqv4H .edge .edge-line{stroke:#19202b;}.refinery-S3CluI8WDJspDI9OUqv4H .edge .edge-arrow{fill:#19202b;}.refinery-S3CluI8WDJspDI9OUqv4H .edge-UNKNOWN text{fill:#696c77;}.refinery-S3CluI8WDJspDI9OUqv4H .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-S3CluI8WDJspDI9OUqv4H .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-S3CluI8WDJspDI9OUqv4H .edge-ERROR text{fill:#ca1243;}.refinery-S3CluI8WDJspDI9OUqv4H .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-S3CluI8WDJspDI9OUqv4H .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-S3CluI8WDJspDI9OUqv4H .icon-TRUE{fill:#19202b;}.refinery-S3CluI8WDJspDI9OUqv4H .icon-UNKNOWN{fill:#696c77;}.refinery-S3CluI8WDJspDI9OUqv4H .icon-ERROR{fill:#ca1243;}.refinery-S3CluI8WDJspDI9OUqv4H text.label-UNKNOWN{fill:#696c77;}.refinery-S3CluI8WDJspDI9OUqv4H text.label-ERROR{fill:#ca1243;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-S3CluI8WDJspDI9OUqv4H text.label-ERROR{fill:#e06c75;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-S3CluI8WDJspDI9OUqv4H-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-S3CluI8WDJspDI9OUqv4H-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-S3CluI8WDJspDI9OUqv4H-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="translate(4, 68.4000015258789)">
4<!-- n0 -->
5
6<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE">
7
8<rect stroke="none" x="0" y="-64.4" width="66" height="64.4" rx="12" ry="12" class="node-bg"/>
9<rect stroke="none" x="-4" y="-68" width="74" height="27" clip-path="url(#refinery-S3CluI8WDJspDI9OUqv4H-clip-0)" class="node-header"/>
10<text text-anchor="start" x="14.75" y="-48.6" font-size="12.00">invalid</text>
11<use x="6" y="-35" width="12" height="12" id="" class="icon icon-ERROR" href="#refinery-S3CluI8WDJspDI9OUqv4H-icon-ERROR"/>
12<g><text text-anchor="start" x="21.81" y="-25.2" font-size="12.00" class="label label-ERROR">Region</text>
13</g>
14<use x="6" y="-19" width="12" height="12" id="" class="icon icon-ERROR" href="#refinery-S3CluI8WDJspDI9OUqv4H-icon-ERROR"/>
15<g><text text-anchor="start" x="22" y="-9.2" font-size="12.00" class="label label-ERROR">State</text>
16</g>
17<polyline points="0,-41 66,-41" class="node-outline"/>
18<rect fill="none" x="0" y="-64.4" width="66" height="64.4" rx="12" ry="12" class="node-outline"/>
19<clipPath id="refinery-S3CluI8WDJspDI9OUqv4H-clip-0"><rect stroke="none" x="0" y="-64.4" width="66" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g></g>
20</svg> \ No newline at end of file
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/InvalidInstance.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg
new file mode 100644
index 00000000..b28c295a
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg
@@ -0,0 +1,229 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="802pt" height="157pt" viewBox="-6 -6 814.3800048828125 169.1999969482422" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-MZ1i4PkeOsY_2x7-6CJ29"><style>.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node .node-outline{stroke:#19202b;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node .node-header{fill:rgb(53, 161, 173);}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node .node-bg{fill:#fff;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-h .node-header{fill:#e06c75;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-i .node-header{fill:#98c379;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-j .node-header{fill:#c678dd;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-n .node-header{fill:#abcc94;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge .edge-line{stroke:#19202b;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge .edge-arrow{fill:#19202b;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge-UNKNOWN text{fill:#696c77;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge-ERROR text{fill:#ca1243;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .icon-TRUE{fill:#19202b;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .icon-UNKNOWN{fill:#696c77;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 .icon-ERROR{fill:#ca1243;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 text.label-UNKNOWN{fill:#696c77;}.refinery-MZ1i4PkeOsY_2x7-6CJ29 text.label-ERROR{fill:#ca1243;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-MZ1i4PkeOsY_2x7-6CJ29 text.label-ERROR{fill:#e06c75;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-MZ1i4PkeOsY_2x7-6CJ29-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-MZ1i4PkeOsY_2x7-6CJ29-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-MZ1i4PkeOsY_2x7-6CJ29-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="translate(4, 153.1999969482422)">
4<!-- n0 -->
5
6<!-- n0&#45;&gt;n0 -->
7
8<!-- n0&#45;&gt;n1 -->
9
10<!-- n0&#45;&gt;n1 -->
11
12<!-- n3 -->
13<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
14
15<rect stroke="none" x="84.25" y="-141.4" width="64.03" height="48.80000000000001" rx="12" ry="12" class="node-bg"/>
16<rect stroke="none" x="80" y="-145" width="72" height="27" clip-path="url(#refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-0)" class="node-header"/>
17<text text-anchor="start" x="109.83" y="-125.6" font-size="12.00">v1</text>
18<use x="90.2516" y="-111.8" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-MZ1i4PkeOsY_2x7-6CJ29-icon-TRUE"/>
19<g><text text-anchor="start" x="106.25" y="-102.2" font-size="12.00" class="label label-TRUE">Vertex</text>
20</g>
21<polyline points="84.25,-118 148.28,-118" class="node-outline"/>
22<rect fill="none" x="84.25" y="-141.4" width="64.03" height="48.80000000000001" rx="12" ry="12" class="node-outline"/>
23<clipPath id="refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-0"><rect stroke="none" x="84.25" y="-141.4" width="64.03" height="48.80000000000001" rx="12" ry="12" class="node-bg"/></clipPath></g>
24<!-- n1&#45;&gt;n3 -->
25<g class="edge edge-TRUE">
26
27<path fill="none" d="M127.79,-92.67C135,-81.99 144.45,-69.17 153.6,-57.6" class="edge-line"/>
28<polygon points="156.32,-59.81 159.88,-49.83 150.87,-55.41 156.32,-59.81" class="edge-line edge-arrow"/>
29<text text-anchor="middle" x="190.06" y="-60.95" font-size="10.50">outgoingTransition</text>
30</g>
31<!-- n5 -->
32<g class="edge edge-TRUE">
33
34<path fill="none" d="M172.8,-48.65C165.6,-59.32 156.15,-72.13 147,-83.71" class="edge-line"/>
35<polygon points="144.27,-81.51 140.72,-91.49 149.72,-85.91 144.27,-81.51" class="edge-line edge-arrow"/>
36<text text-anchor="middle" x="140.38" y="-74.06" font-size="10.50">source</text>
37</g>
38<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
39
40<rect stroke="none" x="40.16" y="-48.8" width="84.22" height="48.8" rx="12" ry="12" class="node-bg"/>
41<rect stroke="none" x="36" y="-52" width="92" height="27" clip-path="url(#refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-1)" class="node-header"/>
42<text text-anchor="start" x="76.72" y="-33" font-size="12.00">t1</text>
43<use x="46.1559" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-MZ1i4PkeOsY_2x7-6CJ29-icon-TRUE"/>
44<g><text text-anchor="start" x="62.16" y="-9.6" font-size="12.00" class="label label-TRUE">Transition</text>
45</g>
46<polyline points="40.16,-25.4 124.38,-25.4" class="node-outline"/>
47<rect fill="none" x="40.16" y="-48.8" width="84.22" height="48.8" rx="12" ry="12" class="node-outline"/>
48<clipPath id="refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-1"><rect stroke="none" x="40.16" y="-48.8" width="84.22" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g><g class="edge edge-TRUE">
49
50<path fill="none" d="M96.97,-48.65C101.54,-58.79 106.27,-70.87 110.06,-81.98" class="edge-line"/>
51<polygon points="106.64,-82.78 113.04,-91.23 113.3,-80.64 106.64,-82.78" class="edge-line edge-arrow"/>
52<text text-anchor="middle" x="89.38" y="-60.85" font-size="10.50">source</text>
53</g><g class="edge edge-TRUE">
54
55<path fill="none" d="M101.52,-92.67C96.95,-82.52 92.23,-70.44 88.44,-59.33" class="edge-line"/>
56<polygon points="91.87,-58.54 85.47,-50.09 85.2,-60.68 91.87,-58.54" class="edge-line edge-arrow"/>
57<text text-anchor="middle" x="46.32" y="-74.16" font-size="10.50">outgoingTransition</text>
58</g><g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
59
60<rect stroke="none" x="142.16" y="-48.8" width="84.22" height="48.8" rx="12" ry="12" class="node-bg"/>
61<rect stroke="none" x="138" y="-52" width="92" height="27" clip-path="url(#refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-2)" class="node-header"/>
62<text text-anchor="start" x="178.72" y="-33" font-size="12.00">t2</text>
63<use x="148.156" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-MZ1i4PkeOsY_2x7-6CJ29-icon-TRUE"/>
64<g><text text-anchor="start" x="164.16" y="-9.6" font-size="12.00" class="label label-TRUE">Transition</text>
65</g>
66<polyline points="142.16,-25.4 226.38,-25.4" class="node-outline"/>
67<rect fill="none" x="142.16" y="-48.8" width="84.22" height="48.8" rx="12" ry="12" class="node-outline"/>
68<clipPath id="refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-2"><rect stroke="none" x="142.16" y="-48.8" width="84.22" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g><!-- n5 -->
69<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
70
71<rect stroke="none" x="200.77" y="-149.2" width="236.99999999999997" height="64.39999999999999" rx="12" ry="12" class="node-bg"/>
72<rect stroke="none" x="196" y="-153" width="244" height="27" clip-path="url(#refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-3)" class="node-header"/>
73<text text-anchor="start" x="312.83" y="-133.4" font-size="12.00">v2</text>
74<use x="206.766" y="-119.8" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-MZ1i4PkeOsY_2x7-6CJ29-icon-TRUE"/>
75<g><text text-anchor="start" x="222.77" y="-110" font-size="12.00" class="label label-TRUE">Vertex</text>
76</g>
77<use x="206.766" y="-103.8" width="12" height="12" id="" class="icon icon-ERROR" href="#refinery-MZ1i4PkeOsY_2x7-6CJ29-icon-ERROR"/>
78<g><text text-anchor="start" x="222.4" y="-94" font-size="12.00" class="label label-ERROR">outgoingTransition::invalidMultiplicity</text>
79</g>
80<polyline points="200.77,-125.8 437.77,-125.8" class="node-outline"/>
81<rect fill="none" x="200.77" y="-149.2" width="236.99999999999997" height="64.39999999999999" rx="12" ry="12" class="node-outline"/>
82<clipPath id="refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-3"><rect stroke="none" x="200.77" y="-149.2" width="236.99999999999997" height="64.39999999999999" rx="12" ry="12" class="node-bg"/></clipPath></g><g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
83
84<rect stroke="none" x="277.16" y="-48.8" width="84.21999999999997" height="48.8" rx="12" ry="12" class="node-bg"/>
85<rect stroke="none" x="273" y="-52" width="92" height="27" clip-path="url(#refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-4)" class="node-header"/>
86<text text-anchor="start" x="313.72" y="-33" font-size="12.00">t3</text>
87<use x="283.156" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-MZ1i4PkeOsY_2x7-6CJ29-icon-TRUE"/>
88<g><text text-anchor="start" x="299.16" y="-9.6" font-size="12.00" class="label label-TRUE">Transition</text>
89</g>
90<polyline points="277.16,-25.4 361.38,-25.4" class="node-outline"/>
91<rect fill="none" x="277.16" y="-48.8" width="84.21999999999997" height="48.8" rx="12" ry="12" class="node-outline"/>
92<clipPath id="refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-4"><rect stroke="none" x="277.16" y="-48.8" width="84.21999999999997" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
93<!-- n4&#45;&gt;n5 -->
94
95<!-- n5&#45;&gt;n4 -->
96<g class="edge edge-TRUE">
97
98<path fill="none" d="M325.25,-48.62C325.82,-56.19 326.07,-64.85 326.01,-73.38" class="edge-line"/>
99<polygon points="322.51,-73.22 325.75,-83.31 329.51,-73.4 322.51,-73.22" class="edge-line edge-arrow"/>
100<text text-anchor="middle" x="309.51" y="-57.13" font-size="10.50">source</text>
101</g>
102<!-- n6&#45;&gt;n5 -->
103<g class="edge edge-TRUE">
104
105<path fill="none" d="M312.82,-84.82C312.47,-76.84 312.42,-68.21 312.68,-60.07" class="edge-line"/>
106<polygon points="316.18,-60.3 313.21,-50.13 309.19,-59.94 316.18,-60.3" class="edge-line edge-arrow"/>
107<text text-anchor="middle" x="358.85" y="-70.18" font-size="10.50">outgoingTransition</text>
108</g>
109<!-- n7 -->
110<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
111
112<rect stroke="none" x="404.16" y="-48.8" width="84.21999999999997" height="48.8" rx="12" ry="12" class="node-bg"/>
113<rect stroke="none" x="400" y="-52" width="92" height="27" clip-path="url(#refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-5)" class="node-header"/>
114<text text-anchor="start" x="440.72" y="-33" font-size="12.00">t4</text>
115<use x="410.156" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-MZ1i4PkeOsY_2x7-6CJ29-icon-TRUE"/>
116<g><text text-anchor="start" x="426.16" y="-9.6" font-size="12.00" class="label label-TRUE">Transition</text>
117</g>
118<polyline points="404.16,-25.4 488.38,-25.4" class="node-outline"/>
119<rect fill="none" x="404.16" y="-48.8" width="84.21999999999997" height="48.8" rx="12" ry="12" class="node-outline"/>
120<clipPath id="refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-5"><rect stroke="none" x="404.16" y="-48.8" width="84.21999999999997" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
121<!-- n8 -->
122<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
123
124<rect stroke="none" x="493.77" y="-149.2" width="237" height="64.39999999999999" rx="12" ry="12" class="node-bg"/>
125<rect stroke="none" x="489" y="-153" width="245" height="27" clip-path="url(#refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-6)" class="node-header"/>
126<text text-anchor="start" x="605.83" y="-133.4" font-size="12.00">v3</text>
127<use x="499.766" y="-119.8" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-MZ1i4PkeOsY_2x7-6CJ29-icon-TRUE"/>
128<g><text text-anchor="start" x="515.77" y="-110" font-size="12.00" class="label label-TRUE">Vertex</text>
129</g>
130<polyline points="493.77,-125.8 730.77,-125.8" class="node-outline"/><use x="499.766" y="-103.8" width="12" height="12" id="" class="icon icon-ERROR" href="#refinery-MZ1i4PkeOsY_2x7-6CJ29-icon-ERROR"/>
131
132<rect fill="none" x="493.77" y="-149.2" width="237" height="64.39999999999999" rx="12" ry="12" class="node-outline"/><g><text text-anchor="start" x="515.4" y="-94" font-size="12.00" class="label label-ERROR">outgoingTransition::invalidMultiplicity</text>
133</g>
134
135<clipPath id="refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-6"><rect stroke="none" x="493.77" y="-149.2" width="237" height="64.39999999999999" rx="12" ry="12" class="node-bg"/></clipPath></g>
136<!-- n7&#45;&gt;n8 -->
137<g class="edge edge-TRUE">
138
139<path fill="none" d="M488.13,-45.15C507.42,-55.16 530.62,-67.65 551.73,-79.34" class="edge-line"/>
140<polygon points="549.83,-82.28 560.27,-84.08 553.23,-76.16 549.83,-82.28" class="edge-line edge-arrow"/>
141<text text-anchor="middle" x="508.37" y="-55.19" font-size="10.50">source</text>
142</g>
143<!-- n8&#45;&gt;n7 -->
144<g class="edge edge-TRUE">
145
146<path fill="none" d="M548.69,-84.82C530.15,-74.94 510.25,-64.06 492.94,-54.34" class="edge-line"/>
147<polygon points="494.83,-51.38 484.4,-49.51 491.38,-57.48 494.83,-51.38" class="edge-line edge-arrow"/>
148<text text-anchor="middle" x="469.61" y="-70.25" font-size="10.50">outgoingTransition</text>
149</g>
150<!-- n9 -->
151<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
152
153<rect stroke="none" x="506.16" y="-48.8" width="84.21999999999997" height="48.8" rx="12" ry="12" class="node-bg"/>
154<rect stroke="none" x="502" y="-52" width="92" height="27" clip-path="url(#refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-7)" class="node-header"/>
155<text text-anchor="start" x="542.72" y="-33" font-size="12.00">t5</text>
156<use x="512.156" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-MZ1i4PkeOsY_2x7-6CJ29-icon-TRUE"/>
157<g><text text-anchor="start" x="528.16" y="-9.6" font-size="12.00" class="label label-TRUE">Transition</text>
158</g>
159<polyline points="506.16,-25.4 590.38,-25.4" class="node-outline"/>
160<rect fill="none" x="506.16" y="-48.8" width="84.21999999999997" height="48.8" rx="12" ry="12" class="node-outline"/>
161<clipPath id="refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-7"><rect stroke="none" x="506.16" y="-48.8" width="84.21999999999997" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
162<!-- n8&#45;&gt;n9 -->
163<g class="edge edge-TRUE">
164
165<path fill="none" d="M583.79,-84.82C577.32,-76.19 570.67,-66.81 564.85,-58.09" class="edge-line"/>
166<polygon points="567.9,-56.37 559.52,-49.89 562.03,-60.18 567.9,-56.37" class="edge-line edge-arrow"/>
167<text text-anchor="middle" x="617.13" y="-69.99" font-size="10.50">outgoingTransition</text>
168</g>
169<!-- n10 -->
170<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
171
172<rect stroke="none" x="608.16" y="-48.8" width="84.22000000000003" height="48.8" rx="12" ry="12" class="node-bg"/>
173<rect stroke="none" x="604" y="-52" width="92" height="27" clip-path="url(#refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-8)" class="node-header"/>
174<text text-anchor="start" x="644.72" y="-33" font-size="12.00">t6</text>
175<use x="614.156" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-MZ1i4PkeOsY_2x7-6CJ29-icon-TRUE"/>
176<g><text text-anchor="start" x="630.16" y="-9.6" font-size="12.00" class="label label-TRUE">Transition</text>
177</g>
178<polyline points="608.16,-25.4 692.38,-25.4" class="node-outline"/>
179<rect fill="none" x="608.16" y="-48.8" width="84.22000000000003" height="48.8" rx="12" ry="12" class="node-outline"/>
180<clipPath id="refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-8"><rect stroke="none" x="608.16" y="-48.8" width="84.22000000000003" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
181<!-- n8&#45;&gt;n10 -->
182<g class="edge edge-TRUE">
183
184<path fill="none" d="M618.89,-84.82C622.03,-76.47 625.8,-67.41 629.66,-58.94" class="edge-line"/>
185<polygon points="632.78,-60.52 633.9,-49.99 626.45,-57.53 632.78,-60.52" class="edge-line edge-arrow"/>
186<text text-anchor="middle" x="579.94" y="-57.16" font-size="10.50">outgoingTransition</text>
187</g>
188<!-- n11 -->
189<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
190
191<rect stroke="none" x="710.16" y="-48.8" width="84.22000000000003" height="48.8" rx="12" ry="12" class="node-bg"/>
192<rect stroke="none" x="706" y="-52" width="92" height="27" clip-path="url(#refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-9)" class="node-header"/>
193<text text-anchor="start" x="746.72" y="-33" font-size="12.00">t7</text>
194<use x="716.156" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-MZ1i4PkeOsY_2x7-6CJ29-icon-TRUE"/>
195<g><text text-anchor="start" x="732.16" y="-9.6" font-size="12.00" class="label label-TRUE">Transition</text>
196</g>
197<polyline points="710.16,-25.4 794.38,-25.4" class="node-outline"/>
198<rect fill="none" x="710.16" y="-48.8" width="84.22000000000003" height="48.8" rx="12" ry="12" class="node-outline"/>
199<clipPath id="refinery-MZ1i4PkeOsY_2x7-6CJ29-clip-9"><rect stroke="none" x="710.16" y="-48.8" width="84.22000000000003" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
200<!-- n8&#45;&gt;n11 -->
201<g class="edge edge-TRUE">
202
203<path fill="none" d="M654,-84.82C668.76,-74.99 685.52,-64.17 700.97,-54.48" class="edge-line"/>
204<polygon points="702.47,-57.67 709.12,-49.42 698.78,-51.73 702.47,-57.67" class="edge-line edge-arrow"/>
205<text text-anchor="middle" x="728.4" y="-57.01" font-size="10.50">outgoingTransition</text>
206</g>
207<!-- n9&#45;&gt;n8 -->
208<g class="edge edge-TRUE">
209
210<path fill="none" d="M570.65,-48.62C577.04,-56.79 583.96,-66.23 590.31,-75.41" class="edge-line"/>
211<polygon points="587.33,-77.25 595.84,-83.57 593.13,-73.33 587.33,-77.25" class="edge-line edge-arrow"/>
212<text text-anchor="middle" x="567.43" y="-69.5" font-size="10.50">source</text>
213</g>
214<!-- n10&#45;&gt;n8 -->
215<g class="edge edge-TRUE">
216
217<path fill="none" d="M646.51,-48.62C643.79,-56.54 640.22,-65.64 636.38,-74.54" class="edge-line"/>
218<polygon points="633.29,-72.88 632.41,-83.44 639.68,-75.73 633.29,-72.88" class="edge-line edge-arrow"/>
219<text text-anchor="middle" x="656.03" y="-57.56" font-size="10.50">source</text>
220</g>
221<!-- n11&#45;&gt;n8 -->
222<g class="edge edge-TRUE">
223
224<path fill="none" d="M722.36,-48.62C708.84,-57.83 692.35,-68.64 676.28,-78.88" class="edge-line"/>
225<polygon points="674.75,-75.7 668.17,-84.01 678.5,-81.62 674.75,-75.7" class="edge-line edge-arrow"/>
226<text text-anchor="middle" x="711.22" y="-70.14" font-size="10.50">source</text>
227</g>
228</g>
229</svg> \ No newline at end of file
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/MultiplicityConstraintsInstance.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg
new file mode 100644
index 00000000..95ba8def
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg
@@ -0,0 +1,29 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="172pt" height="57pt" viewBox="-6 -6 184.24000549316406 68.79999923706055" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-8UTvxM6Gq4184FIveUdov"><style>.refinery-8UTvxM6Gq4184FIveUdov .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-8UTvxM6Gq4184FIveUdov .node .node-outline{stroke:#19202b;}.refinery-8UTvxM6Gq4184FIveUdov .node .node-header{fill:rgb(53, 161, 173);}.refinery-8UTvxM6Gq4184FIveUdov .node .node-bg{fill:#fff;}.refinery-8UTvxM6Gq4184FIveUdov .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-8UTvxM6Gq4184FIveUdov .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-8UTvxM6Gq4184FIveUdov .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-h .node-header{fill:#e06c75;}.refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-i .node-header{fill:#98c379;}.refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-j .node-header{fill:#c678dd;}.refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-n .node-header{fill:#abcc94;}.refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-8UTvxM6Gq4184FIveUdov .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-8UTvxM6Gq4184FIveUdov .edge .edge-line{stroke:#19202b;}.refinery-8UTvxM6Gq4184FIveUdov .edge .edge-arrow{fill:#19202b;}.refinery-8UTvxM6Gq4184FIveUdov .edge-UNKNOWN text{fill:#696c77;}.refinery-8UTvxM6Gq4184FIveUdov .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-8UTvxM6Gq4184FIveUdov .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-8UTvxM6Gq4184FIveUdov .edge-ERROR text{fill:#ca1243;}.refinery-8UTvxM6Gq4184FIveUdov .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-8UTvxM6Gq4184FIveUdov .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-8UTvxM6Gq4184FIveUdov .icon-TRUE{fill:#19202b;}.refinery-8UTvxM6Gq4184FIveUdov .icon-UNKNOWN{fill:#696c77;}.refinery-8UTvxM6Gq4184FIveUdov .icon-ERROR{fill:#ca1243;}.refinery-8UTvxM6Gq4184FIveUdov text.label-UNKNOWN{fill:#696c77;}.refinery-8UTvxM6Gq4184FIveUdov text.label-ERROR{fill:#ca1243;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-8UTvxM6Gq4184FIveUdov text.label-ERROR{fill:#e06c75;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-8UTvxM6Gq4184FIveUdov-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-8UTvxM6Gq4184FIveUdov-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-8UTvxM6Gq4184FIveUdov-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="translate(4, 52.79999923706055)">
4<!-- n0 -->
5<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-k"><rect stroke="none" x="5.5" y="-42.5" width="79" height="49" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
6
7<rect stroke="none" x="0" y="-48.8" width="78.19" height="48.8" rx="12" ry="12" class="node-bg"/>
8<rect stroke="none" x="-4" y="-52" width="86" height="27" clip-path="url(#refinery-8UTvxM6Gq4184FIveUdov-clip-0)" class="node-header"/>
9<text text-anchor="start" x="5" y="-33" font-size="12.00">Region::new</text>
10<use x="6" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-8UTvxM6Gq4184FIveUdov-icon-TRUE"/>
11<g><text text-anchor="start" x="22" y="-9.6" font-size="12.00" class="label label-TRUE">Region</text>
12</g>
13<polyline points="0,-25.4 78.19,-25.4" class="node-outline"/>
14<rect fill="none" x="0" y="-48.8" width="78.19" height="48.8" rx="12" ry="12" class="node-outline"/>
15<clipPath id="refinery-8UTvxM6Gq4184FIveUdov-clip-0"><rect stroke="none" x="0" y="-48.8" width="78.19" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
16<!-- n2 -->
17
18<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-h"><rect stroke="none" x="100.5" y="-42.5" width="69" height="49" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
19
20<rect stroke="none" x="95.95" y="-48.8" width="68.29" height="48.8" rx="12" ry="12" class="node-bg"/>
21<rect stroke="none" x="91" y="-52" width="76" height="27" clip-path="url(#refinery-8UTvxM6Gq4184FIveUdov-clip-1)" class="node-header"/>
22<text text-anchor="start" x="100.95" y="-33" font-size="12.00">State::new</text>
23
24
25
26
27<use x="101.954" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-8UTvxM6Gq4184FIveUdov-icon-TRUE"/><g><text text-anchor="start" x="117.95" y="-9.6" font-size="12.00" class="label label-TRUE">State</text>
28</g><polyline points="95.95,-25.4 164.24,-25.4" class="node-outline"/><rect fill="none" x="95.95" y="-48.8" width="68.29" height="48.8" rx="12" ry="12" class="node-outline"/><clipPath id="refinery-8UTvxM6Gq4184FIveUdov-clip-1"><rect stroke="none" x="95.95" y="-48.8" width="68.29" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g></g>
29</svg> \ No newline at end of file
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsSimple.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg
new file mode 100644
index 00000000..cdf365f0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg
@@ -0,0 +1,38 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="230pt" height="104pt" viewBox="-6 -6 242.10000610351562 116.4000015258789" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-snWM44tZVFiopoyqQzHDw"><style>.refinery-snWM44tZVFiopoyqQzHDw .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-snWM44tZVFiopoyqQzHDw .node .node-outline{stroke:#19202b;}.refinery-snWM44tZVFiopoyqQzHDw .node .node-header{fill:rgb(53, 161, 173);}.refinery-snWM44tZVFiopoyqQzHDw .node .node-bg{fill:#fff;}.refinery-snWM44tZVFiopoyqQzHDw .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-snWM44tZVFiopoyqQzHDw .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-snWM44tZVFiopoyqQzHDw .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-h .node-header{fill:#e06c75;}.refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-i .node-header{fill:#98c379;}.refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-j .node-header{fill:#c678dd;}.refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-n .node-header{fill:#abcc94;}.refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-snWM44tZVFiopoyqQzHDw .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-snWM44tZVFiopoyqQzHDw .edge .edge-line{stroke:#19202b;}.refinery-snWM44tZVFiopoyqQzHDw .edge .edge-arrow{fill:#19202b;}.refinery-snWM44tZVFiopoyqQzHDw .edge-UNKNOWN text{fill:#696c77;}.refinery-snWM44tZVFiopoyqQzHDw .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-snWM44tZVFiopoyqQzHDw .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-snWM44tZVFiopoyqQzHDw .edge-ERROR text{fill:#ca1243;}.refinery-snWM44tZVFiopoyqQzHDw .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-snWM44tZVFiopoyqQzHDw .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-snWM44tZVFiopoyqQzHDw .icon-TRUE{fill:#19202b;}.refinery-snWM44tZVFiopoyqQzHDw .icon-UNKNOWN{fill:#696c77;}.refinery-snWM44tZVFiopoyqQzHDw .icon-ERROR{fill:#ca1243;}.refinery-snWM44tZVFiopoyqQzHDw text.label-UNKNOWN{fill:#696c77;}.refinery-snWM44tZVFiopoyqQzHDw text.label-ERROR{fill:#ca1243;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-snWM44tZVFiopoyqQzHDw text.label-ERROR{fill:#e06c75;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-snWM44tZVFiopoyqQzHDw-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-snWM44tZVFiopoyqQzHDw-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-snWM44tZVFiopoyqQzHDw-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="translate(4, 100.4000015258789)">
4<!-- n0 -->
5<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-k"><rect stroke="none" x="5.5" y="-66.5" width="79" height="49" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
6
7<rect stroke="none" x="0" y="-72.6" width="78.19" height="48.8" rx="12" ry="12" class="node-bg"/>
8<rect stroke="none" x="-4" y="-76" width="86" height="27" clip-path="url(#refinery-snWM44tZVFiopoyqQzHDw-clip-0)" class="node-header"/>
9<text text-anchor="start" x="5" y="-56.8" font-size="12.00">Region::new</text>
10<use x="6" y="-43" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-snWM44tZVFiopoyqQzHDw-icon-TRUE"/>
11<g><text text-anchor="start" x="22" y="-33.4" font-size="12.00" class="label label-TRUE">Region</text>
12</g>
13<polyline points="0,-49.2 78.19,-49.2" class="node-outline"/>
14<rect fill="none" x="0" y="-72.6" width="78.19" height="48.8" rx="12" ry="12" class="node-outline"/>
15<clipPath id="refinery-snWM44tZVFiopoyqQzHDw-clip-0"><rect stroke="none" x="0" y="-72.6" width="78.19" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
16<!-- n1 -->
17<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-h"><rect stroke="none" x="101.5" y="-90.5" width="127" height="97" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
18
19<rect stroke="none" x="96.1" y="-96.4" width="126" height="96.4" rx="12" ry="12" class="node-bg"/>
20<rect stroke="none" x="92" y="-100" width="134" height="27" clip-path="url(#refinery-snWM44tZVFiopoyqQzHDw-clip-1)" class="node-header"/>
21<text text-anchor="start" x="129.95" y="-80.6" font-size="12.00">State::new</text>
22<use x="102.096" y="-67" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-snWM44tZVFiopoyqQzHDw-icon-TRUE"/>
23<g><text text-anchor="start" x="118.01" y="-58.2" font-style="italic" font-size="12.00" class="label label-TRUE">CompositeElement</text>
24</g>
25<use x="102.096" y="-51" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-snWM44tZVFiopoyqQzHDw-icon-TRUE"/>
26<g><text text-anchor="start" x="118.1" y="-42.2" font-style="italic" font-size="12.00" class="label label-TRUE">Vertex</text>
27</g>
28<use x="102.096" y="-35" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-snWM44tZVFiopoyqQzHDw-icon-TRUE"/>
29<g><text text-anchor="start" x="118.1" y="-26.2" font-style="italic" font-size="12.00" class="label label-TRUE">RegularState</text>
30</g>
31<use x="102.096" y="-19" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-snWM44tZVFiopoyqQzHDw-icon-TRUE"/>
32<g><text text-anchor="start" x="118.1" y="-9.2" font-size="12.00" class="label label-TRUE">State</text>
33</g>
34<polyline points="96.1,-73 222.1,-73" class="node-outline"/>
35<rect fill="none" x="96.1" y="-96.4" width="126" height="96.4" rx="12" ry="12" class="node-outline"/>
36<clipPath id="refinery-snWM44tZVFiopoyqQzHDw-clip-1"><rect stroke="none" x="96.1" y="-96.4" width="126" height="96.4" rx="12" ry="12" class="node-bg"/></clipPath></g>
37</g>
38</svg> \ No newline at end of file
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/NewObjectsWithInheritance.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg
new file mode 100644
index 00000000..56a4d956
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg
@@ -0,0 +1,69 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="236pt" height="142pt" viewBox="-6 -6 247.8800048828125 153.60000610351562" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-aUMOWvqBGMJmEq5FBgfQD"><style>.refinery-aUMOWvqBGMJmEq5FBgfQD .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-aUMOWvqBGMJmEq5FBgfQD .node .node-outline{stroke:#19202b;}.refinery-aUMOWvqBGMJmEq5FBgfQD .node .node-header{fill:rgb(53, 161, 173);}.refinery-aUMOWvqBGMJmEq5FBgfQD .node .node-bg{fill:#fff;}.refinery-aUMOWvqBGMJmEq5FBgfQD .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-aUMOWvqBGMJmEq5FBgfQD .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-aUMOWvqBGMJmEq5FBgfQD .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-h .node-header{fill:#e06c75;}.refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-i .node-header{fill:#98c379;}.refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-j .node-header{fill:#c678dd;}.refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-n .node-header{fill:#abcc94;}.refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-aUMOWvqBGMJmEq5FBgfQD .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-aUMOWvqBGMJmEq5FBgfQD .edge .edge-line{stroke:#19202b;}.refinery-aUMOWvqBGMJmEq5FBgfQD .edge .edge-arrow{fill:#19202b;}.refinery-aUMOWvqBGMJmEq5FBgfQD .edge-UNKNOWN text{fill:#696c77;}.refinery-aUMOWvqBGMJmEq5FBgfQD .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-aUMOWvqBGMJmEq5FBgfQD .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-aUMOWvqBGMJmEq5FBgfQD .edge-ERROR text{fill:#ca1243;}.refinery-aUMOWvqBGMJmEq5FBgfQD .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-aUMOWvqBGMJmEq5FBgfQD .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-aUMOWvqBGMJmEq5FBgfQD .icon-TRUE{fill:#19202b;}.refinery-aUMOWvqBGMJmEq5FBgfQD .icon-UNKNOWN{fill:#696c77;}.refinery-aUMOWvqBGMJmEq5FBgfQD .icon-ERROR{fill:#ca1243;}.refinery-aUMOWvqBGMJmEq5FBgfQD text.label-UNKNOWN{fill:#696c77;}.refinery-aUMOWvqBGMJmEq5FBgfQD text.label-ERROR{fill:#ca1243;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-aUMOWvqBGMJmEq5FBgfQD text.label-ERROR{fill:#e06c75;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-aUMOWvqBGMJmEq5FBgfQD-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-aUMOWvqBGMJmEq5FBgfQD-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-aUMOWvqBGMJmEq5FBgfQD-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="translate(4, 137.60000610351562)">
4<!-- n0 -->
5
6<!-- n1 -->
7
8<!-- n1&#45;&gt;n0 -->
9<!-- n1&#45;&gt;n0 -->
10
11<!-- n1&#45;&gt;n0 -->
12
13<!-- n1&#45;&gt;n0 -->
14
15
16<!-- n3 -->
17<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
18
19<rect stroke="none" x="46.81" y="-133.6" width="64.03" height="48.8" rx="12" ry="12" class="node-bg"/>
20<rect stroke="none" x="42" y="-137" width="72" height="27" clip-path="url(#refinery-aUMOWvqBGMJmEq5FBgfQD-clip-0)" class="node-header"/>
21<text text-anchor="start" x="72.39" y="-117.8" font-size="12.00">v1</text>
22<use x="52.8135" y="-104" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-aUMOWvqBGMJmEq5FBgfQD-icon-TRUE"/>
23<g><text text-anchor="start" x="68.81" y="-94.4" font-size="12.00" class="label label-TRUE">Vertex</text>
24</g>
25<polyline points="46.81,-110.2 110.84,-110.2" class="node-outline"/>
26<rect fill="none" x="46.81" y="-133.6" width="64.03" height="48.8" rx="12" ry="12" class="node-outline"/>
27<clipPath id="refinery-aUMOWvqBGMJmEq5FBgfQD-clip-0"><rect stroke="none" x="46.81" y="-133.6" width="64.03" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
28<g class="edge edge-TRUE">
29
30<path fill="none" d="M114.46,-48.63C110.99,-56.83 106.51,-66.22 101.86,-75.08" class="edge-line"/>
31<polygon points="98.81,-73.35 97.1,-83.81 104.96,-76.7 98.81,-73.35" class="edge-line edge-arrow"/>
32<text text-anchor="middle" x="89.45" y="-70.24" font-size="10.50">source</text>
33</g><g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
34
35<rect stroke="none" x="128.81" y="-133.6" width="64.03" height="48.8" rx="12" ry="12" class="node-bg"/>
36<rect stroke="none" x="124" y="-137" width="72" height="27" clip-path="url(#refinery-aUMOWvqBGMJmEq5FBgfQD-clip-1)" class="node-header"/>
37<text text-anchor="start" x="154.39" y="-117.8" font-size="12.00">v2</text>
38<use x="134.814" y="-104" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-aUMOWvqBGMJmEq5FBgfQD-icon-TRUE"/>
39<g><text text-anchor="start" x="150.81" y="-94.4" font-size="12.00" class="label label-TRUE">Vertex</text>
40</g>
41<polyline points="128.81,-110.2 192.84,-110.2" class="node-outline"/>
42<rect fill="none" x="128.81" y="-133.6" width="64.03" height="48.8" rx="12" ry="12" class="node-outline"/>
43<clipPath id="refinery-aUMOWvqBGMJmEq5FBgfQD-clip-1"><rect stroke="none" x="128.81" y="-133.6" width="64.03" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g><g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
44
45<rect stroke="none" x="77.72" y="-48.8" width="84.22" height="48.8" rx="12" ry="12" class="node-bg"/>
46<rect stroke="none" x="73" y="-52" width="92" height="27" clip-path="url(#refinery-aUMOWvqBGMJmEq5FBgfQD-clip-2)" class="node-header"/>
47<text text-anchor="start" x="114.28" y="-33" font-size="12.00">t1</text>
48<use x="83.7178" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-aUMOWvqBGMJmEq5FBgfQD-icon-TRUE"/>
49<g><text text-anchor="start" x="99.72" y="-9.6" font-size="12.00" class="label label-TRUE">Transition</text>
50</g>
51<polyline points="77.72,-25.4 161.94,-25.4" class="node-outline"/>
52<rect fill="none" x="77.72" y="-48.8" width="84.22" height="48.8" rx="12" ry="12" class="node-outline"/>
53<clipPath id="refinery-aUMOWvqBGMJmEq5FBgfQD-clip-2"><rect stroke="none" x="77.72" y="-48.8" width="84.22" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g><g class="edge edge-TRUE">
54
55<path fill="none" d="M84.13,-85.14C87.58,-76.95 92.06,-67.57 96.71,-58.7" class="edge-line"/>
56<polygon points="99.76,-60.41 101.47,-49.96 93.61,-57.06 99.76,-60.41" class="edge-line edge-arrow"/>
57<text text-anchor="middle" x="46.32" y="-57.24" font-size="10.50">outgoingTransition</text>
58</g><g class="edge edge-TRUE">
59
60<path fill="none" d="M137.47,-48.63C142.07,-56.74 146.83,-66.01 150.92,-74.79" class="edge-line"/>
61<polygon points="147.65,-76.04 154.91,-83.75 154.04,-73.19 147.65,-76.04" class="edge-line edge-arrow"/>
62<text text-anchor="middle" x="132.53" y="-57.44" font-size="10.50">target</text>
63</g><g class="edge edge-TRUE">
64
65<path fill="none" d="M143.28,-85.14C138.68,-77.04 133.92,-67.77 129.82,-58.99" class="edge-line"/>
66<polygon points="133.08,-57.72 125.81,-50.01 126.69,-60.57 133.08,-57.72" class="edge-line edge-arrow"/>
67<text text-anchor="middle" x="180.75" y="-70.04" font-size="10.50">incomingTransition</text>
68</g></g>
69</svg> \ No newline at end of file
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeInstance.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg
new file mode 100644
index 00000000..81ab4a0c
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg
@@ -0,0 +1,24 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="117pt" height="57pt" viewBox="-6 -6 128.5 68.79999923706055" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-4mmABsPwhJURILrHpcKRU"><style>.refinery-4mmABsPwhJURILrHpcKRU .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-4mmABsPwhJURILrHpcKRU .node .node-outline{stroke:#19202b;}.refinery-4mmABsPwhJURILrHpcKRU .node .node-header{fill:rgb(53, 161, 173);}.refinery-4mmABsPwhJURILrHpcKRU .node .node-bg{fill:#fff;}.refinery-4mmABsPwhJURILrHpcKRU .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-4mmABsPwhJURILrHpcKRU .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-4mmABsPwhJURILrHpcKRU .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-h .node-header{fill:#e06c75;}.refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-i .node-header{fill:#98c379;}.refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-j .node-header{fill:#c678dd;}.refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-n .node-header{fill:#abcc94;}.refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-4mmABsPwhJURILrHpcKRU .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-4mmABsPwhJURILrHpcKRU .edge .edge-line{stroke:#19202b;}.refinery-4mmABsPwhJURILrHpcKRU .edge .edge-arrow{fill:#19202b;}.refinery-4mmABsPwhJURILrHpcKRU .edge-UNKNOWN text{fill:#696c77;}.refinery-4mmABsPwhJURILrHpcKRU .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-4mmABsPwhJURILrHpcKRU .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-4mmABsPwhJURILrHpcKRU .edge-ERROR text{fill:#ca1243;}.refinery-4mmABsPwhJURILrHpcKRU .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-4mmABsPwhJURILrHpcKRU .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-4mmABsPwhJURILrHpcKRU .icon-TRUE{fill:#19202b;}.refinery-4mmABsPwhJURILrHpcKRU .icon-UNKNOWN{fill:#696c77;}.refinery-4mmABsPwhJURILrHpcKRU .icon-ERROR{fill:#ca1243;}.refinery-4mmABsPwhJURILrHpcKRU text.label-UNKNOWN{fill:#696c77;}.refinery-4mmABsPwhJURILrHpcKRU text.label-ERROR{fill:#ca1243;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-4mmABsPwhJURILrHpcKRU text.label-ERROR{fill:#e06c75;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-4mmABsPwhJURILrHpcKRU-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-4mmABsPwhJURILrHpcKRU-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-4mmABsPwhJURILrHpcKRU-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="translate(4, 52.79999923706055)">
4<!-- n0 -->
5<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-p"><rect stroke="none" x="5.5" y="-42.5" width="80" height="49" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
6
7<rect stroke="none" x="0" y="-48.8" width="79.01" height="48.8" rx="12" ry="12" class="node-bg"/>
8<rect stroke="none" x="-4" y="-52" width="87" height="27" clip-path="url(#refinery-4mmABsPwhJURILrHpcKRU-clip-0)" class="node-header"/>
9<text text-anchor="start" x="5" y="-33" font-size="12.00">Person::new</text>
10<use x="6" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-4mmABsPwhJURILrHpcKRU-icon-TRUE"/>
11<g><text text-anchor="start" x="22" y="-9.6" font-size="12.00" class="label label-TRUE">Person</text>
12</g>
13<polyline points="0,-25.4 79.01,-25.4" class="node-outline"/>
14<rect fill="none" x="0" y="-48.8" width="79.01" height="48.8" rx="12" ry="12" class="node-outline"/>
15<clipPath id="refinery-4mmABsPwhJURILrHpcKRU-clip-0"><rect stroke="none" x="0" y="-48.8" width="79.01" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
16<!-- n0&#45;&gt;n0 -->
17<g class="edge edge-UNKNOWN">
18
19<path fill="none" stroke-dasharray="5,2" d="M78.75,-33.47C89.14,-32.95 97.01,-29.93 97.01,-24.4 97.01,-21.12 94.24,-18.72 89.81,-17.2" class="edge-line"/>
20<polygon points="90.68,-13.8 80.24,-15.58 89.52,-20.7 90.68,-13.8" class="edge-line edge-arrow"/>
21<text text-anchor="middle" x="93.87" y="-36.59" font-size="10.50">friend</text>
22</g>
23</g>
24</svg> \ No newline at end of file
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesOppositeSelf.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg
new file mode 100644
index 00000000..fac74815
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg
@@ -0,0 +1,43 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="104pt" height="142pt" viewBox="-6 -6 116.04000091552734 153.60000610351562" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-KS4S5srdaYqLoF1P1dM89"><style>.refinery-KS4S5srdaYqLoF1P1dM89 .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-KS4S5srdaYqLoF1P1dM89 .node .node-outline{stroke:#19202b;}.refinery-KS4S5srdaYqLoF1P1dM89 .node .node-header{fill:rgb(53, 161, 173);}.refinery-KS4S5srdaYqLoF1P1dM89 .node .node-bg{fill:#fff;}.refinery-KS4S5srdaYqLoF1P1dM89 .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-KS4S5srdaYqLoF1P1dM89 .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-KS4S5srdaYqLoF1P1dM89 .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-h .node-header{fill:#e06c75;}.refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-i .node-header{fill:#98c379;}.refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-j .node-header{fill:#c678dd;}.refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-n .node-header{fill:#abcc94;}.refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-KS4S5srdaYqLoF1P1dM89 .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-KS4S5srdaYqLoF1P1dM89 .edge .edge-line{stroke:#19202b;}.refinery-KS4S5srdaYqLoF1P1dM89 .edge .edge-arrow{fill:#19202b;}.refinery-KS4S5srdaYqLoF1P1dM89 .edge-UNKNOWN text{fill:#696c77;}.refinery-KS4S5srdaYqLoF1P1dM89 .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-KS4S5srdaYqLoF1P1dM89 .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-KS4S5srdaYqLoF1P1dM89 .edge-ERROR text{fill:#ca1243;}.refinery-KS4S5srdaYqLoF1P1dM89 .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-KS4S5srdaYqLoF1P1dM89 .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-KS4S5srdaYqLoF1P1dM89 .icon-TRUE{fill:#19202b;}.refinery-KS4S5srdaYqLoF1P1dM89 .icon-UNKNOWN{fill:#696c77;}.refinery-KS4S5srdaYqLoF1P1dM89 .icon-ERROR{fill:#ca1243;}.refinery-KS4S5srdaYqLoF1P1dM89 text.label-UNKNOWN{fill:#696c77;}.refinery-KS4S5srdaYqLoF1P1dM89 text.label-ERROR{fill:#ca1243;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-KS4S5srdaYqLoF1P1dM89 text.label-ERROR{fill:#e06c75;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-KS4S5srdaYqLoF1P1dM89-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-KS4S5srdaYqLoF1P1dM89-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-KS4S5srdaYqLoF1P1dM89-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="translate(4, 137.60000610351562)">
4<!-- n0 -->
5<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-h"><rect stroke="none" x="15.5" y="-42.5" width="76" height="49" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
6
7<rect stroke="none" x="10.1" y="-48.8" width="75.84" height="48.8" rx="12" ry="12" class="node-bg"/>
8<rect stroke="none" x="6" y="-52" width="83" height="27" clip-path="url(#refinery-KS4S5srdaYqLoF1P1dM89-clip-0)" class="node-header"/>
9<text text-anchor="start" x="15.1" y="-33" font-size="12.00">Vertex::new</text>
10<use x="16.0957" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-KS4S5srdaYqLoF1P1dM89-icon-TRUE"/>
11<g><text text-anchor="start" x="32.1" y="-9.6" font-size="12.00" class="label label-TRUE">Vertex</text>
12</g>
13<polyline points="10.1,-25.4 85.94,-25.4" class="node-outline"/>
14<rect fill="none" x="10.1" y="-48.8" width="75.84" height="48.8" rx="12" ry="12" class="node-outline"/>
15<clipPath id="refinery-KS4S5srdaYqLoF1P1dM89-clip-0"><rect stroke="none" x="10.1" y="-48.8" width="75.84" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
16<!-- n1 -->
17<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-i"><rect stroke="none" x="5.5" y="-127.5" width="97" height="49" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
18
19<rect stroke="none" x="0" y="-133.6" width="96.04" height="48.8" rx="12" ry="12" class="node-bg"/>
20<rect stroke="none" x="-4" y="-137" width="104" height="27" clip-path="url(#refinery-KS4S5srdaYqLoF1P1dM89-clip-1)" class="node-header"/>
21<text text-anchor="start" x="5" y="-117.8" font-size="12.00">Transition::new</text>
22<use x="6" y="-104" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-KS4S5srdaYqLoF1P1dM89-icon-TRUE"/>
23<g><text text-anchor="start" x="22" y="-94.4" font-size="12.00" class="label label-TRUE">Transition</text>
24</g>
25<polyline points="0,-110.2 96.04,-110.2" class="node-outline"/>
26<rect fill="none" x="0" y="-133.6" width="96.04" height="48.8" rx="12" ry="12" class="node-outline"/>
27<clipPath id="refinery-KS4S5srdaYqLoF1P1dM89-clip-1"><rect stroke="none" x="0" y="-133.6" width="96.04" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
28<!-- n1&#45;&gt;n0 -->
29<g class="edge edge-UNKNOWN">
30
31<path fill="none" stroke-dasharray="5,2" d="M41.9,-85.14C41.32,-77.31 41.14,-68.38 41.35,-59.86" class="edge-line"/>
32<polygon points="44.84,-60.29 41.81,-50.14 37.85,-59.96 44.84,-60.29" class="edge-line edge-arrow"/>
33<text text-anchor="middle" x="24.78" y="-70.26" font-size="10.50">source</text>
34</g>
35<!-- n1&#45;&gt;n0 -->
36<g class="edge edge-UNKNOWN">
37
38<path fill="none" stroke-dasharray="5,2" d="M54.14,-85.14C54.71,-77.31 54.9,-68.38 54.68,-59.86" class="edge-line"/>
39<polygon points="58.19,-59.96 54.23,-50.14 51.2,-60.29 58.19,-59.96" class="edge-line edge-arrow"/>
40<text text-anchor="middle" x="40.18" y="-57.66" font-size="10.50">target</text>
41</g>
42</g>
43</svg> \ No newline at end of file
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/ReferencesSimple.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/index.md b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/index.md
new file mode 100644
index 00000000..18cbbf9f
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/classes/index.md
@@ -0,0 +1,213 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4description: Metamodeling in Refinery
5sidebar_position: 0
6---
7
8# Classes and references
9
10Refinery supports _metamodeling_ to describe the desired structure of generated models.
11
12The metamodeling facilities are inspired by object-oriented software and the [Eclipse Modeling Foundation](https://eclipse.dev/modeling/emf/) (EMF) Core, a lightweight framework for data models.
13The textual syntax in Refinery for defining metamodels is largely compatible with [Xcore](https://wiki.eclipse.org/Xcore), a textual syntax for EMF metamodels.
14
15## Classes
16
17Classes are declared with the `class` keyword.
18
19Like in many programming languages, class members are specified between curly braces `{}`.
20If a class has no members, the declaration may be terminated with a `.` instead.
21
22```refinery
23% Class with no members.
24class Region {}
25
26% Alternative syntax without curly braces.
27class State.
28```
29
30By default, a _new object_ is added to the partial model to represent the instances of a class.
31For example, the new objects `Region::new` and `State::new` represent potential instances of the classes `Region` and `State`, respectively:
32
33import NewObjectsSimple from './NewObjectsSimple.svg';
34
35<NewObjectsSimple />
36
37As you can see, no new objects represent potential nodes that are instanceof of both `Region` and `State`.
38In fact, such instances are not permitted at all.
39Each node must the instance of a _single most-specific class:_
40
41import InvalidInstance from './InvalidInstance.svg';
42
43<InvalidInstance />
44
45### Inheritance
46
47Like in object-oriented programming languages, classes may declare _superclasses_ with the `extends` keyword.
48The inheritance hierarchy may not contain any cycles (a class cannot be a superclass of itself), but _multiple inheritance_ is allowed.
49
50Classes that can't be instantiated directly (i.e., a subclass must be instantiated instead) can be marked with the `abstract` keyword.
51Such classes do not have a _new object,_ since there are no direct instances to represent.
52
53```refinery
54abstract class CompositeElement.
55class Region.
56abstract class Vertex.
57abstract class RegularState extends Vertex.
58class State extends RegularState, CompositeElement.
59```
60
61Notice that the new object `State::new` is an instance of `CompositeElement`, `Vertex`, `RegularState`, and `State` as well.
62
63import NewObjectsWithInheritance from './NewObjectsWithInheritance.svg';
64
65<NewObjectsWithInheritance />
66
67## References
68
69The graph structure of model generated by Refinery is determined by the _references_ of the metamodel, which will appear as labeled edges between nodes (class instances).
70
71References are declared as class members by providing the _target type,_ and optional _multiplicity,_ and the name of the reference:
72
73```refinery
74class Vertex.
75class Transition {
76 Vertex[1] source
77 Vertex[1] target
78}
79```
80
81import ReferencesSimple from './ReferencesSimple.svg';
82
83<ReferencesSimple />
84
85You may add the `refers` keyword for compatibility with [Xcore](https://wiki.eclipse.org/Xcore). The following specification is equivalent:
86
87```refinery
88class Vertex.
89class Transition {
90 refers Vertex[1] source
91 refers Vertex[1] target
92}
93```
94
95### Opposite constraints
96
97The `opposite` keywords specifies that two references are in an _opposite_ relationship, i.e., if one reference is present in a direction, the other must be present between the same nodes in the opposite direction.
98
99```
100class Vertex {
101 Transition[] outgoingTransition opposite source
102 Transition[] incomingTransition opposite target
103}
104class Transition {
105 Vertex[1] source opposite outgoingTransition
106 Vertex[1] target opposite incomingTransition
107}
108```
109
110import ReferencesOppositeInstance from './ReferencesOppositeInstance.svg';
111
112<ReferencesOppositeInstance />
113
114Opposites must be declared in pairs: it is a specification error to declare the `opposite` for one direction but not the other.
115
116Unlike in EMF, references that are the `opposite` of themselves are also supported.
117These must always be present in both directions between two nodes.
118Thus, they correspond to undirected graph edges.
119
120```refinery
121class Person {
122 Person[] friend opposite friend
123}
124```
125
126import ReferencesOppositeSelf from './ReferencesOppositeSelf.svg';
127
128<ReferencesOppositeSelf />
129
130### Multiplicity
131
132_Multiplicity constraints_ can be provided after the reference type in square braces.
133They specify how many _outgoing_ references should exist for any given instance of the class.
134
135:::info
136
137To control the number of _incoming_ references, add an `opposite` reference with multiplicity constraint.
138
139:::
140
141A multiplicity constraint is of the form `[n..m]`, where the non-negative integer `n` is the _lower_ bound of outgoing references,
142and `m` is a positive integer or `*` corresponding to the _upper_ bound of outgoing references.
143The value of `*` represent a reference with _unbounded_ upper multiplicity.
144
145If `n` = `m`, the shorter form `[n]` may be used.
146The bound `[0..*]` may be abbreviated as `[]`.
147If the multiplicity constraint is omitted, the bound `[0..1]` is assumed.
148
149---
150
151In the following model, the node `v1` satisfies all multiplicity constraints of `outgoingTransition`.
152The node `v2` violates the lower bound constraint, while `v3` violates the upper bound constraint.
153All `Transition` instances satisfy the multiplicity constraints associated with `source`.
154
155```refinery
156class Vertex {
157 Transition[2..3] outgoingTransition opposite source
158}
159class Transition {
160 Vertex[1] source opposite outgoingTransition
161}
162```
163
164import MultiplicityConstraintsInstance from './MultiplicityConstraintsInstance.svg';
165
166<MultiplicityConstraintsInstance />
167
168### Containment hierarchy
169
170To structure models and ensure their connectedness, Refinery supports _containment_ constraints.
171
172References may be marked as _containment_ references with the `contains` keyword.
173
174Classes that are the _target type_ of at least one _containment_ reference are considered `contained`.
175An instance of a `contained` class must have exactly 1 incoming containment reference.
176Instances of classes that are not `contained` must _not_ have any incoming containment references.
177
178Containment references have to form a _forest_, i.e., they must not contain any cycles.
179The _roots_ of the forest are instances of classes that are not `contained`, while `contained` classes for the internal nodes and leaves of the trees.
180
181Opposites of _containment_ references have to be marked with the `container` keyword.
182They must not specify any multiplicity constraint, since the multiplicity is already implied by the containment hierarchy.
183
184---
185
186In the following model, the instances of `Region` are the roots of the containment hierarchy.
187The classes `Vertex` are `Transition` are both considered `contained`.
188
189```refinery
190class Region {
191 contains Vertex[] vertices opposite region
192}
193
194class Vertex {
195 container Region region opposite vertices
196 contains Transition[] outgoingTransition opposite source
197 Transition[] incomingTransition opposite target
198}
199
200class Transition {
201 container Vertex source opposite outgoingTransition
202 Vertex[1] target opposite incomingTransition
203}
204```
205
206Containment edges are show with **thick** lines:
207
208import ContainmentInstance from './ContainmentInstance.svg';
209
210<ContainmentInstance />
211
212Containment edges form must form a forest.
213In contrast, non-containment references, such as `target`, may cross the containment hierarchy.
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg
new file mode 100644
index 00000000..8ddc65f3
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg
@@ -0,0 +1,20 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="72pt" height="72pt" viewBox="-6 -6 84 84.4000015258789" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-t1ihtn3yDar9Rl2Fph8SJ"><style>.refinery-t1ihtn3yDar9Rl2Fph8SJ .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node .node-outline{stroke:#19202b;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node .node-header{fill:rgb(53, 161, 173);}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node .node-bg{fill:#fff;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-h .node-header{fill:#e06c75;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-i .node-header{fill:#98c379;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-j .node-header{fill:#c678dd;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-n .node-header{fill:#abcc94;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .edge .edge-line{stroke:#19202b;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .edge .edge-arrow{fill:#19202b;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .edge-UNKNOWN text{fill:#696c77;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .edge-ERROR text{fill:#ca1243;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .icon-TRUE{fill:#19202b;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .icon-UNKNOWN{fill:#696c77;}.refinery-t1ihtn3yDar9Rl2Fph8SJ .icon-ERROR{fill:#ca1243;}.refinery-t1ihtn3yDar9Rl2Fph8SJ text.label-UNKNOWN{fill:#696c77;}.refinery-t1ihtn3yDar9Rl2Fph8SJ text.label-ERROR{fill:#ca1243;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-t1ihtn3yDar9Rl2Fph8SJ text.label-ERROR{fill:#e06c75;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-t1ihtn3yDar9Rl2Fph8SJ-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-t1ihtn3yDar9Rl2Fph8SJ-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-t1ihtn3yDar9Rl2Fph8SJ-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="translate(4, 68.4000015258789)">
4<!-- n3 -->
5<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE">
6
7<rect stroke="none" x="0" y="-64.4" width="64" height="64.4" rx="12" ry="12" class="node-bg"/>
8<rect stroke="none" x="-4" y="-68" width="72" height="27" clip-path="url(#refinery-t1ihtn3yDar9Rl2Fph8SJ-clip-0)" class="node-header"/>
9<text text-anchor="start" x="25.56" y="-48.6" font-size="12.00">v1</text>
10
11
12<use x="6" y="-35" width="12" height="12" id="" class="icon icon-ERROR" href="#refinery-t1ihtn3yDar9Rl2Fph8SJ-icon-ERROR"/>
13<g><text text-anchor="start" x="21.99" y="-25.2" font-size="12.00" class="label label-ERROR">Vertex</text>
14</g>
15<use x="6" y="-19" width="12" height="12" id="" class="icon icon-ERROR" href="#refinery-t1ihtn3yDar9Rl2Fph8SJ-icon-ERROR"/>
16<g><text text-anchor="start" x="22" y="-9.2" font-size="12.00" class="label label-ERROR">State</text>
17</g>
18<polyline points="0,-41 64,-41" class="node-outline"/><rect fill="none" x="0" y="-64.4" width="64" height="64.4" rx="12" ry="12" class="node-outline"/><clipPath id="refinery-t1ihtn3yDar9Rl2Fph8SJ-clip-0"><rect stroke="none" x="0" y="-64.4" width="64" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g>
19</g>
20</svg> \ No newline at end of file
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsError.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg
new file mode 100644
index 00000000..26b3d1ff
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg
@@ -0,0 +1,99 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="250pt" height="157pt" viewBox="-6 -6 262.17999267578125 169.1999969482422" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-yow0X_ZN3HQDi30KE0Sac"><style>.refinery-yow0X_ZN3HQDi30KE0Sac .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-yow0X_ZN3HQDi30KE0Sac .node .node-outline{stroke:#19202b;}.refinery-yow0X_ZN3HQDi30KE0Sac .node .node-header{fill:rgb(53, 161, 173);}.refinery-yow0X_ZN3HQDi30KE0Sac .node .node-bg{fill:#fff;}.refinery-yow0X_ZN3HQDi30KE0Sac .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-yow0X_ZN3HQDi30KE0Sac .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-yow0X_ZN3HQDi30KE0Sac .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-h .node-header{fill:#e06c75;}.refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-i .node-header{fill:#98c379;}.refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-j .node-header{fill:#c678dd;}.refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-n .node-header{fill:#abcc94;}.refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-yow0X_ZN3HQDi30KE0Sac .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-yow0X_ZN3HQDi30KE0Sac .edge .edge-line{stroke:#19202b;}.refinery-yow0X_ZN3HQDi30KE0Sac .edge .edge-arrow{fill:#19202b;}.refinery-yow0X_ZN3HQDi30KE0Sac .edge-UNKNOWN text{fill:#696c77;}.refinery-yow0X_ZN3HQDi30KE0Sac .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-yow0X_ZN3HQDi30KE0Sac .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-yow0X_ZN3HQDi30KE0Sac .edge-ERROR text{fill:#ca1243;}.refinery-yow0X_ZN3HQDi30KE0Sac .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-yow0X_ZN3HQDi30KE0Sac .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-yow0X_ZN3HQDi30KE0Sac .icon-TRUE{fill:#19202b;}.refinery-yow0X_ZN3HQDi30KE0Sac .icon-UNKNOWN{fill:#696c77;}.refinery-yow0X_ZN3HQDi30KE0Sac .icon-ERROR{fill:#ca1243;}.refinery-yow0X_ZN3HQDi30KE0Sac text.label-UNKNOWN{fill:#696c77;}.refinery-yow0X_ZN3HQDi30KE0Sac text.label-ERROR{fill:#ca1243;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-yow0X_ZN3HQDi30KE0Sac text.label-ERROR{fill:#e06c75;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-yow0X_ZN3HQDi30KE0Sac-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-yow0X_ZN3HQDi30KE0Sac-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-yow0X_ZN3HQDi30KE0Sac-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="translate(4, 153.1999969482422)">
4<!-- n3 -->
5<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-k"><rect stroke="none" x="6.5" y="-143.5" width="79" height="49" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
6
7<rect stroke="none" x="1.07" y="-149.2" width="78.19000000000001" height="48.79999999999998" rx="12" ry="12" class="node-bg"/>
8<rect stroke="none" x="-3" y="-153" width="86" height="27" clip-path="url(#refinery-yow0X_ZN3HQDi30KE0Sac-clip-0)" class="node-header"/>
9<text text-anchor="start" x="6.07" y="-133.4" font-size="12.00">Region::new</text>
10<use x="7.07291" y="-119.6" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-yow0X_ZN3HQDi30KE0Sac-icon-TRUE"/>
11<g><text text-anchor="start" x="23.07" y="-110" font-size="12.00" class="label label-TRUE">Region</text>
12</g>
13<polyline points="1.07,-125.8 79.26,-125.8" class="node-outline"/>
14<rect fill="none" x="1.07" y="-149.2" width="78.19000000000001" height="48.79999999999998" rx="12" ry="12" class="node-outline"/>
15<clipPath id="refinery-yow0X_ZN3HQDi30KE0Sac-clip-0"><rect stroke="none" x="1.07" y="-149.2" width="78.19000000000001" height="48.79999999999998" rx="12" ry="12" class="node-bg"/></clipPath></g>
16<!-- n4 -->
17<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-j"><rect stroke="none" x="14.5" y="-58.5" width="69" height="65" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
18
19<rect stroke="none" x="9.03" y="-64.4" width="68.28" height="64.4" rx="12" ry="12" class="node-bg"/>
20<rect stroke="none" x="5" y="-68" width="76" height="27" clip-path="url(#refinery-yow0X_ZN3HQDi30KE0Sac-clip-1)" class="node-header"/>
21<text text-anchor="start" x="14.03" y="-48.6" font-size="12.00">State::new</text>
22<use x="15.027" y="-35" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-yow0X_ZN3HQDi30KE0Sac-icon-TRUE"/>
23<g><text text-anchor="start" x="31.01" y="-25.2" font-size="12.00" class="label label-TRUE">Vertex</text>
24</g>
25<use x="15.027" y="-19" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-yow0X_ZN3HQDi30KE0Sac-icon-TRUE"/>
26<g><text text-anchor="start" x="31.03" y="-9.2" font-size="12.00" class="label label-TRUE">State</text>
27</g>
28<polyline points="9.03,-41 77.31,-41" class="node-outline"/>
29<rect fill="none" x="9.03" y="-64.4" width="68.28" height="64.4" rx="12" ry="12" class="node-outline"/>
30<clipPath id="refinery-yow0X_ZN3HQDi30KE0Sac-clip-1"><rect stroke="none" x="9.03" y="-64.4" width="68.28" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g>
31<!-- n3&#45;&gt;n4 -->
32<g class="edge edge-UNKNOWN">
33
34<path fill="none" stroke-width="2" stroke-dasharray="5,2" d="M40.94,-100.47C41.19,-92.98 41.47,-84.45 41.75,-76.02" class="edge-line"/>
35<polygon stroke-width="2" points="44.81,-76.18 42.04,-67.34 38.69,-75.98 44.81,-76.18" class="edge-line edge-arrow"/>
36<text text-anchor="start" x="0" y="-86.89" font-weight="bold" font-size="10.50">vertices</text>
37</g>
38<!-- n8 -->
39<!-- n4 -->
40<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
41
42<rect stroke="none" x="96.17" y="-64.4" width="63.999999999999986" height="64.4" rx="12" ry="12" class="node-bg"/>
43<rect stroke="none" x="92" y="-68" width="71" height="27" clip-path="url(#refinery-yow0X_ZN3HQDi30KE0Sac-clip-2)" class="node-header"/>
44<text text-anchor="start" x="121.73" y="-48.6" font-size="12.00">v1</text>
45<use x="102.169" y="-35" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-yow0X_ZN3HQDi30KE0Sac-icon-TRUE"/>
46<g><text text-anchor="start" x="118.15" y="-25.2" font-size="12.00" class="label label-TRUE">Vertex</text>
47</g>
48<use x="102.169" y="-19" width="12" height="12" id="" class="icon icon-UNKNOWN" href="#refinery-yow0X_ZN3HQDi30KE0Sac-icon-UNKNOWN"/>
49<g><text text-anchor="start" x="118.17" y="-9.2" font-size="12.00" class="label label-UNKNOWN">State</text>
50</g>
51<polyline points="96.17,-41 160.17,-41" class="node-outline"/>
52<rect fill="none" x="96.17" y="-64.4" width="63.999999999999986" height="64.4" rx="12" ry="12" class="node-outline"/>
53<clipPath id="refinery-yow0X_ZN3HQDi30KE0Sac-clip-2"><rect stroke="none" x="96.17" y="-64.4" width="63.999999999999986" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g><!-- n0&#45;&gt;n3 -->
54<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-k">
55
56<rect stroke="none" x="96.98" y="-149.2" width="66.38000000000001" height="48.79999999999998" rx="12" ry="12" class="node-bg"/>
57<rect stroke="none" x="92" y="-153" width="74" height="27" clip-path="url(#refinery-yow0X_ZN3HQDi30KE0Sac-clip-3)" class="node-header"/>
58<text text-anchor="start" x="124.29" y="-133.4" font-size="12.00">r1</text>
59<use x="102.982" y="-119.6" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-yow0X_ZN3HQDi30KE0Sac-icon-TRUE"/>
60<g><text text-anchor="start" x="118.98" y="-110" font-size="12.00" class="label label-TRUE">Region</text>
61</g>
62<polyline points="96.98,-125.8 163.36,-125.8" class="node-outline"/>
63<rect fill="none" x="96.98" y="-149.2" width="66.38000000000001" height="48.79999999999998" rx="12" ry="12" class="node-outline"/>
64<clipPath id="refinery-yow0X_ZN3HQDi30KE0Sac-clip-3"><rect stroke="none" x="96.98" y="-149.2" width="66.38000000000001" height="48.79999999999998" rx="12" ry="12" class="node-bg"/></clipPath></g><g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
65
66<rect stroke="none" x="178.15" y="-56.6" width="64.03" height="48.800000000000004" rx="12" ry="12" class="node-bg"/>
67<rect stroke="none" x="174" y="-60" width="72" height="27" clip-path="url(#refinery-yow0X_ZN3HQDi30KE0Sac-clip-4)" class="node-header"/>
68<text text-anchor="start" x="203.73" y="-40.8" font-size="12.00">v2</text>
69<use x="184.154" y="-27" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-yow0X_ZN3HQDi30KE0Sac-icon-TRUE"/>
70<g><text text-anchor="start" x="200.15" y="-17.4" font-size="12.00" class="label label-TRUE">Vertex</text>
71</g>
72
73
74<polyline points="178.15,-33.2 242.18,-33.2" class="node-outline"/><rect fill="none" x="178.15" y="-56.6" width="64.03" height="48.800000000000004" rx="12" ry="12" class="node-outline"/><clipPath id="refinery-yow0X_ZN3HQDi30KE0Sac-clip-4"><rect stroke="none" x="178.15" y="-56.6" width="64.03" height="48.800000000000004" rx="12" ry="12" class="node-bg"/></clipPath></g>
75<g class="edge edge-UNKNOWN">
76
77<path fill="none" stroke-width="2" stroke-dasharray="5,2" d="M107.76,-100.47C99.59,-91.95 90.1,-82.07 80.95,-72.55" class="edge-line"/>
78<polygon stroke-width="2" points="83.41,-70.68 75.14,-66.49 78.99,-74.93 83.41,-70.68" class="edge-line edge-arrow"/>
79<text text-anchor="start" x="48.91" y="-86.57" font-weight="bold" font-size="10.50">vertices</text>
80</g>
81<!-- n2&#45;&gt;n0 -->
82
83<!-- n3&#45;&gt;n0 -->
84
85<!-- n3&#45;&gt;n4 -->
86
87<g class="edge edge-TRUE">
88
89<path fill="none" stroke-width="2" d="M129.65,-100.47C129.49,-92.98 129.3,-84.45 129.11,-76.02" class="edge-line"/>
90<polygon stroke-width="2" points="132.18,-76.02 128.92,-67.34 126.05,-76.15 132.18,-76.02" class="edge-line edge-arrow"/>
91<text text-anchor="start" x="129.26" y="-86.89" font-weight="bold" font-size="10.50">vertices</text>
92</g>
93<g class="edge edge-TRUE">
94
95<path fill="none" stroke-width="2" d="M150.77,-100.47C160.29,-89.69 171.74,-76.72 182.04,-65.06" class="edge-line"/>
96<polygon stroke-width="2" points="184.14,-67.31 187.63,-58.72 179.55,-63.25 184.14,-67.31" class="edge-line edge-arrow"/>
97<text text-anchor="start" x="128.85" y="-69.81" font-weight="bold" font-size="10.50">vertices</text>
98</g></g>
99</svg> \ No newline at end of file
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/AssertionsExample.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg
new file mode 100644
index 00000000..2ab002bf
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg
@@ -0,0 +1,129 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="327pt" height="157pt" viewBox="-6 -6 339.3299865722656 169.1999969482422" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-p_2c2ycZZXd-I3Xg-BBah"><style>.refinery-p_2c2ycZZXd-I3Xg-BBah .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-p_2c2ycZZXd-I3Xg-BBah .node .node-outline{stroke:#19202b;}.refinery-p_2c2ycZZXd-I3Xg-BBah .node .node-header{fill:rgb(53, 161, 173);}.refinery-p_2c2ycZZXd-I3Xg-BBah .node .node-bg{fill:#fff;}.refinery-p_2c2ycZZXd-I3Xg-BBah .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-p_2c2ycZZXd-I3Xg-BBah .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-p_2c2ycZZXd-I3Xg-BBah .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-h .node-header{fill:#e06c75;}.refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-i .node-header{fill:#98c379;}.refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-j .node-header{fill:#c678dd;}.refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-n .node-header{fill:#abcc94;}.refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-p_2c2ycZZXd-I3Xg-BBah .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-p_2c2ycZZXd-I3Xg-BBah .edge .edge-line{stroke:#19202b;}.refinery-p_2c2ycZZXd-I3Xg-BBah .edge .edge-arrow{fill:#19202b;}.refinery-p_2c2ycZZXd-I3Xg-BBah .edge-UNKNOWN text{fill:#696c77;}.refinery-p_2c2ycZZXd-I3Xg-BBah .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-p_2c2ycZZXd-I3Xg-BBah .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-p_2c2ycZZXd-I3Xg-BBah .edge-ERROR text{fill:#ca1243;}.refinery-p_2c2ycZZXd-I3Xg-BBah .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-p_2c2ycZZXd-I3Xg-BBah .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-p_2c2ycZZXd-I3Xg-BBah .icon-TRUE{fill:#19202b;}.refinery-p_2c2ycZZXd-I3Xg-BBah .icon-UNKNOWN{fill:#696c77;}.refinery-p_2c2ycZZXd-I3Xg-BBah .icon-ERROR{fill:#ca1243;}.refinery-p_2c2ycZZXd-I3Xg-BBah text.label-UNKNOWN{fill:#696c77;}.refinery-p_2c2ycZZXd-I3Xg-BBah text.label-ERROR{fill:#ca1243;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-p_2c2ycZZXd-I3Xg-BBah text.label-ERROR{fill:#e06c75;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-p_2c2ycZZXd-I3Xg-BBah-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-p_2c2ycZZXd-I3Xg-BBah-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-p_2c2ycZZXd-I3Xg-BBah-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="scale(1 1) rotate(0) translate(4 153.2)">
4<!-- n0 -->
5
6<!-- n2 -->
7<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-j"><rect stroke="none" x="5.5" y="-58.5" width="69" height="65" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
8
9<rect stroke="none" x="0" y="-64.4" width="68.28" height="64.4" rx="12" ry="12" class="node-bg"/>
10<rect stroke="none" x="-4" y="-68" width="76" height="27" clip-path="url(#refinery-p_2c2ycZZXd-I3Xg-BBah-clip-0)" class="node-header"/>
11<text text-anchor="start" x="5" y="-48.6" font-size="12.00">State::new</text>
12<use x="6" y="-35" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-p_2c2ycZZXd-I3Xg-BBah-icon-TRUE"/>
13<g><text text-anchor="start" x="21.99" y="-25.2" font-size="12.00" class="label label-TRUE">Vertex</text>
14</g>
15<use x="6" y="-19" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-p_2c2ycZZXd-I3Xg-BBah-icon-TRUE"/>
16<g><text text-anchor="start" x="22" y="-9.2" font-size="12.00" class="label label-TRUE">State</text>
17</g>
18<polyline points="0,-41 68.28,-41" class="node-outline"/>
19<rect fill="none" x="0" y="-64.4" width="68.28" height="64.4" rx="12" ry="12" class="node-outline"/>
20<clipPath id="refinery-p_2c2ycZZXd-I3Xg-BBah-clip-0"><rect stroke="none" x="0" y="-64.4" width="68.28" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g>
21<!-- n0&#45;&gt;n2 -->
22
23<!-- n3 -->
24<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-k">
25
26<rect stroke="none" x="84.96" y="-149.2" width="66.37000000000002" height="48.79999999999998" rx="12" ry="12" class="node-bg"/>
27<rect stroke="none" x="80" y="-153" width="74" height="27" clip-path="url(#refinery-p_2c2ycZZXd-I3Xg-BBah-clip-1)" class="node-header"/>
28<text text-anchor="start" x="112.26" y="-133.4" font-size="12.00">r1</text>
29<use x="90.9551" y="-119.6" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-p_2c2ycZZXd-I3Xg-BBah-icon-TRUE"/>
30<g><text text-anchor="start" x="106.96" y="-110" font-size="12.00" class="label label-TRUE">Region</text>
31</g>
32<polyline points="84.96,-125.8 151.33,-125.8" class="node-outline"/>
33<rect fill="none" x="84.96" y="-149.2" width="66.37000000000002" height="48.79999999999998" rx="12" ry="12" class="node-outline"/>
34<clipPath id="refinery-p_2c2ycZZXd-I3Xg-BBah-clip-1"><rect stroke="none" x="84.96" y="-149.2" width="66.37000000000002" height="48.79999999999998" rx="12" ry="12" class="node-bg"/></clipPath></g>
35<!-- n3&#45;&gt;n2 -->
36<g class="edge edge-UNKNOWN">
37
38<path fill="none" stroke-width="2" stroke-dasharray="5,2" d="M96.51,-100.47C88.69,-92.04 79.64,-82.27 70.89,-72.83" class="edge-line"/>
39<polygon stroke-width="2" points="73.24,-70.86 65.04,-66.53 68.75,-75.03 73.24,-70.86" class="edge-line edge-arrow"/>
40<text text-anchor="start" x="38.02" y="-86.32" font-weight="bold" font-size="10.50">vertices</text>
41</g>
42<!-- n4 -->
43<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
44
45<rect stroke="none" x="86.14" y="-64.4" width="63.999999999999986" height="64.4" rx="12" ry="12" class="node-bg"/>
46<rect stroke="none" x="82" y="-68" width="71" height="27" clip-path="url(#refinery-p_2c2ycZZXd-I3Xg-BBah-clip-2)" class="node-header"/>
47<text text-anchor="start" x="111.71" y="-48.6" font-size="12.00">v1</text>
48<use x="92.1416" y="-35" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-p_2c2ycZZXd-I3Xg-BBah-icon-TRUE"/>
49<g><text text-anchor="start" x="108.13" y="-25.2" font-size="12.00" class="label label-TRUE">Vertex</text>
50</g>
51<use x="92.1416" y="-19" width="12" height="12" id="" class="icon icon-UNKNOWN" href="#refinery-p_2c2ycZZXd-I3Xg-BBah-icon-UNKNOWN"/>
52<g><text text-anchor="start" x="108.14" y="-9.2" font-size="12.00" class="label label-UNKNOWN">State</text>
53</g>
54<polyline points="86.14,-41 150.14,-41" class="node-outline"/>
55<rect fill="none" x="86.14" y="-64.4" width="63.999999999999986" height="64.4" rx="12" ry="12" class="node-outline"/>
56<clipPath id="refinery-p_2c2ycZZXd-I3Xg-BBah-clip-2"><rect stroke="none" x="86.14" y="-64.4" width="63.999999999999986" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g>
57<!-- n3&#45;&gt;n4 -->
58<g class="edge edge-TRUE">
59
60<path fill="none" stroke-width="2" d="M118.14,-100.47C118.14,-92.98 118.14,-84.45 118.14,-76.02" class="edge-line"/>
61<polygon stroke-width="2" points="121.2,-76.09 118.14,-67.34 115.08,-76.09 121.2,-76.09" class="edge-line edge-arrow"/>
62<text text-anchor="start" x="118.14" y="-86.89" font-weight="bold" font-size="10.50">vertices</text>
63</g>
64<!-- n5 -->
65<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-k">
66
67<rect stroke="none" x="168.96" y="-149.2" width="66.37" height="48.79999999999998" rx="12" ry="12" class="node-bg"/>
68<rect stroke="none" x="164" y="-153" width="74" height="27" clip-path="url(#refinery-p_2c2ycZZXd-I3Xg-BBah-clip-3)" class="node-header"/>
69<text text-anchor="start" x="196.26" y="-133.4" font-size="12.00">r2</text>
70<use x="174.955" y="-119.6" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-p_2c2ycZZXd-I3Xg-BBah-icon-TRUE"/>
71<g><text text-anchor="start" x="190.96" y="-110" font-size="12.00" class="label label-TRUE">Region</text>
72</g>
73<polyline points="168.96,-125.8 235.33,-125.8" class="node-outline"/>
74<rect fill="none" x="168.96" y="-149.2" width="66.37" height="48.79999999999998" rx="12" ry="12" class="node-outline"/>
75<clipPath id="refinery-p_2c2ycZZXd-I3Xg-BBah-clip-3"><rect stroke="none" x="168.96" y="-149.2" width="66.37" height="48.79999999999998" rx="12" ry="12" class="node-bg"/></clipPath></g>
76<!-- n6 -->
77<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
78
79<rect stroke="none" x="170.14" y="-64.4" width="64" height="64.4" rx="12" ry="12" class="node-bg"/>
80<rect stroke="none" x="166" y="-68" width="72" height="27" clip-path="url(#refinery-p_2c2ycZZXd-I3Xg-BBah-clip-4)" class="node-header"/>
81<text text-anchor="start" x="195.71" y="-48.6" font-size="12.00">v2</text>
82<use x="176.142" y="-35" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-p_2c2ycZZXd-I3Xg-BBah-icon-TRUE"/>
83<g><text text-anchor="start" x="192.13" y="-25.2" font-size="12.00" class="label label-TRUE">Vertex</text>
84</g>
85<use x="176.142" y="-19" width="12" height="12" id="" class="icon icon-UNKNOWN" href="#refinery-p_2c2ycZZXd-I3Xg-BBah-icon-UNKNOWN"/>
86<g><text text-anchor="start" x="192.14" y="-9.2" font-size="12.00" class="label label-UNKNOWN">State</text>
87</g>
88<polyline points="170.14,-41 234.14,-41" class="node-outline"/>
89<rect fill="none" x="170.14" y="-64.4" width="64" height="64.4" rx="12" ry="12" class="node-outline"/>
90<clipPath id="refinery-p_2c2ycZZXd-I3Xg-BBah-clip-4"><rect stroke="none" x="170.14" y="-64.4" width="64" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g>
91<!-- n5&#45;&gt;n6 -->
92<g class="edge edge-TRUE">
93
94<path fill="none" stroke-width="2" d="M202.14,-100.47C202.14,-92.98 202.14,-84.45 202.14,-76.02" class="edge-line"/>
95<polygon stroke-width="2" points="205.2,-76.09 202.14,-67.34 199.08,-76.09 205.2,-76.09" class="edge-line edge-arrow"/>
96<text text-anchor="start" x="160.61" y="-86.89" font-weight="bold" font-size="10.50">vertices</text>
97</g><g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
98
99<rect stroke="none" x="254.14" y="-64.4" width="64" height="64.4" rx="12" ry="12" class="node-bg"/>
100<rect stroke="none" x="250" y="-68" width="72" height="27" clip-path="url(#refinery-p_2c2ycZZXd-I3Xg-BBah-clip-5)" class="node-header"/>
101<text text-anchor="start" x="279.71" y="-48.6" font-size="12.00">v3</text>
102<use x="260.142" y="-35" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-p_2c2ycZZXd-I3Xg-BBah-icon-TRUE"/>
103<g><text text-anchor="start" x="276.13" y="-25.2" font-size="12.00" class="label label-TRUE">Vertex</text>
104</g>
105<use x="260.142" y="-19" width="12" height="12" id="" class="icon icon-UNKNOWN" href="#refinery-p_2c2ycZZXd-I3Xg-BBah-icon-UNKNOWN"/>
106<g><text text-anchor="start" x="276.14" y="-9.2" font-size="12.00" class="label label-UNKNOWN">State</text>
107</g>
108<polyline points="254.14,-41 318.14,-41" class="node-outline"/>
109<rect fill="none" x="254.14" y="-64.4" width="64" height="64.4" rx="12" ry="12" class="node-outline"/>
110<clipPath id="refinery-p_2c2ycZZXd-I3Xg-BBah-clip-5"><rect stroke="none" x="254.14" y="-64.4" width="64" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g>
111<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-k">
112
113<rect stroke="none" x="252.96" y="-149.2" width="66.36999999999998" height="48.79999999999998" rx="12" ry="12" class="node-bg"/>
114<rect stroke="none" x="248" y="-153" width="74" height="27" clip-path="url(#refinery-p_2c2ycZZXd-I3Xg-BBah-clip-6)" class="node-header"/>
115<text text-anchor="start" x="280.26" y="-133.4" font-size="12.00">r3</text>
116<use x="258.955" y="-119.6" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-p_2c2ycZZXd-I3Xg-BBah-icon-TRUE"/>
117<g><text text-anchor="start" x="274.96" y="-110" font-size="12.00" class="label label-TRUE">Region</text>
118</g>
119<polyline points="252.96,-125.8 319.33,-125.8" class="node-outline"/>
120<rect fill="none" x="252.96" y="-149.2" width="66.36999999999998" height="48.79999999999998" rx="12" ry="12" class="node-outline"/>
121<clipPath id="refinery-p_2c2ycZZXd-I3Xg-BBah-clip-6"><rect stroke="none" x="252.96" y="-149.2" width="66.36999999999998" height="48.79999999999998" rx="12" ry="12" class="node-bg"/></clipPath></g><!-- n7&#45;&gt;n8 -->
122<g class="edge edge-TRUE">
123
124<path fill="none" stroke-width="2" d="M286.14,-100.47C286.14,-92.98 286.14,-84.45 286.14,-76.02" class="edge-line"/>
125<polygon stroke-width="2" points="289.2,-76.09 286.14,-67.34 283.08,-76.09 289.2,-76.09" class="edge-line edge-arrow"/>
126<text text-anchor="start" x="244.61" y="-86.89" font-weight="bold" font-size="10.50">vertices</text>
127</g>
128</g>
129</svg> \ No newline at end of file
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/DefaultAssertions.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg
new file mode 100644
index 00000000..a5232575
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg
@@ -0,0 +1,81 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="508pt" height="57pt" viewBox="-6 -6 519.5700073242188 68.79999923706055" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-meygjgDtG1kB8-FV4IATS"><style>.refinery-meygjgDtG1kB8-FV4IATS .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-meygjgDtG1kB8-FV4IATS .node .node-outline{stroke:#19202b;}.refinery-meygjgDtG1kB8-FV4IATS .node .node-header{fill:rgb(53, 161, 173);}.refinery-meygjgDtG1kB8-FV4IATS .node .node-bg{fill:#fff;}.refinery-meygjgDtG1kB8-FV4IATS .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-meygjgDtG1kB8-FV4IATS .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-meygjgDtG1kB8-FV4IATS .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-h .node-header{fill:#e06c75;}.refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-i .node-header{fill:#98c379;}.refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-j .node-header{fill:#c678dd;}.refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-n .node-header{fill:#abcc94;}.refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-meygjgDtG1kB8-FV4IATS .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-meygjgDtG1kB8-FV4IATS .edge .edge-line{stroke:#19202b;}.refinery-meygjgDtG1kB8-FV4IATS .edge .edge-arrow{fill:#19202b;}.refinery-meygjgDtG1kB8-FV4IATS .edge-UNKNOWN text{fill:#696c77;}.refinery-meygjgDtG1kB8-FV4IATS .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-meygjgDtG1kB8-FV4IATS .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-meygjgDtG1kB8-FV4IATS .edge-ERROR text{fill:#ca1243;}.refinery-meygjgDtG1kB8-FV4IATS .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-meygjgDtG1kB8-FV4IATS .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-meygjgDtG1kB8-FV4IATS .icon-TRUE{fill:#19202b;}.refinery-meygjgDtG1kB8-FV4IATS .icon-UNKNOWN{fill:#696c77;}.refinery-meygjgDtG1kB8-FV4IATS .icon-ERROR{fill:#ca1243;}.refinery-meygjgDtG1kB8-FV4IATS text.label-UNKNOWN{fill:#696c77;}.refinery-meygjgDtG1kB8-FV4IATS text.label-ERROR{fill:#ca1243;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-meygjgDtG1kB8-FV4IATS text.label-ERROR{fill:#e06c75;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-meygjgDtG1kB8-FV4IATS-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-meygjgDtG1kB8-FV4IATS-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-meygjgDtG1kB8-FV4IATS-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="translate(4, 52.79999923706055)">
4<!-- n0 -->
5<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE">
6
7<rect stroke="none" x="0" y="-48.8" width="59.74" height="48.8" rx="12" ry="12" class="node-bg"/>
8<rect stroke="none" x="-4" y="-52" width="67" height="27" clip-path="url(#refinery-meygjgDtG1kB8-FV4IATS-clip-0)" class="node-header"/>
9<text text-anchor="start" x="6.58" y="-33" font-size="12.00">node [1]</text>
10
11
12<polyline points="0,-25.4 59.74,-25.4" class="node-outline"/><use x="6" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-meygjgDtG1kB8-FV4IATS-icon-TRUE"/>
13<rect fill="none" x="0" y="-48.8" width="59.74" height="48.8" rx="12" ry="12" class="node-outline"/><g><text text-anchor="start" x="22" y="-9.6" font-size="12.00" class="label label-TRUE">exists</text>
14</g>
15<clipPath id="refinery-meygjgDtG1kB8-FV4IATS-clip-0"><rect stroke="none" x="0" y="-48.8" width="59.74" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
16<!-- n0&#45;&gt;n0 -->
17<g class="edge edge-TRUE">
18
19<path fill="none" d="M59.32,-33.55C69.51,-33.64 77.74,-30.6 77.74,-24.4 77.74,-20.82 74.99,-18.29 70.7,-16.81" class="edge-line"/>
20<polygon points="71.2,-13.35 60.82,-15.46 70.25,-20.28 71.2,-13.35" class="edge-line edge-arrow"/>
21<text text-anchor="middle" x="75.93" y="-36.7" font-size="10.50">equals</text>
22</g>
23<!-- n1 -->
24<g class="node node-IMPLICIT node-exists-UNKNOWN node-equalsSelf-TRUE">
25
26<rect stroke="none" x="95.38" y="-48.8" width="100.98000000000002" height="48.8" rx="12" ry="12" class="node-bg"/>
27<rect stroke="none" x="91" y="-52" width="108" height="27" clip-path="url(#refinery-meygjgDtG1kB8-FV4IATS-clip-1)" class="node-header"/>
28<text text-anchor="start" x="100.38" y="-33" font-size="12.00">removable [0..1]</text>
29
30
31<use x="101.384" y="-19.2" width="12" height="12" id="" class="icon icon-UNKNOWN" href="#refinery-meygjgDtG1kB8-FV4IATS-icon-UNKNOWN"/>
32<g><text text-anchor="start" x="117.38" y="-9.6" font-size="12.00" class="label label-UNKNOWN">exists</text>
33</g>
34<polyline points="95.38,-25.4 196.36,-25.4" class="node-outline"/><rect fill="none" x="95.38" y="-48.8" width="100.98000000000002" height="48.8" rx="12" ry="12" class="node-outline"/><clipPath id="refinery-meygjgDtG1kB8-FV4IATS-clip-1"><rect stroke="none" x="95.38" y="-48.8" width="100.98000000000002" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
35<!-- n1&#45;&gt;n1 -->
36<g class="edge edge-TRUE">
37
38<path fill="none" d="M196.34,-33.23C206.82,-32.3 214.36,-29.36 214.36,-24.4 214.36,-21.46 211.7,-19.22 207.35,-17.7" class="edge-line"/>
39<polygon points="208.31,-14.32 197.83,-15.86 206.98,-21.2 208.31,-14.32" class="edge-line edge-arrow"/>
40<text text-anchor="middle" x="213.45" y="-36.29" font-size="10.50">equals</text>
41</g>
42<!-- n2 -->
43<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-UNKNOWN"><rect stroke="none" x="237.5" y="-42.5" width="70" height="49" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
44
45<rect stroke="none" x="232.01" y="-48.8" width="69.72000000000003" height="48.8" rx="12" ry="12" class="node-bg"/>
46<rect stroke="none" x="228" y="-52" width="77" height="27" clip-path="url(#refinery-meygjgDtG1kB8-FV4IATS-clip-2)" class="node-header"/>
47<text text-anchor="start" x="237.01" y="-33" font-size="12.00">multi [1..*]</text>
48<use x="238.011" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-meygjgDtG1kB8-FV4IATS-icon-TRUE"/>
49<g><text text-anchor="start" x="254.01" y="-9.6" font-size="12.00" class="label label-TRUE">exists</text>
50</g>
51<polyline points="232.01,-25.4 301.73,-25.4" class="node-outline"/>
52<rect fill="none" x="232.01" y="-48.8" width="69.72000000000003" height="48.8" rx="12" ry="12" class="node-outline"/>
53<clipPath id="refinery-meygjgDtG1kB8-FV4IATS-clip-2"><rect stroke="none" x="232.01" y="-48.8" width="69.72000000000003" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
54<!-- n2&#45;&gt;n2 -->
55<g class="edge edge-UNKNOWN">
56
57<path fill="none" d="M301.69,-33.52C311.86,-33.21 319.73,-30.17 319.73,-24.4 319.73,-21.07 317.1,-18.64 312.91,-17.13" class="edge-line" stroke-dasharray="5,2"/>
58<polygon points="313.62,-13.7 303.19,-15.52 312.48,-20.61 313.62,-13.7" class="edge-line edge-arrow"/>
59<text text-anchor="middle" x="318.3" y="-36.66" font-size="10.50">equals</text>
60</g>
61<!-- n3 -->
62<g class="node node-IMPLICIT node-exists-UNKNOWN node-equalsSelf-UNKNOWN"><rect stroke="none" x="342.5" y="-42.5" width="130" height="49" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
63
64<rect stroke="none" x="337.25" y="-48.8" width="129.24" height="48.8" rx="12" ry="12" class="node-bg"/>
65<rect stroke="none" x="333" y="-52" width="137" height="27" clip-path="url(#refinery-meygjgDtG1kB8-FV4IATS-clip-3)" class="node-header"/>
66<text text-anchor="start" x="342.25" y="-33" font-size="12.00">removableMulti [0..*]</text>
67<use x="343.251" y="-19.2" width="12" height="12" id="" class="icon icon-UNKNOWN" href="#refinery-meygjgDtG1kB8-FV4IATS-icon-UNKNOWN"/>
68<g><text text-anchor="start" x="359.25" y="-9.6" font-size="12.00" class="label label-UNKNOWN">exists</text>
69</g>
70<polyline points="337.25,-25.4 466.49,-25.4" class="node-outline"/>
71<rect fill="none" x="337.25" y="-48.8" width="129.24" height="48.8" rx="12" ry="12" class="node-outline"/>
72<clipPath id="refinery-meygjgDtG1kB8-FV4IATS-clip-3"><rect stroke="none" x="337.25" y="-48.8" width="129.24" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
73<!-- n3&#45;&gt;n3 -->
74<g class="edge edge-UNKNOWN">
75
76<path fill="none" stroke-dasharray="5,2" d="M466.3,-32.9C477.06,-31.71 484.49,-28.88 484.49,-24.4 484.49,-21.74 481.87,-19.66 477.49,-18.16" class="edge-line"/>
77<polygon points="478.28,-14.75 467.78,-16.2 476.89,-21.61 478.28,-14.75" class="edge-line edge-arrow"/>
78<text text-anchor="middle" x="483.44" y="-35.94" font-size="10.50">equals</text>
79</g>
80</g>
81</svg> \ No newline at end of file
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/MultiObjects.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg
new file mode 100644
index 00000000..440dfb19
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg
@@ -0,0 +1,58 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="260pt" height="157pt" viewBox="-6 -6 271.9100036621094 169.1999969482422" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery--ID4ju8v8LPQmawWdGqBG"><style>.refinery--ID4ju8v8LPQmawWdGqBG .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery--ID4ju8v8LPQmawWdGqBG .node .node-outline{stroke:#19202b;}.refinery--ID4ju8v8LPQmawWdGqBG .node .node-header{fill:rgb(53, 161, 173);}.refinery--ID4ju8v8LPQmawWdGqBG .node .node-bg{fill:#fff;}.refinery--ID4ju8v8LPQmawWdGqBG .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery--ID4ju8v8LPQmawWdGqBG .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery--ID4ju8v8LPQmawWdGqBG .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-g .node-header{fill:#e5c07b;}.refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-h .node-header{fill:#e06c75;}.refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-i .node-header{fill:#98c379;}.refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-j .node-header{fill:#c678dd;}.refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-k .node-header{fill:#80a7f4;}.refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-m .node-header{fill:#e78b8f;}.refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-n .node-header{fill:#abcc94;}.refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-p .node-header{fill:#92c0e9;}.refinery--ID4ju8v8LPQmawWdGqBG .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery--ID4ju8v8LPQmawWdGqBG .edge .edge-line{stroke:#19202b;}.refinery--ID4ju8v8LPQmawWdGqBG .edge .edge-arrow{fill:#19202b;}.refinery--ID4ju8v8LPQmawWdGqBG .edge-UNKNOWN text{fill:#696c77;}.refinery--ID4ju8v8LPQmawWdGqBG .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery--ID4ju8v8LPQmawWdGqBG .edge-UNKNOWN .edge-arrow{fill:none;}.refinery--ID4ju8v8LPQmawWdGqBG .edge-ERROR text{fill:#ca1243;}.refinery--ID4ju8v8LPQmawWdGqBG .edge-ERROR .edge-line{stroke:#ca1243;}.refinery--ID4ju8v8LPQmawWdGqBG .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery--ID4ju8v8LPQmawWdGqBG .icon-TRUE{fill:#19202b;}.refinery--ID4ju8v8LPQmawWdGqBG .icon-UNKNOWN{fill:#696c77;}.refinery--ID4ju8v8LPQmawWdGqBG .icon-ERROR{fill:#ca1243;}.refinery--ID4ju8v8LPQmawWdGqBG text.label-UNKNOWN{fill:#696c77;}.refinery--ID4ju8v8LPQmawWdGqBG text.label-ERROR{fill:#ca1243;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery--ID4ju8v8LPQmawWdGqBG text.label-ERROR{fill:#e06c75;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery--ID4ju8v8LPQmawWdGqBG-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery--ID4ju8v8LPQmawWdGqBG-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery--ID4ju8v8LPQmawWdGqBG-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="scale(1 1) rotate(0) translate(4 153.2)">
4<!-- n0 -->
5<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-k"><rect stroke="none" x="74.5" y="-143.5" width="117" height="49" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
6
7<rect stroke="none" x="69.26" y="-149.2" width="116.17999999999999" height="48.79999999999998" rx="12" ry="12" class="node-bg"/>
8<rect stroke="none" x="65" y="-153" width="124" height="27" clip-path="url(#refinery--ID4ju8v8LPQmawWdGqBG-clip-0)" class="node-header"/>
9<text text-anchor="start" x="74.26" y="-133.4" font-size="12.00">Region::new [0..70]</text>
10<use x="75.2588" y="-119.6" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery--ID4ju8v8LPQmawWdGqBG-icon-TRUE"/>
11<g><text text-anchor="start" x="91.26" y="-110" font-size="12.00" class="label label-TRUE">Region</text>
12</g>
13<polyline points="69.26,-125.8 185.44,-125.8" class="node-outline"/>
14<rect fill="none" x="69.26" y="-149.2" width="116.17999999999999" height="48.79999999999998" rx="12" ry="12" class="node-outline"/>
15<clipPath id="refinery--ID4ju8v8LPQmawWdGqBG-clip-0"><rect stroke="none" x="69.26" y="-149.2" width="116.17999999999999" height="48.79999999999998" rx="12" ry="12" class="node-bg"/></clipPath></g>
16<!-- n2 -->
17<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-j"><rect stroke="none" x="143.5" y="-58.5" width="114" height="65" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
18
19<rect stroke="none" x="138.78" y="-64.4" width="113.13" height="64.4" rx="12" ry="12" class="node-bg"/>
20<rect stroke="none" x="134" y="-68" width="121" height="27" clip-path="url(#refinery--ID4ju8v8LPQmawWdGqBG-clip-1)" class="node-header"/>
21<text text-anchor="start" x="143.78" y="-48.6" font-size="12.00">State::new [0..120]</text>
22<use x="144.782" y="-35" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery--ID4ju8v8LPQmawWdGqBG-icon-TRUE"/>
23<g><text text-anchor="start" x="160.77" y="-25.2" font-size="12.00" class="label label-TRUE">Vertex</text>
24</g>
25<use x="144.782" y="-19" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery--ID4ju8v8LPQmawWdGqBG-icon-TRUE"/>
26<g><text text-anchor="start" x="160.78" y="-9.2" font-size="12.00" class="label label-TRUE">State</text>
27</g>
28<polyline points="138.78,-41 251.91,-41" class="node-outline"/>
29<rect fill="none" x="138.78" y="-64.4" width="113.13" height="64.4" rx="12" ry="12" class="node-outline"/>
30<clipPath id="refinery--ID4ju8v8LPQmawWdGqBG-clip-1"><rect stroke="none" x="138.78" y="-64.4" width="113.13" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g><g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-h"><rect stroke="none" x="5.5" y="-50.5" width="121" height="49" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
31
32<rect stroke="none" x="0" y="-56.6" width="120.7" height="48.800000000000004" rx="12" ry="12" class="node-bg"/>
33<rect stroke="none" x="-4" y="-60" width="128" height="27" clip-path="url(#refinery--ID4ju8v8LPQmawWdGqBG-clip-2)" class="node-header"/>
34<text text-anchor="start" x="5" y="-40.8" font-size="12.00">Vertex::new [0..120]</text>
35<use x="6" y="-27" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery--ID4ju8v8LPQmawWdGqBG-icon-TRUE"/>
36<g><text text-anchor="start" x="22" y="-17.4" font-size="12.00" class="label label-TRUE">Vertex</text>
37</g>
38<polyline points="0,-33.2 120.7,-33.2" class="node-outline"/>
39<rect fill="none" x="0" y="-56.6" width="120.7" height="48.800000000000004" rx="12" ry="12" class="node-outline"/>
40<clipPath id="refinery--ID4ju8v8LPQmawWdGqBG-clip-2"><rect stroke="none" x="0" y="-56.6" width="120.7" height="48.800000000000004" rx="12" ry="12" class="node-bg"/></clipPath></g>
41<!-- n0&#45;&gt;n2 -->
42<g class="edge edge-UNKNOWN">
43
44<path fill="none" stroke-width="2" stroke-dasharray="5,2" d="M110.09,-100.47C102.28,-89.9 92.91,-77.23 84.42,-65.75" class="edge-line"/>
45<polygon stroke-width="2" points="87.01,-64.1 79.34,-58.89 82.08,-67.74 87.01,-64.1" class="edge-line edge-arrow"/>
46<text text-anchor="start" x="52.27" y="-82.58" font-weight="bold" font-size="10.50">vertices</text>
47</g>
48<!-- n3 -->
49
50<!-- n3&#45;&gt;n2 -->
51<g class="edge edge-UNKNOWN">
52
53<path fill="none" stroke-width="2" stroke-dasharray="5,2" d="M144.86,-100.47C150.99,-92.3 158.07,-82.87 164.95,-73.7" class="edge-line"/>
54<polygon stroke-width="2" points="167.38,-75.57 170.18,-66.73 162.48,-71.89 167.38,-75.57" class="edge-line edge-arrow"/>
55<text text-anchor="start" x="116.95" y="-86.47" font-weight="bold" font-size="10.50">vertices</text>
56</g>
57</g>
58</svg> \ No newline at end of file
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/ObjectScopes.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg
new file mode 100644
index 00000000..6f988065
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg
@@ -0,0 +1,58 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="246pt" height="157pt" viewBox="-6 -6 258.2899932861328 169.1999969482422" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-J5TgkNWMX1Aj-K6cbPdd9"><style>.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node .node-outline{stroke:#19202b;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node .node-header{fill:rgb(53, 161, 173);}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node .node-bg{fill:#fff;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-h .node-header{fill:#e06c75;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-i .node-header{fill:#98c379;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-j .node-header{fill:#c678dd;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-n .node-header{fill:#abcc94;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge .edge-line{stroke:#19202b;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge .edge-arrow{fill:#19202b;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge-UNKNOWN text{fill:#696c77;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge-ERROR text{fill:#ca1243;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .icon-TRUE{fill:#19202b;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .icon-UNKNOWN{fill:#696c77;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 .icon-ERROR{fill:#ca1243;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 text.label-UNKNOWN{fill:#696c77;}.refinery-J5TgkNWMX1Aj-K6cbPdd9 text.label-ERROR{fill:#ca1243;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-J5TgkNWMX1Aj-K6cbPdd9 text.label-ERROR{fill:#e06c75;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-J5TgkNWMX1Aj-K6cbPdd9-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-J5TgkNWMX1Aj-K6cbPdd9-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-J5TgkNWMX1Aj-K6cbPdd9-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="scale(1 1) rotate(0) translate(4 153.2)">
4<!-- n0 -->
5<g class="node node-NEW node-exists-UNKNOWN node-equalsSelf-UNKNOWN node-typeHash-k"><rect stroke="none" x="74.5" y="-143.5" width="117" height="49" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
6
7<rect stroke="none" x="69.69" y="-149.2" width="116.18" height="48.79999999999998" rx="12" ry="12" class="node-bg"/>
8<rect stroke="none" x="65" y="-153" width="124" height="27" clip-path="url(#refinery-J5TgkNWMX1Aj-K6cbPdd9-clip-0)" class="node-header"/>
9<text text-anchor="start" x="74.69" y="-133.4" font-size="12.00">Region::new [0..70]</text>
10<use x="75.6895" y="-119.6" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-J5TgkNWMX1Aj-K6cbPdd9-icon-TRUE"/>
11<g><text text-anchor="start" x="91.69" y="-110" font-size="12.00" class="label label-TRUE">Region</text>
12</g>
13<polyline points="69.69,-125.8 185.87,-125.8" class="node-outline"/>
14<rect fill="none" x="69.69" y="-149.2" width="116.18" height="48.79999999999998" rx="12" ry="12" class="node-outline"/>
15<clipPath id="refinery-J5TgkNWMX1Aj-K6cbPdd9-clip-0"><rect stroke="none" x="69.69" y="-149.2" width="116.18" height="48.79999999999998" rx="12" ry="12" class="node-bg"/></clipPath></g>
16<!-- n2 -->
17<g class="node node-NEW node-exists-TRUE node-equalsSelf-UNKNOWN node-typeHash-j"><rect stroke="none" x="150.5" y="-58.5" width="94" height="65" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
18
19<rect stroke="none" x="145.27" y="-64.4" width="93.01999999999998" height="64.4" rx="12" ry="12" class="node-bg"/>
20<rect stroke="none" x="141" y="-68" width="101" height="27" clip-path="url(#refinery-J5TgkNWMX1Aj-K6cbPdd9-clip-1)" class="node-header"/>
21<text text-anchor="start" x="150.27" y="-48.6" font-size="12.00">State::new [20]</text>
22<use x="151.268" y="-35" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-J5TgkNWMX1Aj-K6cbPdd9-icon-TRUE"/>
23<g><text text-anchor="start" x="167.25" y="-25.2" font-size="12.00" class="label label-TRUE">Vertex</text>
24</g>
25<use x="151.268" y="-19" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-J5TgkNWMX1Aj-K6cbPdd9-icon-TRUE"/>
26<g><text text-anchor="start" x="167.27" y="-9.2" font-size="12.00" class="label label-TRUE">State</text>
27</g>
28<polyline points="145.27,-41 238.29,-41" class="node-outline"/>
29<rect fill="none" x="145.27" y="-64.4" width="93.01999999999998" height="64.4" rx="12" ry="12" class="node-outline"/>
30<clipPath id="refinery-J5TgkNWMX1Aj-K6cbPdd9-clip-1"><rect stroke="none" x="145.27" y="-64.4" width="93.01999999999998" height="64.4" rx="12" ry="12" class="node-bg"/></clipPath></g><g class="node node-NEW node-exists-TRUE node-equalsSelf-UNKNOWN node-typeHash-h"><rect stroke="none" x="5.5" y="-50.5" width="128" height="49" rx="12.5" ry="12.5" class="node-shadow node-bg"/>
31
32<rect stroke="none" x="0" y="-56.6" width="127.56" height="48.800000000000004" rx="12" ry="12" class="node-bg"/>
33<rect stroke="none" x="-4" y="-60" width="135" height="27" clip-path="url(#refinery-J5TgkNWMX1Aj-K6cbPdd9-clip-2)" class="node-header"/>
34<text text-anchor="start" x="5" y="-40.8" font-size="12.00">Vertex::new [30..100]</text>
35<use x="6" y="-27" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-J5TgkNWMX1Aj-K6cbPdd9-icon-TRUE"/>
36<g><text text-anchor="start" x="22" y="-17.4" font-size="12.00" class="label label-TRUE">Vertex</text>
37</g>
38<polyline points="0,-33.2 127.56,-33.2" class="node-outline"/>
39<rect fill="none" x="0" y="-56.6" width="127.56" height="48.800000000000004" rx="12" ry="12" class="node-outline"/>
40<clipPath id="refinery-J5TgkNWMX1Aj-K6cbPdd9-clip-2"><rect stroke="none" x="0" y="-56.6" width="127.56" height="48.800000000000004" rx="12" ry="12" class="node-bg"/></clipPath></g>
41<!-- n0&#45;&gt;n2 -->
42<g class="edge edge-UNKNOWN">
43
44<path fill="none" stroke-width="2" stroke-dasharray="5,2" d="M111.3,-100.47C103.83,-89.9 94.88,-77.23 86.77,-65.75" class="edge-line"/>
45<polygon stroke-width="2" points="89.5,-64.3 81.95,-58.93 84.5,-67.84 89.5,-64.3" class="edge-line edge-arrow"/>
46<text text-anchor="start" x="54.2" y="-82.58" font-weight="bold" font-size="10.50">vertices</text>
47</g>
48<!-- n3 -->
49
50<!-- n3&#45;&gt;n2 -->
51<g class="edge edge-UNKNOWN">
52
53<path fill="none" stroke-width="2" stroke-dasharray="5,2" d="M144.26,-100.47C150.03,-92.3 156.69,-82.87 163.17,-73.7" class="edge-line"/>
54<polygon stroke-width="2" points="165.51,-75.7 168.06,-66.78 160.51,-72.16 165.51,-75.7" class="edge-line edge-arrow"/>
55<text text-anchor="start" x="115.55" y="-86.47" font-weight="bold" font-size="10.50">vertices</text>
56</g>
57</g>
58</svg> \ No newline at end of file
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/StrongerObjectScopes.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/index.md b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/index.md
new file mode 100644
index 00000000..e366e9b8
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/logic/index.md
@@ -0,0 +1,256 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4description: Four-valued logic abstraction
5sidebar_position: 1
6---
7
8# Partial modeling
9
10Refinery allow precisely expressing _unknown,_ _uncertain_ or even _contradictory_ information using [four-valued logic](https://en.wikipedia.org/wiki/Four-valued_logic#Belnap).
11During model generation, unknown aspects of the partial model get _refined_ into concrete (true or false) facts until the generated model is completed, or a contradiction is reached.
12
13The _Belnap--Dunn four-valued logic_ supports the following truth values:
14
15* `true` values correspond to facts known about the model, e.g., that a node is the instance of a given class or there is a reference between two nodes.
16* `false` values correspond to facts that are known not to hold, e.g., that a node is _not_ an instance of a given class or there is _no_ reference between two nodes.
17* `unknown` values express uncertain properties and design decisions yet to be made. During model refinement, `unknown` values are gradually replaced with `true` and `false` values until a consistent and concrete model is derived.
18* `error` values represent contradictions and validation failures in the model. One a model contains an error value, it can't be refined into a consistent model anymore.
19
20## Assertions
21
22_Assertions_ express facts about a partial model. An assertion is formed by a _symbol_ and an _argument list_ of _nodes_ in parentheses.
23Possible symbols include [classes](../classes/#classes), [references](../classes/#references), and [predicates](../predicates).
24Nodes appearing in the argument list are automatically added to the model.
25
26A _negative_ assertion with a `false` truth value is indicated by prefixing it with `!`.
27
28---
29
30Consider the following metamodel:
31
32```refinery
33class Region {
34 contains Vertex[] vertices
35}
36class Vertex.
37class State extends Vertex.
38```
39
40Along with the following set of assertions:
41
42```refinery
43Region(r1).
44Vertex(v1).
45Vertex(v2).
46!State(v2).
47vertices(r1, v1).
48vertices(r1, v2).
49!vertices(Region::new, v1).
50!vertices(Region::new, v2).
51```
52
53import AssertionsExample from './AssertionsExample.svg';
54
55<AssertionsExample />
56
57It is `true` that `r1` is an instance of the class `Region`, while `v1` and `v2` are instances of the class `Vertex`.
58We also assert that `v2` is _not_ an instance of the class `State`, but it is unknown whether `v1` is an instance of the class `State`.
59Types that are `unknown` are shown in a lighter color and with an outlined icon.
60
61It is `true` that there is a `vertices` reference between `r1` and `v1`, as well as `r1` and `v2`, but there is no such reference from `Region::new` to the same vertices.
62As no information is provided, it is `unknown` whether `State::new` is a vertex of any `Region` instance.
63References that are `unknown` are shown in a lighter color and with a dashed line.
64
65### Propagation
66
67Refinery can automatically infer some facts about the partial model based on the provided assertions by information _propagation._
68The set of assertions in the [example above](#assertions) is equivalent to the following:
69
70```refinery
71vertices(r1, v1).
72vertices(r1, v2).
73!State(v2).
74```
75
76By the type constraints of the `vertices` reference, Refinery can infer that `r1` is a `Region` instance and `v1` and `v2` are `Vertex` instances.
77Since `State` is a subclass of `Vertex`, it is still unknown whether `v1` is a `State` instance,
78but `v2` is explicitly forbidden from being such by the negative assertion `!State(v2)`.
79We may omit `!vertices(Region::new, v1)` and `!vertices(Region::new, v2)`, since `v1` and `v2` may be a target of only one [containment](../classes/#containment-hierarchy) reference.
80
81Contradictory assertions lead to `error` values in the partial model:
82
83```refinery
84State(v1).
85!Vertex(v1).
86```
87
88import AssertionsError from './AssertionsError.svg';
89
90<AssertionsError />
91
92### Default assertions
93
94Assertions marked with the `default` keyword have _lower priority_ that other assertions.
95They may contain wildcard arguments `*` to specify information about _all_ nodes in the graph.
96However, they can be overridden by more specific assertions that are not marked with the `default` keyword.
97
98---
99
100To make sure that the reference `vertices` is `false` everywhere except where explicitly asserted, we may add a `default` assertion:
101
102```refinery
103default !vertices(*, *).
104vertices(r1, v1).
105vertices(r2, v2).
106vertices(r3, v3).
107?vertices(r1, State::new).
108```
109
110import DefaultAssertions from './DefaultAssertions.svg';
111
112<DefaultAssertions />
113
114We can prefix an assertion with `?` to explicitly assert that some fact about the partial model is `unknown`.
115This is useful for overriding negative `default` assertions.
116
117## Multi-objects
118
119The special symbols `exists` and `equals` control the _number of graph nodes_ represented by an object in a partial model.
120
121By default, `exists` is `true` for all objects.
122An object `o` with `?exists(o)` (i.e., `exists(o)` explicitly set to `unknown`) may be _removed_ from the partial model.
123Therefore, it represents _at least 0_ graph nodes.
124
125By default, `equals` is `true` for its _diagonal_, i.e., we have `equals(o, o)` for all object `o`.
126For off-diagonal pairs, i.e., `(p, q)` with `p` not equal to `q`, we always have `!equals(p, q)`: distinct objects can never be _merged._
127If we set a _diagonal_ entry to `unknown` by writing `?equals(o, o)`, the object `o` becomes a **multi-object:** it can be freely _split_ into multiple graph nodes.
128Therefore, multi-objects represent _possibly more than 1_ graph nodes.
129
130| `exists(o)` | `equals(o, o)` | Number of nodes | Description |
131|:-:|:-:|-:|:-|
132| `true` | `true` | `1` | graph node |
133| `unknown` | `true` | `0..1` | removable graph node |
134| `true` | `unknown` | `1..*` | multi-object |
135| `unknown` | `unknown` | `0..*` | removable multi-object |
136
137In the Refinery web UI, `?exists(o)` is represented with a _dashed_ border, while `?equals(o, o)`
138
139```refinery
140node(node).
141
142node(removable).
143?exists(removable).
144
145node(multi).
146?equals(multi, multi).
147
148node(removableMulti).
149?exists(removableMulti).
150?equals(removableMulti, removableMulti).
151```
152
153import MultiObjects from './MultiObjects.svg';
154
155<MultiObjects />
156
157import TuneIcon from '@material-icons/svg/svg/tune/baseline.svg';
158import LabelIcon from '@material-icons/svg/svg/label/baseline.svg';
159import LabelOutlineIcon from '@material-icons/svg/svg/label/outline.svg';
160
161:::info
162
163You may use the <TuneIcon style={{ fill: 'currentColor', verticalAlign: 'text-top' }} title="Filter panel icon" />&nbsp;_filter panel_ icon in Refinery to toggle the visibility of special symbols like `exists` and `equals`.
164You may either show <LabelOutlineIcon style={{ fill: 'currentColor', verticalAlign: 'text-top' }} title="Unknown value icon" />&nbsp;_both true and unknown_ values or <LabelIcon style={{ fill: 'currentColor', verticalAlign: 'text-top' }} title="True value icon" />&nbsp;_just true_ values.
165The _object scopes_ toggle will also show the number of graph nodes represented by an object in square brackets after its name, like in the figure above.
166:::
167
168By default, a **new object** `C::new` is added for each non-`abstract` [class](../classes#classes) `C` with `?exists(C::new)` and `?equals(C::new, C::new)`.
169This multi-object represents all potential instances of the class.
170To assert that no new instances of `C` should be added to the generated model, you may write `!exists(C::new)`.
171
172You may use the `multi` keyword to quickly defined a (removable) multi-object:
173
174```refinery
175multi removableMulti.
176% This is equivalent to:
177% ?exists(removableMulti).
178% ?equals(removableMulti, removableMulti).
179```
180
181## Type scopes
182
183_Type scopes_ offer finer-grained control over the number of graph nodes in the generated model (as represented by the multi-objects) that `exists` or `equals` assertions.
184
185A _type scope constraint_ is formed by a unary symbol (a [class](../classes/#classes) or a [predicate](../predicates) with a single parameter) and _scope range._
186Ranges have a form similar to [multiplicity constraints](../classes#multiplicity): a range `n..m` indicates a lower bound of `n` and an upper bound of `m`.
187While an upper bound of `*` indicates a possibly unbounded number of objects, generated models will always be finite.
188Like for multiplicity constraints, the case `n..n` can be abbreviated as `n`.
189
190The number of nodes in the generated model can be controlled using the `node` special symbol.
191For example, we may write the following to generate a model with at least 100 at and most 120 nodes:
192
193```refinery
194scope node = 100..200.
195```
196
197A `scope` declaration may prescribe type scope constraint for any number of symbols, separated by `,`.
198Multiple `scope` declarations are also permitted.
199Multiple ranges provided for the same symbol will be intersected, i.e., they influence the generated model simultaneously.
200
201In other words,
202```
203scope Region = 10, State = 80..120.
204scope State = 100..150.
205% Equivalent to:
206scope Region = 10, State = 100..120.
207```
208
209The _object scopes_ option in the <TuneIcon style={{ fill: 'currentColor', verticalAlign: 'text-top' }} title="Filter panel icon" />&nbsp;_filter panel_ may help in exploring the effects of object scopes.
210
211---
212
213Consider the example
214
215```refinery
216class Region {
217 contains Vertex[] vertices
218}
219class Vertex.
220class State extends Vertex.
221scope node = 100..120, Vertex = 50..*.
222```
223
224import ObjectScopes from './ObjectScopes.svg';
225
226<ObjectScopes />
227
228Notice that Refinery could determine that there can be no more than 70 `Region` instances in the generated model, since at least 50 of the `100..120` nodes in the model must be `Vertex` instances.
229However, since `State` is a subclass of `Vertex` (i.e., `State::new` is also an instance of `Vertex`), the range `50..*` is shared between both `Vertex::new` and `State::new`, resulting in both representing `0..120` nodes.
230Nevertheless, every generated model will obey the scope constraint exactly, i.e., will have between 100 and 120 node, at least 50 of which are `Vertex` instances.
231
232By providing more information, Refinery can determine more precise ranges for multi-objects.
233For example, we may strengthen the scope constraints as follows:
234
235```refinery
236scope node = 100..120, Vertex = 50..*, State = 20.
237```
238
239import StrongerObjectScopes from './StrongerObjectScopes.svg';
240
241<StrongerObjectScopes />
242
243### Incremental scopes
244
245We may specify an _incremental_ object scope with the `+=` operator to determine the number of new instances to be added to the model.
246This is only allowed for symbol that are classes with no subclasses, as it directly influences the number of nodes represented by the corresponding `::new` object.
247
248For example, to ensure that between 5 and 7 `State` instances are added to the model, we may write:
249
250```refinery
251State(s1).
252State(s2).
253scope State += 5..7.
254```
255
256Since `s1` and `s2` are also instances of the `State` class, the generated concrete model will have between 7 and 9 `State` instances altogether.
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg
new file mode 100644
index 00000000..be9465b8
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg
@@ -0,0 +1,76 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="216pt" height="226pt" viewBox="-6 -6 227.8699951171875 238.39999389648438" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="refinery-9k5t5y1ScYnYvNXEZbWT4"><style>.refinery-9k5t5y1ScYnYvNXEZbWT4 .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node .node-outline{stroke:#19202b;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node .node-header{fill:rgb(53, 161, 173);}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node .node-bg{fill:#fff;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node-INDIVIDUAL .node-outline{stroke-width:2;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node-shadow.node-bg{fill:#19202b;opacity:0.24;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-g .node-header{fill:#e5c07b;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-h .node-header{fill:#e06c75;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-i .node-header{fill:#98c379;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-j .node-header{fill:#c678dd;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-k .node-header{fill:#80a7f4;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-l .node-header{fill:#e3d1b2;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-m .node-header{fill:#e78b8f;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-n .node-header{fill:#abcc94;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-o .node-header{fill:#dbb2e8;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-p .node-header{fill:#92c0e9;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#19202b;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .edge .edge-line{stroke:#19202b;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .edge .edge-arrow{fill:#19202b;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .edge-UNKNOWN text{fill:#696c77;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .edge-UNKNOWN .edge-line{stroke:#696c77;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .edge-UNKNOWN .edge-arrow{fill:none;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .edge-ERROR text{fill:#ca1243;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .edge-ERROR .edge-line{stroke:#ca1243;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .edge-ERROR .edge-arrow{fill:#ca1243;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .icon-TRUE{fill:#19202b;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .icon-UNKNOWN{fill:#696c77;}.refinery-9k5t5y1ScYnYvNXEZbWT4 .icon-ERROR{fill:#ca1243;}.refinery-9k5t5y1ScYnYvNXEZbWT4 text.label-UNKNOWN{fill:#696c77;}.refinery-9k5t5y1ScYnYvNXEZbWT4 text.label-ERROR{fill:#ca1243;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node .node-outline{stroke:#ebebff;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node .node-header{fill:rgb(60, 127, 135);}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node .node-bg{fill:#282c34;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node-INDIVIDUAL .node-outline{stroke-width:2;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node-shadow.node-bg{fill:#ebebff;opacity:0.32;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node-exists-UNKNOWN .node-outline{stroke-dasharray:5 2;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-g .node-header{fill:#ae8003;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-h .node-header{fill:#a23b47;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-i .node-header{fill:#428141;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-j .node-header{fill:#854797;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-k .node-header{fill:#3982bb;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-l .node-header{fill:#827662;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-m .node-header{fill:#904f53;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-n .node-header{fill:#647e63;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-o .node-header{fill:#805f89;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .node-typeHash-p .node-header{fill:#4f7799;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .edge text{font-family:"Open Sans Variable","Open Sans","Roboto","Helvetica","Arial",sans-serif;fill:#ebebff;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .edge .edge-line{stroke:#ebebff;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .edge .edge-arrow{fill:#ebebff;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .edge-UNKNOWN text{fill:#abb2bf;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .edge-UNKNOWN .edge-line{stroke:#abb2bf;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .edge-UNKNOWN .edge-arrow{fill:none;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .edge-ERROR text{fill:#e06c75;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .edge-ERROR .edge-line{stroke:#e06c75;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .edge-ERROR .edge-arrow{fill:#e06c75;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .icon-TRUE{fill:#ebebff;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .icon-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 .icon-ERROR{fill:#e06c75;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 text.label-UNKNOWN{fill:#abb2bf;}[data-theme="dark"] .refinery-9k5t5y1ScYnYvNXEZbWT4 text.label-ERROR{fill:#e06c75;}</style><defs><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-9k5t5y1ScYnYvNXEZbWT4-icon-TRUE" class="icon-TRUE"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-9k5t5y1ScYnYvNXEZbWT4-icon-UNKNOWN" class="icon-UNKNOWN"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16zM16 17H5V7h11l3.55 5L16 17z"/></svg><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" id="refinery-9k5t5y1ScYnYvNXEZbWT4-icon-ERROR" class="icon-ERROR"><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17L12 13.41L8.41 17L7 15.59L10.59 12L7 8.41L8.41 7L12 10.59L15.59 7L17 8.41L13.41 12L17 15.59z"/></svg></defs>
3<g class="graph" transform="translate(4, 222.39999389648438)">
4<!-- n2 -->
5<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-i">
6
7<rect stroke="none" x="64.75" y="-48.8" width="84.22" height="48.8" rx="12" ry="12" class="node-bg"/>
8<rect stroke="none" x="60" y="-52" width="92" height="27" clip-path="url(#refinery-9k5t5y1ScYnYvNXEZbWT4-clip-0)" class="node-header"/>
9<text text-anchor="start" x="76.52" y="-33" font-size="12.00">transition1</text>
10<use x="70.7485" y="-19.2" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-9k5t5y1ScYnYvNXEZbWT4-icon-TRUE"/>
11<g><text text-anchor="start" x="86.75" y="-9.6" font-size="12.00" class="label label-TRUE">Transition</text>
12</g>
13<polyline points="64.75,-25.4 148.97,-25.4" class="node-outline"/>
14<rect fill="none" x="64.75" y="-48.8" width="84.22" height="48.8" rx="12" ry="12" class="node-outline"/>
15<clipPath id="refinery-9k5t5y1ScYnYvNXEZbWT4-clip-0"><rect stroke="none" x="64.75" y="-48.8" width="84.22" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
16<!-- n3 -->
17<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
18
19<rect stroke="none" x="74.84" y="-218.4" width="64.03" height="48.80000000000001" rx="12" ry="12" class="node-bg"/>
20<rect stroke="none" x="70" y="-222" width="72" height="27" clip-path="url(#refinery-9k5t5y1ScYnYvNXEZbWT4-clip-1)" class="node-header"/>
21<text text-anchor="start" x="85.98" y="-202.6" font-size="12.00">vertex1</text>
22<use x="80.8442" y="-188.8" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-9k5t5y1ScYnYvNXEZbWT4-icon-TRUE"/>
23<g><text text-anchor="start" x="96.84" y="-179.2" font-size="12.00" class="label label-TRUE">Vertex</text>
24</g>
25<polyline points="74.84,-195 138.87,-195" class="node-outline"/>
26<rect fill="none" x="74.84" y="-218.4" width="64.03" height="48.80000000000001" rx="12" ry="12" class="node-outline"/>
27<clipPath id="refinery-9k5t5y1ScYnYvNXEZbWT4-clip-1"><rect stroke="none" x="74.84" y="-218.4" width="64.03" height="48.80000000000001" rx="12" ry="12" class="node-bg"/></clipPath></g>
28<!-- n2&#45;&gt;n3 -->
29<g class="edge edge-TRUE">
30
31<path fill="none" d="M111.71,-48.78C113.97,-77.25 114.21,-125.59 112.45,-158.38" class="edge-line"/>
32<polygon points="108.96,-157.98 111.8,-168.19 115.95,-158.44 108.96,-157.98" class="edge-line edge-arrow"/>
33<text text-anchor="middle" x="97.12" y="-99.47" font-size="10.50">source</text>
34</g>
35<!-- n4 -->
36<g class="node node-IMPLICIT node-exists-TRUE node-equalsSelf-TRUE node-typeHash-h">
37
38<rect stroke="none" x="143.84" y="-133.6" width="64.03" height="48.8" rx="12" ry="12" class="node-bg"/>
39<rect stroke="none" x="139" y="-137" width="72" height="27" clip-path="url(#refinery-9k5t5y1ScYnYvNXEZbWT4-clip-2)" class="node-header"/>
40<text text-anchor="start" x="154.98" y="-117.8" font-size="12.00">vertex2</text>
41<use x="149.844" y="-104" width="12" height="12" id="" class="icon icon-TRUE" href="#refinery-9k5t5y1ScYnYvNXEZbWT4-icon-TRUE"/>
42<g><text text-anchor="start" x="165.84" y="-94.4" font-size="12.00" class="label label-TRUE">Vertex</text>
43</g>
44<polyline points="143.84,-110.2 207.87,-110.2" class="node-outline"/>
45<rect fill="none" x="143.84" y="-133.6" width="64.03" height="48.8" rx="12" ry="12" class="node-outline"/>
46<clipPath id="refinery-9k5t5y1ScYnYvNXEZbWT4-clip-2"><rect stroke="none" x="143.84" y="-133.6" width="64.03" height="48.8" rx="12" ry="12" class="node-bg"/></clipPath></g>
47<!-- n2&#45;&gt;n4 -->
48<g class="edge edge-TRUE">
49
50<path fill="none" d="M132.35,-48.63C140.1,-57.19 148.46,-67.04 155.81,-76.23" class="edge-line"/>
51<polygon points="152.92,-78.21 161.83,-83.94 158.44,-73.91 152.92,-78.21" class="edge-line edge-arrow"/>
52<text text-anchor="middle" x="133.35" y="-57.15" font-size="10.50">target</text>
53</g>
54<!-- n3&#45;&gt;n2 -->
55<g class="edge edge-TRUE">
56
57<path fill="none" stroke-width="2" d="M102.01,-169.7C99.75,-141.26 99.5,-92.92 101.27,-60.1" class="edge-line"/>
58<polygon stroke-width="2" points="104.3,-60.73 101.81,-51.8 98.18,-60.33 104.3,-60.73" class="edge-line edge-arrow"/>
59<text text-anchor="start" x="0" y="-113.73" font-weight="bold" font-size="10.50">outgoingTransition</text>
60</g>
61<!-- n4&#45;&gt;n2 -->
62<!-- n4&#45;&gt;n2 -->
63<g class="edge edge-TRUE">
64
65<path fill="none" d="M150.52,-85.14C142.77,-76.59 134.41,-66.75 127.05,-57.54" class="edge-line"/>
66<polygon points="129.93,-55.54 121.01,-49.82 124.41,-59.86 129.93,-55.54" class="edge-line edge-arrow"/>
67<text text-anchor="middle" x="87.8" y="-70.33" font-size="10.50">incomingTransition</text>
68</g><g class="edge edge-TRUE">
69
70<path fill="none" d="M126.08,-169.94C133.27,-161.31 141.57,-151.34 149.31,-142.06" class="edge-line"/>
71<polygon points="151.82,-144.51 155.53,-134.59 146.44,-140.03 151.82,-144.51" class="edge-line edge-arrow"/>
72<text text-anchor="middle" x="116.57" y="-154.94" font-size="10.50">neighbors</text>
73</g>
74
75</g>
76</svg> \ No newline at end of file
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/DerivedFeature.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/index.md b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/index.md
new file mode 100644
index 00000000..261054c1
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/language/predicates/index.md
@@ -0,0 +1,284 @@
1---
2SPDX-FileCopyrightText: 2024 The Refinery Authors
3SPDX-License-Identifier: EPL-2.0
4description: Model queries and model validation
5sidebar_position: 2
6---
7
8# Graph predicates
9
10Graph predicates are logic expressions that can be used to query for interesting model fragments, as well as for validating the consistency of models. They are evaluated on partial models according to [four-valued logic](../logic) semantics.
11
12Predicates in Refinery are written in [Disjunctive Normal Form](https://en.wikipedia.org/wiki/Disjunctive_normal_form) (DNF) as an _OR_ of _ANDs_, i.e., a _disjunction_ of _clauses_ formed as a _conjunction_ of positive or negated logic _literals._
13This matches the syntax and semantics of logical query languages, such as [Datalog](https://en.wikipedia.org/wiki/Datalog), and logical programming languages, such as [Prolog](https://en.wikipedia.org/wiki/Prolog).
14
15import Link from '@docusaurus/Link';
16
17<details>
18<summary>Example metamodel</summary>
19
20In the examples on this page, we will use the following metamodel as illustration:
21
22```refinery
23abstract class CompositeElement {
24 contains Region[] regions
25}
26
27class Region {
28 contains Vertex[] vertices opposite region
29}
30
31abstract class Vertex {
32 container Region region opposite vertices
33 contains Transition[] outgoingTransition opposite source
34 Transition[] incomingTransition opposite target
35}
36
37class Transition {
38 container Vertex source opposite outgoingTransition
39 Vertex[1] target opposite incomingTransition
40}
41
42abstract class Pseudostate extends Vertex.
43
44abstract class RegularState extends Vertex.
45
46class Entry extends Pseudostate.
47
48class Exit extends Pseudostate.
49
50class Choice extends Pseudostate.
51
52class FinalState extends RegularState.
53
54class State extends RegularState, CompositeElement.
55
56class Statechart extends CompositeElement.
57```
58
59<p>
60 <Link
61 href="https://refinery.services/#/1/KLUv_WAEAiUIAOIKIR5gadMGg1ajk9jLoipJ58vc0vAE5opt1YaDpyOCAAdaCjMohSdgl4rj1yTo8UCgpTDHCIAE-o3Jr28mGO9AEoDcR-tLGh4liE2Z3IOX50z-FksLaNWLpLXd1QiUII2vNjCMBWOVEgTzjhG0eHVMIyIyFOjoxcrBv83FkgftlmJ0K_0eVDQgEBSCrXYvD1Q2wlwGXecz2HjRADQOLMh6iIYIWBPuFBBCI2igVgiHAFH4uclAydd4TFayN-oOpjzxgd0FlTzkN6QZ8CQDXBN4EPjB5VJZCANQlJA3wDd_PVyUA5eA0gaeAcgENsm4YnCogWihMAMkA8-CoB-gm9HJC0AB"
62 className="button button--lg button--primary button--play"
63 >Try in Refinery</Link>
64</p>
65
66</details>
67
68[Assertions](../logic/#assertions) about graph predicates can prescribe where the predicate should (for positive assertions) or should not (for negative assertions) hold.
69When generating consistent models
70
71## Atoms
72
73An _atom_ is formed by a _symbol_ and _argument list_ of variables.
74Possible symbols include [classes](../classes/#classes), [references](../classes/#references), and [predicates](../predicates).
75We may write a basic graph query as a conjunction (AND) of atoms.
76
77The `pred` keyword defines a graph predicate. After the _predicate name_, a _parameter list_ of variables is provided. The atoms of the graph predicate are written after the `<->` operator, and a full stop `.` terminates the predicate definition.
78
79The following predicate `entryInRegion` will match pairs of `Region` instances `r` and `Entry` instances `e` such that `e` is a vertex in `r`.
80
81```refinery
82pred entryInRegion(r, e) <->
83 Region(r),
84 vertices(r, e),
85 Entry(e).
86```
87
88We may write unary symbols that act as _parameter types_ directly in the parameter list. The following definition is equivalent to the previous one:
89
90```refinery
91pred entryInRegion(Region r, Entry e) <->
92 vertices(r, e).
93```
94
95import TableIcon from '@material-icons/svg/svg/table_chart/baseline.svg';
96
97:::info
98
99You may display the result of graph predicate matching in the <TableIcon style={{ fill: 'currentColor', verticalAlign: 'text-top' }} title="Table view icon" />&nbsp;_table view_ of the Refinery web UI.
100
101:::
102
103## Quantification
104
105Variables not appearing in the parameter list are _existentially quantified._
106
107The following predicate matches `Region` instances with two entries:
108
109```refinery
110pred multipleEntriesInRegion(Region r) <->
111 entryInRegion(r, e1),
112 entryInRegion(r, e2),
113 e1 != e2.
114```
115
116Existentially quantified variables that appear only once in the predicate should be prefixed with `_`. This shows that the variable is intentionally used only once (as opposite to the second reference to the variable being omitted by mistake).
117
118```refinery
119pred regionWithEntry(Region r) <->
120 entryInRegion(r, _e).
121```
122
123Alternatively, you may use a single `_` whenever a variable occurring only once is desired. Different occurrences of `_` are considered distinct variables.
124
125```refinery
126pred regionWithEntry(Region r) <->
127 entryInRegion(r, _).
128```
129
130## Negation
131
132Negative literals are written by prefixing the corresponding atom with `!`.
133
134Inside negative literals, quantification is _universal:_ the literal matches if there is no assignment of the variables solely appearing in it that satisfies the corresponding atom.
135
136The following predicate matches `Region` instances that have no `Entry`:
137
138```refinery
139pred regionWithoutEntry(Region r) <->
140 !entryInRegion(r, _).
141```
142
143In a graph predicate, all parameter variables must be _positively bound,_ i.e., appear in at least one positive literal (atom).
144Negative literals may further constrain the predicate match one it has been established by the positive literals.
145
146## Object equality
147
148The operators `a == b` and `a != b` correspond to the literals `equals(a, b)` and `!equals(a, b)`, respectively.
149See the section about [multi-objects](../logic/#multi-objects) for more information about the `equals` symbol.
150
151## Transitive closure
152
153The `+` operator forms the [transitive closure](https://en.wikipedia.org/wiki/Transitive_closure) of symbols with exactly 2 parameters.
154The transitive closure `r+(a, b)` holds if either `r(a, b)` is `true`, or there is a sequence of objects `c1`, `c2`, &hellip;, `cn` such that `r(a, c1)`, `r(c1, c2)`, `r(c2, c3)`, &hellip;, `r(cn, b)`.
155In other words, there is a path labelled with `r` in the graph from `a` to `b`.
156
157Transitive closure may express queries about graph reachability:
158
159```refinery
160pred neighbors(Vertex v1, Vertex v2) <->
161 Transition(t),
162 source(t, v1),
163 target(t, v2).
164
165pred cycle(Vertex v) <->
166 neighbors+(v, v).
167```
168
169## Disjunction
170
171Disjunction (OR) of _clauses_ formed by a conjunction (AND) of literals is denoted by `;`.
172
173```refinery
174pred regionWithInvalidNumberOfEntries(Region r) <->
175 !entryInRegion(r, _)
176;
177 entryInRegion(r, e1),
178 entryInRegion(r, e2),
179 e1 != e2.
180```
181
182Every clause of a disjunction must bind every parameter variable of the graph predicate _positively._
183_Type annotations_ on parameter are applied in all clauses.
184Therefore, the previous graph pattern is equivalent to the following:
185
186```refinery
187pred regionWithInvalidNumberOfEntries(r) <->
188 Region(r),
189 !entryInRegion(r, _)
190;
191 Region(r),
192 entryInRegion(r, e1),
193 entryInRegion(r, e2),
194 e1 != e2.
195```
196
197## Derived features
198
199Graph predicates may act as _derived types_ and _references_ in metamodel.
200
201A graph predicate with exactly 1 parameters can be use as if it was a class: you may use it as a [_parameter type_](#atoms) in other graph patterns, as a _target type_ of a (non-containment) [reference](../classes/#references), or in a [_scope constraint_](../logic#type-scopes).
202
203_Derived references_ are graph predicates with exactly 2 parameters, which correspond the source and target node of the reference.
204
205import TuneIcon from '@material-icons/svg/svg/tune/baseline.svg';
206import LabelIcon from '@material-icons/svg/svg/label/baseline.svg';
207import LabelOutlineIcon from '@material-icons/svg/svg/label/outline.svg';
208
209:::info
210
211You may use the <TuneIcon style={{ fill: 'currentColor', verticalAlign: 'text-top' }} title="Filter panel icon" />&nbsp;_filter panel_ icon in Refinery to toggle the visibility of graph predicates with 1 or 2 parameters.
212You may either show <LabelOutlineIcon style={{ fill: 'currentColor', verticalAlign: 'text-top' }} title="Unknown value icon" />&nbsp;_both true and unknown_ values or <LabelIcon style={{ fill: 'currentColor', verticalAlign: 'text-top' }} title="True value icon" />&nbsp;_just true_ values.
213
214:::
215
216---
217
218For example, we may replace the reference `neighbors` in the class `Vertex`:
219
220```refinery
221class Vertex {
222 Vertex[] neighbors
223}
224```
225
226with the graph predicate `neighbors` as follows:
227
228
229```refinery
230class Vertex {
231 contains Transition[] outgoingTransition opposite source
232 Transition[] incomingTransition opposite target
233}
234
235class Transition {
236 container Vertex source opposite outgoingTransition
237 Vertex[1] target opposite incomingTransition
238}
239
240pred neighbors(Vertex v1, Vertex v2) <->
241 Transition(t),
242 source(t, v1),
243 target(t, v2).
244```
245
246Since `neighbors` is now computed based on the `Transition` instances and their `source` and `target` references present in the model, the assertion
247
248```refinery
249neighbors(vertex1, vertex2).
250```
251
252will only be satisfied if a corresponding node `transition1` is present in the generated model that also satisfies
253
254```refinery
255Transition(transition1).
256source(transition1, vertex1).
257target(transition1, vertex2).
258```
259
260import DerivedFeature from './DerivedFeature.svg';
261
262<DerivedFeature />
263
264## Error predicates
265
266A common use-case for graph predicates is _model validation_, where a predicate highlights _errors_ in the model.
267Such predicates are called _error predicates._
268In a consistent generated model, an error predicates should have no matches.
269
270You can declare error predicates with the `error` keyword:
271
272```refinery
273error regionWithoutEntry(Region r) <->
274 !entryInRegion(r, _).
275```
276
277This is equivalent to asserting that the error predicate is `false` everywhere:
278
279```refinery
280pred regionWithoutEntry(Region r) <->
281 !entryInRegion(r, _).
282
283!regionWithoutEntry(*).
284```
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/_category_.yml b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/_category_.yml
new file mode 100644
index 00000000..fd563704
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/_category_.yml
@@ -0,0 +1,11 @@
1# SPDX-FileCopyrightText: 2024 The Refinery Authors
2#
3# SPDX-License-Identifier: EPL-2.0
4
5position: 1
6label: Tutorials
7link:
8 type: generated-index
9 slug: /learn/tutorials
10 title: Tutorial overview
11 description: Try Refinery in practical partial modeling challenges!
diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig1.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig1.svg
index 1e20393a..1e20393a 100644
--- a/subprojects/docs/src/learn/tutorials/file-system/fig1.svg
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig1.svg
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig1.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig1.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig1.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig2.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig2.svg
index 6375bfd6..6375bfd6 100644
--- a/subprojects/docs/src/learn/tutorials/file-system/fig2.svg
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig2.svg
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig2.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig2.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig2.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig3.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig3.svg
index 0d020a71..0d020a71 100644
--- a/subprojects/docs/src/learn/tutorials/file-system/fig3.svg
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig3.svg
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig3.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig3.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig3.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/src/learn/tutorials/file-system/fig4.svg b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig4.svg
index d6701bdd..d6701bdd 100644
--- a/subprojects/docs/src/learn/tutorials/file-system/fig4.svg
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig4.svg
diff --git a/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig4.svg.license b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig4.svg.license
new file mode 100644
index 00000000..b80566a0
--- /dev/null
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/fig4.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/src/learn/tutorials/file-system/index.md b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/index.md
index 365d0fba..365d0fba 100644
--- a/subprojects/docs/src/learn/tutorials/file-system/index.md
+++ b/subprojects/docs/versioned_docs/version-0.1.0/learn/tutorials/file-system/index.md
diff --git a/subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json b/subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json
new file mode 100644
index 00000000..2f70ab5e
--- /dev/null
+++ b/subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json
@@ -0,0 +1,14 @@
1{
2 "learnSidebar": [
3 {
4 "type": "autogenerated",
5 "dirName": "learn"
6 }
7 ],
8 "developSidebar": [
9 {
10 "type": "autogenerated",
11 "dirName": "develop"
12 }
13 ]
14}
diff --git a/subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json.license b/subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json.license
new file mode 100644
index 00000000..cfe95706
--- /dev/null
+++ b/subprojects/docs/versioned_sidebars/version-0.1.0-sidebars.json.license
@@ -0,0 +1,3 @@
1Copyright (c) 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/docs/versions.json b/subprojects/docs/versions.json
new file mode 100644
index 00000000..7b999c75
--- /dev/null
+++ b/subprojects/docs/versions.json
@@ -0,0 +1,3 @@
1[
2 "0.1.0"
3]
diff --git a/subprojects/docs/versions.json.license b/subprojects/docs/versions.json.license
new file mode 100644
index 00000000..2891afa3
--- /dev/null
+++ b/subprojects/docs/versions.json.license
@@ -0,0 +1,3 @@
1Copyright (c) 2024 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: CC0-1.0
diff --git a/subprojects/frontend/package.json b/subprojects/frontend/package.json
index acff57db..ca7bff56 100644
--- a/subprojects/frontend/package.json
+++ b/subprojects/frontend/package.json
@@ -28,35 +28,36 @@
28 }, 28 },
29 "homepage": "https://refinery.tools", 29 "homepage": "https://refinery.tools",
30 "dependencies": { 30 "dependencies": {
31 "@codemirror/autocomplete": "^6.17.0", 31 "@codemirror/autocomplete": "^6.18.0",
32 "@codemirror/commands": "^6.6.0", 32 "@codemirror/commands": "^6.6.0",
33 "@codemirror/language": "^6.10.2", 33 "@codemirror/language": "^6.10.2",
34 "@codemirror/lint": "^6.8.1", 34 "@codemirror/lint": "^6.8.1",
35 "@codemirror/search": "^6.5.6", 35 "@codemirror/search": "^6.5.6",
36 "@codemirror/state": "^6.4.1", 36 "@codemirror/state": "^6.4.1",
37 "@codemirror/view": "^6.28.4", 37 "@codemirror/view": "^6.33.0",
38 "@emotion/cache": "^11.11.0", 38 "@emotion/cache": "^11.13.1",
39 "@emotion/react": "^11.11.4", 39 "@emotion/react": "^11.13.3",
40 "@emotion/serialize": "^1.1.4", 40 "@emotion/serialize": "^1.3.1",
41 "@emotion/styled": "^11.11.5", 41 "@emotion/sheet": "^1.4.0",
42 "@emotion/utils": "^1.2.1", 42 "@emotion/styled": "^11.13.0",
43 "@fontsource-variable/jetbrains-mono": "^5.0.21", 43 "@fontsource-variable/jetbrains-mono": "^5.0.22",
44 "@fontsource-variable/open-sans": "^5.0.29", 44 "@fontsource-variable/open-sans": "^5.0.30",
45 "@fontsource/open-sans": "^5.0.28", 45 "@fontsource/open-sans": "^5.0.29",
46 "@hpcc-js/wasm": "^2.18.0", 46 "@hpcc-js/wasm": "^2.21.0",
47 "@hpcc-js/wasm-zstd": "^1.2.0",
47 "@lezer/common": "^1.2.1", 48 "@lezer/common": "^1.2.1",
48 "@lezer/highlight": "^1.2.0", 49 "@lezer/highlight": "^1.2.1",
49 "@lezer/lr": "^1.4.1", 50 "@lezer/lr": "^1.4.2",
50 "@material-icons/svg": "^1.0.33", 51 "@material-icons/svg": "^1.0.33",
51 "@mui/icons-material": "^5.16.0", 52 "@mui/icons-material": "^6.0.1",
52 "@mui/material": "^5.16.0", 53 "@mui/material": "^6.0.1",
53 "@mui/system": "^5.16.0", 54 "@mui/system": "^6.0.1",
54 "@mui/x-data-grid": "^7.9.0", 55 "@mui/x-data-grid": "^7.15.0",
55 "ansi-styles": "^6.2.1", 56 "ansi-styles": "^6.2.1",
56 "csstype": "^3.1.3", 57 "csstype": "^3.1.3",
57 "d3": "^7.9.0", 58 "d3": "^7.9.0",
58 "d3-color": "^3.1.0", 59 "d3-color": "^3.1.0",
59 "d3-graphviz": "patch:d3-graphviz@npm%3A5.4.0#~/.yarn/patches/d3-graphviz-npm-5.4.0-4298b33e9f.patch", 60 "d3-graphviz": "patch:d3-graphviz@npm%3A5.6.0#~/.yarn/patches/d3-graphviz-npm-5.6.0-129e64ec05.patch",
60 "d3-selection": "^3.0.0", 61 "d3-selection": "^3.0.0",
61 "d3-zoom": "patch:d3-zoom@npm%3A3.0.0#~/.yarn/patches/d3-zoom-npm-3.0.0-18f706a421.patch", 62 "d3-zoom": "patch:d3-zoom@npm%3A3.0.0#~/.yarn/patches/d3-zoom-npm-3.0.0-18f706a421.patch",
62 "escape-string-regexp": "^5.0.0", 63 "escape-string-regexp": "^5.0.0",
@@ -64,7 +65,7 @@
64 "lodash-es": "^4.17.21", 65 "lodash-es": "^4.17.21",
65 "loglevel": "^1.9.1", 66 "loglevel": "^1.9.1",
66 "loglevel-plugin-prefix": "^0.8.4", 67 "loglevel-plugin-prefix": "^0.8.4",
67 "mobx": "^6.13.0", 68 "mobx": "^6.13.1",
68 "mobx-react-lite": "^4.0.7", 69 "mobx-react-lite": "^4.0.7",
69 "ms": "^2.1.3", 70 "ms": "^2.1.3",
70 "nanoid": "^5.0.7", 71 "nanoid": "^5.0.7",
@@ -88,18 +89,18 @@
88 "@types/lodash-es": "^4.17.12", 89 "@types/lodash-es": "^4.17.12",
89 "@types/micromatch": "^4.0.9", 90 "@types/micromatch": "^4.0.9",
90 "@types/ms": "^0.7.34", 91 "@types/ms": "^0.7.34",
91 "@types/node": "^20.14.10", 92 "@types/node": "^20.16.2",
92 "@types/pnpapi": "^0.0.5", 93 "@types/pnpapi": "^0.0.5",
93 "@types/react": "^18.3.3", 94 "@types/react": "^18.3.5",
94 "@types/react-dom": "^18.3.0", 95 "@types/react-dom": "^18.3.0",
95 "@vitejs/plugin-react-swc": "^3.7.0", 96 "@vitejs/plugin-react-swc": "^3.7.0",
96 "@xstate/cli": "^0.5.17", 97 "@xstate/cli": "^0.5.17",
97 "html-minifier-terser": "^7.2.0", 98 "html-minifier-terser": "^7.2.0",
98 "micromatch": "^4.0.7", 99 "micromatch": "^4.0.8",
99 "pnpapi": "^0.0.0", 100 "pnpapi": "^0.0.0",
100 "typescript": "5.5.3", 101 "typescript": "5.5.4",
101 "vite": "^5.3.3", 102 "vite": "^5.4.2",
102 "vite-plugin-pwa": "^0.20.0", 103 "vite-plugin-pwa": "^0.20.2",
103 "workbox-window": "^7.1.0" 104 "workbox-window": "^7.1.0"
104 } 105 }
105} 106}
diff --git a/subprojects/frontend/src/graph/GraphStore.ts b/subprojects/frontend/src/graph/GraphStore.ts
index 86ffd802..a133d636 100644
--- a/subprojects/frontend/src/graph/GraphStore.ts
+++ b/subprojects/frontend/src/graph/GraphStore.ts
@@ -25,6 +25,7 @@ export function getDefaultVisibility(
25 case 'class': 25 case 'class':
26 case 'reference': 26 case 'reference':
27 case 'opposite': 27 case 'opposite':
28 case 'base':
28 return 'all'; 29 return 'all';
29 case 'predicate': 30 case 'predicate':
30 return detail.error ? 'must' : 'none'; 31 return detail.error ? 'must' : 'none';
@@ -233,4 +234,9 @@ export default class GraphStore {
233 get name(): string { 234 get name(): string {
234 return this.nameOverride ?? this.editorStore.simpleNameOrFallback; 235 return this.nameOverride ?? this.editorStore.simpleNameOrFallback;
235 } 236 }
237
238 get showNonExistent(): boolean {
239 const existsVisibility = this.visibility.get('builtin::exists') ?? 'none';
240 return existsVisibility !== 'none' || this.scopes;
241 }
236} 242}
diff --git a/subprojects/frontend/src/graph/GraphTheme.tsx b/subprojects/frontend/src/graph/GraphTheme.tsx
index bdc01b78..1127a46d 100644
--- a/subprojects/frontend/src/graph/GraphTheme.tsx
+++ b/subprojects/frontend/src/graph/GraphTheme.tsx
@@ -143,6 +143,21 @@ export function createGraphTheme({
143 'text.label-ERROR': { 143 'text.label-ERROR': {
144 fill: theme.palette.error.main, 144 fill: theme.palette.error.main,
145 }, 145 },
146 '.node-exists-FALSE': {
147 'text:not(.label-ERROR)': {
148 fill: theme.palette.text.secondary,
149 },
150 '.node-outline': {
151 stroke: theme.palette.text.secondary,
152 strokeDasharray: '2 4',
153 },
154 '.node-header': {
155 fill: theme.palette.background.default,
156 },
157 '.icon-TRUE': {
158 fill: theme.palette.text.secondary,
159 },
160 },
146 }; 161 };
147} 162}
148 163
diff --git a/subprojects/frontend/src/graph/dotSource.ts b/subprojects/frontend/src/graph/dotSource.ts
index ce504c37..9099cd09 100644
--- a/subprojects/frontend/src/graph/dotSource.ts
+++ b/subprojects/frontend/src/graph/dotSource.ts
@@ -128,11 +128,16 @@ function createNodes(
128 const { 128 const {
129 semantics: { nodes }, 129 semantics: { nodes },
130 scopes, 130 scopes,
131 showNonExistent,
131 } = graph; 132 } = graph;
132 133
133 nodes.forEach((node, i) => { 134 nodes.forEach((node, i) => {
134 const data = nodeData[i]; 135 const data = nodeData[i];
135 if (data === undefined || data.isolated || data.exists === 'FALSE') { 136 if (
137 data === undefined ||
138 data.isolated ||
139 (!showNonExistent && data.exists === 'FALSE')
140 ) {
136 return; 141 return;
137 } 142 }
138 const classList = [ 143 const classList = [
@@ -255,6 +260,7 @@ function createRelationEdges(
255): void { 260): void {
256 const { 261 const {
257 semantics: { nodes, partialInterpretation }, 262 semantics: { nodes, partialInterpretation },
263 showNonExistent,
258 } = graph; 264 } = graph;
259 const { detail } = relation; 265 const { detail } = relation;
260 266
@@ -297,9 +303,9 @@ function createRelationEdges(
297 const toData = nodeData[to]; 303 const toData = nodeData[to];
298 if ( 304 if (
299 fromData === undefined || 305 fromData === undefined ||
300 fromData.exists === 'FALSE' ||
301 toData === undefined || 306 toData === undefined ||
302 toData.exists === 'FALSE' 307 (!showNonExistent &&
308 (fromData.exists === 'FALSE' || toData.exists === 'FALSE'))
303 ) { 309 ) {
304 return; 310 return;
305 } 311 }
diff --git a/subprojects/frontend/src/graph/export/exportDiagram.tsx b/subprojects/frontend/src/graph/export/exportDiagram.tsx
index 73b40fea..663cafe1 100644
--- a/subprojects/frontend/src/graph/export/exportDiagram.tsx
+++ b/subprojects/frontend/src/graph/export/exportDiagram.tsx
@@ -6,7 +6,7 @@
6 6
7import createCache from '@emotion/cache'; 7import createCache from '@emotion/cache';
8import { serializeStyles } from '@emotion/serialize'; 8import { serializeStyles } from '@emotion/serialize';
9import type { StyleSheet } from '@emotion/utils'; 9import type { StyleSheet } from '@emotion/sheet';
10import italicFontURL from '@fontsource/open-sans/files/open-sans-latin-400-italic.woff2?url'; 10import italicFontURL from '@fontsource/open-sans/files/open-sans-latin-400-italic.woff2?url';
11import normalFontURL from '@fontsource/open-sans/files/open-sans-latin-400-normal.woff2?url'; 11import normalFontURL from '@fontsource/open-sans/files/open-sans-latin-400-normal.woff2?url';
12import boldFontURL from '@fontsource/open-sans/files/open-sans-latin-700-normal.woff2?url'; 12import boldFontURL from '@fontsource/open-sans/files/open-sans-latin-700-normal.woff2?url';
diff --git a/subprojects/frontend/src/language/problem.grammar b/subprojects/frontend/src/language/problem.grammar
index b8038b70..56867964 100644
--- a/subprojects/frontend/src/language/problem.grammar
+++ b/subprojects/frontend/src/language/problem.grammar
@@ -52,8 +52,7 @@ statement {
52 kw<"extern"> ckw<"aggregator"> AggregatorName "." 52 kw<"extern"> ckw<"aggregator"> AggregatorName "."
53 } | 53 } |
54 PredicateDefinition { 54 PredicateDefinition {
55 ckw<"shadow">? 55 ((kw<"error"> | kw<"partial"> | ckw<"shadow">)* kw<"pred"> | kw<"error">)
56 (kw<"error">? kw<"pred"> | kw<"error">)
57 RelationName ParameterList<Parameter>? 56 RelationName ParameterList<Parameter>?
58 PredicateBody { ("<->" sep<OrOp, Conjunction>)? "." } 57 PredicateBody { ("<->" sep<OrOp, Conjunction>)? "." }
59 } | 58 } |
diff --git a/subprojects/frontend/src/persistence/compressionWorker.ts b/subprojects/frontend/src/persistence/compressionWorker.ts
index 7b93b20b..df476535 100644
--- a/subprojects/frontend/src/persistence/compressionWorker.ts
+++ b/subprojects/frontend/src/persistence/compressionWorker.ts
@@ -1,13 +1,10 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> 2 * SPDX-FileCopyrightText: 2023-2024 The Refinery Authors <https://refinery.tools/>
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6 6
7import type { Zstd } from '@hpcc-js/wasm'; 7import { Zstd } from '@hpcc-js/wasm-zstd';
8// We need to use a deep import for proper code splitting with `vite-plugin-pwa`.
9// @ts-expect-error Typescript doesn't find the declarations for the deep import.
10import { Zstd as zstdLoader } from '@hpcc-js/wasm/zstd';
11 8
12import type { 9import type {
13 CompressResponse, 10 CompressResponse,
@@ -56,13 +53,13 @@ async function base64Decode(compressedText: string): Promise<Uint8Array> {
56 return new Uint8Array(await result.arrayBuffer()); 53 return new Uint8Array(await result.arrayBuffer());
57} 54}
58 55
59let zstd: Awaited<ReturnType<typeof Zstd.load>> | undefined; 56let zstd: Zstd | undefined;
60 57
61globalThis.onmessage = (event) => { 58globalThis.onmessage = (event) => {
62 (async () => { 59 (async () => {
63 if (zstd === undefined) { 60 if (zstd === undefined) {
64 // Since we don't have types for the deep import, we have to cast here. 61 // Since we don't have types for the deep import, we have to cast here.
65 zstd = await (zstdLoader as { load: typeof Zstd.load }).load(); 62 zstd = await Zstd.load();
66 } 63 }
67 // Since the render thread will only send us valid messages, 64 // Since the render thread will only send us valid messages,
68 // we can save a bit of bundle size by using a cast instead of `parse` 65 // we can save a bit of bundle size by using a cast instead of `parse`
diff --git a/subprojects/frontend/src/xtext/xtextServiceResults.ts b/subprojects/frontend/src/xtext/xtextServiceResults.ts
index c5bc1320..7c2fb8ec 100644
--- a/subprojects/frontend/src/xtext/xtextServiceResults.ts
+++ b/subprojects/frontend/src/xtext/xtextServiceResults.ts
@@ -156,6 +156,7 @@ export const RelationMetadata = z.object({
156 opposite: z.string(), 156 opposite: z.string(),
157 }), 157 }),
158 z.object({ type: z.literal('predicate'), error: z.boolean() }), 158 z.object({ type: z.literal('predicate'), error: z.boolean() }),
159 z.object({ type: z.literal('base') }),
159 z.object({ type: z.literal('builtin') }), 160 z.object({ type: z.literal('builtin') }),
160 ]), 161 ]),
161}); 162});
diff --git a/subprojects/generator-cli/build.gradle.kts b/subprojects/generator-cli/build.gradle.kts
index 6c681222..edb13b65 100644
--- a/subprojects/generator-cli/build.gradle.kts
+++ b/subprojects/generator-cli/build.gradle.kts
@@ -1,5 +1,5 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> 2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
@@ -11,14 +11,9 @@ plugins {
11dependencies { 11dependencies {
12 implementation(project(":refinery-generator")) 12 implementation(project(":refinery-generator"))
13 implementation(libs.jcommander) 13 implementation(libs.jcommander)
14 implementation(libs.slf4j.api) 14 implementation(libs.slf4j)
15} 15}
16 16
17application { 17application {
18 mainClass.set("tools.refinery.generator.cli.RefineryCli") 18 mainClass.set("tools.refinery.generator.cli.RefineryCli")
19} 19}
20
21tasks.shadowJar {
22 // Silence Xtext warning.
23 append("plugin.properties")
24}
diff --git a/subprojects/generator/build.gradle.kts b/subprojects/generator/build.gradle.kts
index 36e3537a..14eebf7d 100644
--- a/subprojects/generator/build.gradle.kts
+++ b/subprojects/generator/build.gradle.kts
@@ -6,6 +6,7 @@
6 6
7plugins { 7plugins {
8 id("tools.refinery.gradle.java-library") 8 id("tools.refinery.gradle.java-library")
9 id("tools.refinery.gradle.java-test-fixtures")
9} 10}
10 11
11mavenArtifact { 12mavenArtifact {
@@ -14,7 +15,7 @@ mavenArtifact {
14 15
15dependencies { 16dependencies {
16 api(project(":refinery-language-semantics")) 17 api(project(":refinery-language-semantics"))
17 api(libs.eclipseCollections.api)
18 implementation(project(":refinery-store-query-interpreter")) 18 implementation(project(":refinery-store-query-interpreter"))
19 testImplementation(testFixtures(project(":refinery-language"))) 19 testFixturesApi(testFixtures(project(":refinery-language")))
20 testFixturesImplementation(libs.junit.api)
20} 21}
diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/CancellableCancellationToken.java b/subprojects/generator/src/main/java/tools/refinery/generator/CancellableCancellationToken.java
new file mode 100644
index 00000000..53bac196
--- /dev/null
+++ b/subprojects/generator/src/main/java/tools/refinery/generator/CancellableCancellationToken.java
@@ -0,0 +1,38 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator;
7
8import tools.refinery.store.util.CancellationToken;
9
10class CancellableCancellationToken implements CancellationToken {
11 private volatile boolean cancelled;
12
13 private final CancellationToken wrappedToken;
14
15 public CancellableCancellationToken(CancellationToken wrappedToken) {
16 this.wrappedToken = wrappedToken;
17 }
18
19 public boolean isCancelled() {
20 return cancelled;
21 }
22
23 public void cancel() {
24 cancelled = true;
25 }
26
27 public void reset() {
28 cancelled = false;
29 }
30
31 @Override
32 public void checkCancelled() {
33 wrappedToken.checkCancelled();
34 if (cancelled) {
35 throw new GeneratorTimeoutException();
36 }
37 }
38}
diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/FilteredInterpretation.java b/subprojects/generator/src/main/java/tools/refinery/generator/FilteredInterpretation.java
new file mode 100644
index 00000000..c068615f
--- /dev/null
+++ b/subprojects/generator/src/main/java/tools/refinery/generator/FilteredInterpretation.java
@@ -0,0 +1,108 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator;
7
8import tools.refinery.logic.AbstractValue;
9import tools.refinery.logic.term.truthvalue.TruthValue;
10import tools.refinery.store.map.AnyVersionedMap;
11import tools.refinery.store.map.Cursor;
12import tools.refinery.store.reasoning.ReasoningAdapter;
13import tools.refinery.store.reasoning.interpretation.PartialInterpretation;
14import tools.refinery.store.reasoning.literal.Concreteness;
15import tools.refinery.store.reasoning.representation.PartialSymbol;
16import tools.refinery.store.tuple.Tuple;
17
18import java.util.Set;
19
20public class FilteredInterpretation<A extends AbstractValue<A, C>, C> implements PartialInterpretation<A, C> {
21 private final PartialInterpretation<A, C> wrappedInterpretation;
22 private final PartialInterpretation<TruthValue, Boolean> existsInterpretation;
23
24 public FilteredInterpretation(PartialInterpretation<A, C> wrappedInterpretation, PartialInterpretation<TruthValue,
25 Boolean> existsInterpretation) {
26 this.wrappedInterpretation = wrappedInterpretation;
27 this.existsInterpretation = existsInterpretation;
28 }
29
30 @Override
31 public ReasoningAdapter getAdapter() {
32 return wrappedInterpretation.getAdapter();
33 }
34
35 @Override
36 public PartialSymbol<A, C> getPartialSymbol() {
37 return wrappedInterpretation.getPartialSymbol();
38 }
39
40 @Override
41 public Concreteness getConcreteness() {
42 return wrappedInterpretation.getConcreteness();
43 }
44
45 @Override
46 public A get(Tuple key) {
47 return tupleExists(key) ? wrappedInterpretation.get(key) :
48 wrappedInterpretation.getPartialSymbol().defaultValue();
49 }
50
51 @Override
52 public Cursor<Tuple, A> getAll() {
53 return new FilteredCursor(wrappedInterpretation.getAll());
54 }
55
56 private boolean tupleExists(Tuple key) {
57 int arity = key.getSize();
58 for (int i = 0; i < arity; i++) {
59 if (!existsInterpretation.get(Tuple.of(key.get(i))).may()) {
60 return false;
61 }
62 }
63 return true;
64 }
65
66 private class FilteredCursor implements Cursor<Tuple, A> {
67 private final Cursor<Tuple, A> wrappedCursor;
68
69 private FilteredCursor(Cursor<Tuple, A> wrappedCursor) {
70 this.wrappedCursor = wrappedCursor;
71 }
72
73 @Override
74 public Tuple getKey() {
75 return wrappedCursor.getKey();
76 }
77
78 @Override
79 public A getValue() {
80 return wrappedCursor.getValue();
81 }
82
83 @Override
84 public boolean isTerminated() {
85 return wrappedCursor.isTerminated();
86 }
87
88 @Override
89 public boolean move() {
90 while (wrappedCursor.move()) {
91 if (tupleExists(getKey())) {
92 return true;
93 }
94 }
95 return false;
96 }
97
98 @Override
99 public boolean isDirty() {
100 return wrappedCursor.isDirty();
101 }
102
103 @Override
104 public Set<AnyVersionedMap> getDependingMaps() {
105 return wrappedCursor.getDependingMaps();
106 }
107 }
108}
diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/GeneratorResult.java b/subprojects/generator/src/main/java/tools/refinery/generator/GeneratorResult.java
new file mode 100644
index 00000000..3ce2631a
--- /dev/null
+++ b/subprojects/generator/src/main/java/tools/refinery/generator/GeneratorResult.java
@@ -0,0 +1,29 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator;
7
8public enum GeneratorResult {
9 SUCCESS {
10 @Override
11 public void orThrow() {
12 // No need to throw on error.
13 }
14 },
15 UNSATISFIABLE {
16 @Override
17 public void orThrow() {
18 throw new UnsatisfiableProblemException();
19 }
20 },
21 TIMEOUT {
22 @Override
23 public void orThrow() {
24 throw new GeneratorTimeoutException();
25 }
26 };
27
28 public abstract void orThrow();
29}
diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/GeneratorTimeoutException.java b/subprojects/generator/src/main/java/tools/refinery/generator/GeneratorTimeoutException.java
new file mode 100644
index 00000000..4312a324
--- /dev/null
+++ b/subprojects/generator/src/main/java/tools/refinery/generator/GeneratorTimeoutException.java
@@ -0,0 +1,12 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator;
7
8public class GeneratorTimeoutException extends RuntimeException {
9 public GeneratorTimeoutException() {
10 super("Model generation timed out");
11 }
12}
diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/ModelFacadeFactory.java b/subprojects/generator/src/main/java/tools/refinery/generator/ModelFacadeFactory.java
new file mode 100644
index 00000000..173be38e
--- /dev/null
+++ b/subprojects/generator/src/main/java/tools/refinery/generator/ModelFacadeFactory.java
@@ -0,0 +1,61 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator;
7
8import com.google.inject.Inject;
9import com.google.inject.Provider;
10import tools.refinery.language.semantics.ModelInitializer;
11import tools.refinery.store.util.CancellationToken;
12
13// This class is used as a fluent builder, so it's not necessary to use the return value of all of its methods.
14@SuppressWarnings("UnusedReturnValue")
15public abstract sealed class ModelFacadeFactory<T extends ModelFacadeFactory<T>> permits ModelSemanticsFactory,
16 ModelGeneratorFactory {
17 @Inject
18 private Provider<ModelInitializer> initializerProvider;
19
20 private CancellationToken cancellationToken = CancellationToken.NONE;
21
22 private boolean keepNonExistingObjects;
23
24 private boolean keepShadowPredicates = true;
25
26 protected abstract T getSelf();
27
28 public T cancellationToken(CancellationToken cancellationToken) {
29 this.cancellationToken = cancellationToken;
30 return getSelf();
31 }
32
33 public T keepNonExistingObjects(boolean keepNonExistentObjects) {
34 this.keepNonExistingObjects = keepNonExistentObjects;
35 return getSelf();
36 }
37
38 public T keepShadowPredicates(boolean keepShadowPredicates) {
39 this.keepShadowPredicates = keepShadowPredicates;
40 return getSelf();
41 }
42
43 protected ModelInitializer createModelInitializer() {
44 var initializer = initializerProvider.get();
45 initializer.setKeepNonExistingObjects(keepNonExistingObjects);
46 initializer.setKeepShadowPredicates(keepShadowPredicates);
47 return initializer;
48 }
49
50 protected CancellationToken getCancellationToken() {
51 return cancellationToken;
52 }
53
54 protected boolean isKeepNonExistingObjects() {
55 return keepNonExistingObjects;
56 }
57
58 protected void checkCancelled() {
59 cancellationToken.checkCancelled();
60 }
61}
diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/ModelGenerator.java b/subprojects/generator/src/main/java/tools/refinery/generator/ModelGenerator.java
index 8dff5622..2f459eb9 100644
--- a/subprojects/generator/src/main/java/tools/refinery/generator/ModelGenerator.java
+++ b/subprojects/generator/src/main/java/tools/refinery/generator/ModelGenerator.java
@@ -10,26 +10,38 @@ import tools.refinery.language.model.problem.Problem;
10import tools.refinery.language.semantics.ProblemTrace; 10import tools.refinery.language.semantics.ProblemTrace;
11import tools.refinery.language.semantics.SolutionSerializer; 11import tools.refinery.language.semantics.SolutionSerializer;
12import tools.refinery.logic.AbstractValue; 12import tools.refinery.logic.AbstractValue;
13import tools.refinery.logic.term.truthvalue.TruthValue;
13import tools.refinery.store.dse.strategy.BestFirstStoreManager; 14import tools.refinery.store.dse.strategy.BestFirstStoreManager;
14import tools.refinery.store.dse.transition.statespace.SolutionStore; 15import tools.refinery.store.dse.transition.statespace.SolutionStore;
15import tools.refinery.store.map.Version; 16import tools.refinery.store.map.Version;
16import tools.refinery.store.model.ModelStore; 17import tools.refinery.store.model.ModelStore;
18import tools.refinery.store.reasoning.ReasoningAdapter;
17import tools.refinery.store.reasoning.interpretation.PartialInterpretation; 19import tools.refinery.store.reasoning.interpretation.PartialInterpretation;
18import tools.refinery.store.reasoning.literal.Concreteness; 20import tools.refinery.store.reasoning.literal.Concreteness;
19import tools.refinery.store.reasoning.representation.PartialSymbol; 21import tools.refinery.store.reasoning.representation.PartialSymbol;
20import tools.refinery.store.reasoning.seed.ModelSeed; 22import tools.refinery.store.reasoning.seed.ModelSeed;
21 23
24import java.util.concurrent.Executors;
25import java.util.concurrent.TimeUnit;
26
22public class ModelGenerator extends ModelFacade { 27public class ModelGenerator extends ModelFacade {
23 private final Version initialVersion; 28 private final Version initialVersion;
24 private final Provider<SolutionSerializer> solutionSerializerProvider; 29 private final Provider<SolutionSerializer> solutionSerializerProvider;
30 private final CancellableCancellationToken cancellationToken;
31 private final boolean keepNonExistingObjects;
32 private final PartialInterpretation<TruthValue, Boolean> existsInterpretation;
25 private long randomSeed = 1; 33 private long randomSeed = 1;
26 private int maxNumberOfSolutions = 1; 34 private int maxNumberOfSolutions = 1;
27 private SolutionStore solutionStore; 35 private SolutionStore solutionStore;
28 36
29 ModelGenerator(ProblemTrace problemTrace, ModelStore store, ModelSeed modelSeed, 37 ModelGenerator(ProblemTrace problemTrace, ModelStore store, ModelSeed modelSeed,
30 Provider<SolutionSerializer> solutionSerializerProvider) { 38 Provider<SolutionSerializer> solutionSerializerProvider,
39 CancellableCancellationToken cancellationToken, boolean keepNonExistingObjects) {
31 super(problemTrace, store, modelSeed, Concreteness.CANDIDATE); 40 super(problemTrace, store, modelSeed, Concreteness.CANDIDATE);
32 this.solutionSerializerProvider = solutionSerializerProvider; 41 this.solutionSerializerProvider = solutionSerializerProvider;
42 this.cancellationToken = cancellationToken;
43 this.keepNonExistingObjects = keepNonExistingObjects;
44 existsInterpretation = super.getPartialInterpretation(ReasoningAdapter.EXISTS_SYMBOL);
33 initialVersion = getModel().commit(); 45 initialVersion = getModel().commit();
34 } 46 }
35 47
@@ -71,33 +83,52 @@ public class ModelGenerator extends ModelFacade {
71 return solutionStore != null; 83 return solutionStore != null;
72 } 84 }
73 85
74 // This method only makes sense if it returns {@code true} on success. 86 public GeneratorResult tryGenerate() {
75 @SuppressWarnings("BooleanMethodIsAlwaysInverted") 87 if (cancellationToken.isCancelled()) {
76 public boolean tryGenerate() { 88 throw new IllegalStateException("Model generation was previously cancelled");
89 }
77 solutionStore = null; 90 solutionStore = null;
78 randomSeed++; 91 randomSeed++;
79 var bestFirst = new BestFirstStoreManager(getModelStore(), maxNumberOfSolutions); 92 var bestFirst = new BestFirstStoreManager(getModelStore(), maxNumberOfSolutions);
80 bestFirst.startExploration(initialVersion, randomSeed); 93 bestFirst.startExploration(initialVersion, randomSeed);
81 var solutions = bestFirst.getSolutionStore().getSolutions(); 94 var solutions = bestFirst.getSolutionStore().getSolutions();
82 if (solutions.isEmpty()) { 95 if (solutions.isEmpty()) {
83 return false; 96 return GeneratorResult.UNSATISFIABLE;
84 } 97 }
85 getModel().restore(solutions.getFirst().version()); 98 getModel().restore(solutions.getFirst().version());
86 solutionStore = bestFirst.getSolutionStore(); 99 solutionStore = bestFirst.getSolutionStore();
87 return true; 100 return GeneratorResult.SUCCESS;
88 } 101 }
89 102
90 public void generate() { 103 public void generate() {
91 if (!tryGenerate()) { 104 tryGenerate().orThrow();
92 throw new UnsatisfiableProblemException(); 105 }
106
107 public GeneratorResult tryGenerateWithTimeout(long l, TimeUnit timeUnit) {
108 try (var executorService = Executors.newSingleThreadScheduledExecutor()) {
109 var timeoutFuture = executorService.schedule(cancellationToken::cancel, l, timeUnit);
110 try {
111 return tryGenerate();
112 } catch (GeneratorTimeoutException e) {
113 return GeneratorResult.TIMEOUT;
114 } finally {
115 timeoutFuture.cancel(true);
116 cancellationToken.reset();
117 }
93 } 118 }
94 } 119 }
95 120
121 public void generateWithTimeout(long l, TimeUnit timeUnit) {
122 tryGenerateWithTimeout(l, timeUnit).orThrow();
123 }
124
96 @Override 125 @Override
97 public <A extends AbstractValue<A, C>, C> PartialInterpretation<A, C> getPartialInterpretation( 126 public <A extends AbstractValue<A, C>, C> PartialInterpretation<A, C> getPartialInterpretation(
98 PartialSymbol<A, C> partialSymbol) { 127 PartialSymbol<A, C> partialSymbol) {
99 checkSuccessfulGeneration(); 128 checkSuccessfulGeneration();
100 return super.getPartialInterpretation(partialSymbol); 129 var partialInterpretation = super.getPartialInterpretation(partialSymbol);
130 return keepNonExistingObjects ? partialInterpretation :
131 new FilteredInterpretation<>(partialInterpretation, existsInterpretation);
101 } 132 }
102 133
103 public Problem serializeSolution() { 134 public Problem serializeSolution() {
diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/ModelGeneratorFactory.java b/subprojects/generator/src/main/java/tools/refinery/generator/ModelGeneratorFactory.java
index 0a1b4396..3205eca2 100644
--- a/subprojects/generator/src/main/java/tools/refinery/generator/ModelGeneratorFactory.java
+++ b/subprojects/generator/src/main/java/tools/refinery/generator/ModelGeneratorFactory.java
@@ -8,7 +8,6 @@ package tools.refinery.generator;
8import com.google.inject.Inject; 8import com.google.inject.Inject;
9import com.google.inject.Provider; 9import com.google.inject.Provider;
10import tools.refinery.language.model.problem.Problem; 10import tools.refinery.language.model.problem.Problem;
11import tools.refinery.language.semantics.ModelInitializer;
12import tools.refinery.language.semantics.SolutionSerializer; 11import tools.refinery.language.semantics.SolutionSerializer;
13import tools.refinery.store.dse.propagation.PropagationAdapter; 12import tools.refinery.store.dse.propagation.PropagationAdapter;
14import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter; 13import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter;
@@ -20,30 +19,28 @@ import tools.refinery.store.reasoning.literal.Concreteness;
20import tools.refinery.store.statecoding.StateCodeCalculatorFactory; 19import tools.refinery.store.statecoding.StateCodeCalculatorFactory;
21import tools.refinery.store.statecoding.StateCoderAdapter; 20import tools.refinery.store.statecoding.StateCoderAdapter;
22import tools.refinery.store.statecoding.neighborhood.NeighborhoodCalculator; 21import tools.refinery.store.statecoding.neighborhood.NeighborhoodCalculator;
23import tools.refinery.store.util.CancellationToken;
24 22
25import java.util.Collection; 23import java.util.Collection;
26import java.util.Set; 24import java.util.Set;
27 25
28// This class is used as a fluent builder, so it's not necessary to use the return value of all of its methods. 26// This class is used as a fluent builder, so it's not necessary to use the return value of all of its methods.
29@SuppressWarnings("UnusedReturnValue") 27@SuppressWarnings("UnusedReturnValue")
30public final class ModelGeneratorFactory { 28public final class ModelGeneratorFactory extends ModelFacadeFactory<ModelGeneratorFactory> {
31 @Inject
32 private Provider<ModelInitializer> initializerProvider;
33
34 @Inject 29 @Inject
35 private Provider<SolutionSerializer> solutionSerializerProvider; 30 private Provider<SolutionSerializer> solutionSerializerProvider;
36 31
37 private CancellationToken cancellationToken = CancellationToken.NONE;
38
39 private boolean debugPartialInterpretations; 32 private boolean debugPartialInterpretations;
40 33
41 private boolean partialInterpretationBasedNeighborhoods; 34 private boolean partialInterpretationBasedNeighborhoods;
42 35
43 private int stateCoderDepth = NeighborhoodCalculator.DEFAULT_DEPTH; 36 private int stateCoderDepth = NeighborhoodCalculator.DEFAULT_DEPTH;
44 37
45 public ModelGeneratorFactory cancellationToken(CancellationToken cancellationToken) { 38 public ModelGeneratorFactory() {
46 this.cancellationToken = cancellationToken; 39 keepShadowPredicates(false);
40 }
41
42 @Override
43 protected ModelGeneratorFactory getSelf() {
47 return this; 44 return this;
48 } 45 }
49 46
@@ -64,22 +61,23 @@ public final class ModelGeneratorFactory {
64 } 61 }
65 62
66 public ModelGenerator createGenerator(Problem problem) { 63 public ModelGenerator createGenerator(Problem problem) {
67 var initializer = initializerProvider.get(); 64 var initializer = createModelInitializer();
68 initializer.readProblem(problem); 65 initializer.readProblem(problem);
69 cancellationToken.checkCancelled(); 66 checkCancelled();
67 var cancellationToken = new CancellableCancellationToken(getCancellationToken());
70 var storeBuilder = ModelStore.builder() 68 var storeBuilder = ModelStore.builder()
71 .cancellationToken(cancellationToken) 69 .cancellationToken(cancellationToken)
72 .with(QueryInterpreterAdapter.builder()) 70 .with(QueryInterpreterAdapter.builder())
73 .with(PropagationAdapter.builder()) 71 .with(PropagationAdapter.builder())
74 .with(StateCoderAdapter.builder() 72 .with(StateCoderAdapter.builder()
75 .stateCodeCalculatorFactory(getStateCoderCalculatorFactory())) 73 .stateCodeCalculatorFactory(getStateCodeCalculatorFactory()))
76 .with(DesignSpaceExplorationAdapter.builder()) 74 .with(DesignSpaceExplorationAdapter.builder())
77 .with(ReasoningAdapter.builder() 75 .with(ReasoningAdapter.builder()
78 .requiredInterpretations(getRequiredInterpretations())); 76 .requiredInterpretations(getRequiredInterpretations()));
79 initializer.configureStoreBuilder(storeBuilder); 77 initializer.configureStoreBuilder(storeBuilder);
80 var store = storeBuilder.build(); 78 var store = storeBuilder.build();
81 var generator = new ModelGenerator(initializer.getProblemTrace(), store, initializer.getModelSeed(), 79 var generator = new ModelGenerator(initializer.getProblemTrace(), store, initializer.getModelSeed(),
82 solutionSerializerProvider); 80 solutionSerializerProvider, cancellationToken, isKeepNonExistingObjects());
83 generator.getPropagationResult().throwIfRejected(); 81 generator.getPropagationResult().throwIfRejected();
84 return generator; 82 return generator;
85 } 83 }
@@ -90,7 +88,7 @@ public final class ModelGeneratorFactory {
90 Set.of(Concreteness.CANDIDATE); 88 Set.of(Concreteness.CANDIDATE);
91 } 89 }
92 90
93 private StateCodeCalculatorFactory getStateCoderCalculatorFactory() { 91 private StateCodeCalculatorFactory getStateCodeCalculatorFactory() {
94 return partialInterpretationBasedNeighborhoods ? 92 return partialInterpretationBasedNeighborhoods ?
95 PartialNeighborhoodCalculator.factory(Concreteness.PARTIAL, stateCoderDepth) : 93 PartialNeighborhoodCalculator.factory(Concreteness.PARTIAL, stateCoderDepth) :
96 NeighborhoodCalculator.factory(stateCoderDepth); 94 NeighborhoodCalculator.factory(stateCoderDepth);
diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/ModelSemanticsFactory.java b/subprojects/generator/src/main/java/tools/refinery/generator/ModelSemanticsFactory.java
index 3c3488df..37a478eb 100644
--- a/subprojects/generator/src/main/java/tools/refinery/generator/ModelSemanticsFactory.java
+++ b/subprojects/generator/src/main/java/tools/refinery/generator/ModelSemanticsFactory.java
@@ -5,27 +5,28 @@
5 */ 5 */
6package tools.refinery.generator; 6package tools.refinery.generator;
7 7
8import com.google.inject.Inject;
9import com.google.inject.Provider;
10import tools.refinery.language.model.problem.Problem; 8import tools.refinery.language.model.problem.Problem;
11import tools.refinery.language.semantics.ModelInitializer;
12import tools.refinery.store.dse.propagation.PropagationAdapter; 9import tools.refinery.store.dse.propagation.PropagationAdapter;
13import tools.refinery.store.model.ModelStore; 10import tools.refinery.store.model.ModelStore;
14import tools.refinery.store.query.interpreter.QueryInterpreterAdapter; 11import tools.refinery.store.query.interpreter.QueryInterpreterAdapter;
15import tools.refinery.store.reasoning.ReasoningAdapter; 12import tools.refinery.store.reasoning.ReasoningAdapter;
16import tools.refinery.store.reasoning.literal.Concreteness; 13import tools.refinery.store.reasoning.literal.Concreteness;
17import tools.refinery.store.util.CancellationToken;
18 14
15import java.util.Collection;
19import java.util.Set; 16import java.util.Set;
20 17
21public final class ModelSemanticsFactory { 18// This class is used as a fluent builder, so it's not necessary to use the return value of all of its methods.
22 @Inject 19@SuppressWarnings("UnusedReturnValue")
23 private Provider<ModelInitializer> initializerProvider; 20public final class ModelSemanticsFactory extends ModelFacadeFactory<ModelSemanticsFactory> {
21 private boolean withCandidateInterpretations;
24 22
25 private CancellationToken cancellationToken = CancellationToken.NONE; 23 @Override
24 protected ModelSemanticsFactory getSelf() {
25 return this;
26 }
26 27
27 public ModelSemanticsFactory cancellationToken(CancellationToken cancellationToken) { 28 public ModelSemanticsFactory withCandidateInterpretations(boolean withCandidateInterpretations) {
28 this.cancellationToken = cancellationToken; 29 this.withCandidateInterpretations = withCandidateInterpretations;
29 return this; 30 return this;
30 } 31 }
31 32
@@ -36,17 +37,23 @@ public final class ModelSemanticsFactory {
36 } 37 }
37 38
38 public ModelSemantics tryCreateSemantics(Problem problem) { 39 public ModelSemantics tryCreateSemantics(Problem problem) {
39 var initializer = initializerProvider.get(); 40 var initializer = createModelInitializer();
40 initializer.readProblem(problem); 41 initializer.readProblem(problem);
42 checkCancelled();
41 var storeBuilder = ModelStore.builder() 43 var storeBuilder = ModelStore.builder()
42 .cancellationToken(cancellationToken) 44 .cancellationToken(getCancellationToken())
43 .with(QueryInterpreterAdapter.builder()) 45 .with(QueryInterpreterAdapter.builder())
44 .with(PropagationAdapter.builder() 46 .with(PropagationAdapter.builder()
45 .throwOnFatalRejection(false)) 47 .throwOnFatalRejection(false))
46 .with(ReasoningAdapter.builder() 48 .with(ReasoningAdapter.builder()
47 .requiredInterpretations(Set.of(Concreteness.PARTIAL))); 49 .requiredInterpretations(getRequiredInterpretations()));
48 initializer.configureStoreBuilder(storeBuilder); 50 initializer.configureStoreBuilder(storeBuilder);
49 var store = storeBuilder.build(); 51 var store = storeBuilder.build();
50 return new ModelSemantics(initializer.getProblemTrace(), store, initializer.getModelSeed()); 52 return new ModelSemantics(initializer.getProblemTrace(), store, initializer.getModelSeed());
51 } 53 }
54
55 private Collection<Concreteness> getRequiredInterpretations() {
56 return withCandidateInterpretations ? Set.of(Concreteness.PARTIAL, Concreteness.CANDIDATE) :
57 Set.of(Concreteness.PARTIAL);
58 }
52} 59}
diff --git a/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java b/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java
new file mode 100644
index 00000000..42ae9466
--- /dev/null
+++ b/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java
@@ -0,0 +1,41 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator;
7
8import com.google.inject.Inject;
9import com.google.inject.Provider;
10import org.junit.jupiter.api.DynamicNode;
11import org.junit.jupiter.api.TestFactory;
12import tools.refinery.generator.tests.DynamicTestLoader;
13import tools.refinery.language.tests.InjectWithRefinery;
14
15import java.util.stream.Stream;
16
17@InjectWithRefinery
18class FileBasedSemanticsTest {
19 @Inject
20 private DynamicTestLoader loader;
21
22 @Inject
23 private Provider<ModelSemanticsFactory> semanticsFactoryProvider;
24
25 @TestFactory
26 Stream<DynamicNode> testWithNonExistingObjects() {
27 return getFileBasedTests(true, true);
28 }
29
30 @TestFactory
31 Stream<DynamicNode> testWithoutNonExistingObjects() {
32 return getFileBasedTests(false, false);
33 }
34
35 private Stream<DynamicNode> getFileBasedTests(boolean keepNonExistingObjects, boolean keepShadowPredicates) {
36 loader.setSemanticsFactoryProvider(() -> semanticsFactoryProvider.get()
37 .keepNonExistingObjects(keepNonExistingObjects)
38 .keepShadowPredicates(keepShadowPredicates));
39 return loader.allFromClasspath(getClass());
40 }
41}
diff --git a/subprojects/generator/src/test/java/tools/refinery/generator/ProblemLoaderTest.java b/subprojects/generator/src/test/java/tools/refinery/generator/ProblemLoaderTest.java
index f0b546d7..14ae1493 100644
--- a/subprojects/generator/src/test/java/tools/refinery/generator/ProblemLoaderTest.java
+++ b/subprojects/generator/src/test/java/tools/refinery/generator/ProblemLoaderTest.java
@@ -5,15 +5,11 @@
5 */ 5 */
6package tools.refinery.generator; 6package tools.refinery.generator;
7 7
8
9import com.google.inject.Inject; 8import com.google.inject.Inject;
10import org.eclipse.xtext.testing.InjectWith;
11import org.eclipse.xtext.testing.extensions.InjectionExtension;
12import org.junit.jupiter.api.extension.ExtendWith;
13import org.junit.jupiter.params.ParameterizedTest; 9import org.junit.jupiter.params.ParameterizedTest;
14import org.junit.jupiter.params.provider.Arguments; 10import org.junit.jupiter.params.provider.Arguments;
15import org.junit.jupiter.params.provider.MethodSource; 11import org.junit.jupiter.params.provider.MethodSource;
16import tools.refinery.language.tests.ProblemInjectorProvider; 12import tools.refinery.language.tests.InjectWithRefinery;
17 13
18import java.io.ByteArrayOutputStream; 14import java.io.ByteArrayOutputStream;
19import java.io.IOException; 15import java.io.IOException;
@@ -25,8 +21,7 @@ import java.util.stream.Stream;
25import static org.hamcrest.MatcherAssert.assertThat; 21import static org.hamcrest.MatcherAssert.assertThat;
26import static org.hamcrest.Matchers.is; 22import static org.hamcrest.Matchers.is;
27 23
28@ExtendWith(InjectionExtension.class) 24@InjectWithRefinery
29@InjectWith(ProblemInjectorProvider.class)
30class ProblemLoaderTest { 25class ProblemLoaderTest {
31 private static final String PREFIX = """ 26 private static final String PREFIX = """
32 class Foo. 27 class Foo.
diff --git a/subprojects/generator/src/test/resources/tools/refinery/generator/crossreference/typeConstraint.problem b/subprojects/generator/src/test/resources/tools/refinery/generator/crossreference/typeConstraint.problem
new file mode 100644
index 00000000..4c24fa5a
--- /dev/null
+++ b/subprojects/generator/src/test/resources/tools/refinery/generator/crossreference/typeConstraint.problem
@@ -0,0 +1,85 @@
1% Copyright (c) 2024 The Refinery Authors <https://refinery.tools/>
2%
3% SPDX-License-Identifier: EPL-2.0
4
5% TEST WITH ERRORS: directed cross reference type constraint
6
7class A {
8 B[] foo
9}
10
11class B.
12
13foo(a1, b1).
14!foo(a2, b2).
15?foo(a3, b3).
16foo(a4, b4): error.
17
18% EXPECT EXACTLY:
19foo(a1, b1).
20!foo(a2, b2).
21?foo(a3, b3).
22foo(a4, b4): error.
23A(a1).
24B(b1).
25?A(a2).
26?B(b2).
27?A(a3).
28?B(b3).
29A(a4).
30B(b4).
31
32% TEST: directed cross reference with predicate type
33
34class A {
35 bar[] foo
36}
37
38pred bar(A a) <-> !foo(a, _).
39
40foo(a1, b1).
41
42% EXPECT:
43A(a1).
44bar(b1).
45
46% TEST WITH ERRORS: directed cross reference with predicate type and assertion
47
48class A {
49 bar[] foo
50}
51
52pred bar(A a) <-> !foo(a, _).
53
54!bar(b1).
55foo(a1, b1).
56
57% EXPECT EXACTLY:
58foo(a1, b1): error.
59A(a1).
60bar(b1): error.
61
62% TEST WITH ERRORS: undirected cross reference type constraint
63
64class A {
65 A[] bar opposite bar
66}
67
68bar(a1, b1).
69!bar(a2, b2).
70?bar(a3, b3).
71bar(a4, b4): error.
72
73% EXPECT EXACTLY:
74bar(a1, b1).
75!bar(a2, b2).
76?bar(a3, b3).
77bar(a4, b4): error.
78A(a1).
79A(b1).
80?A(a2).
81?A(b2).
82?A(a3).
83?A(b3).
84A(a4).
85A(b4).
diff --git a/subprojects/generator/src/test/resources/tools/refinery/generator/crossreference/undirectedMultiplicity.problem b/subprojects/generator/src/test/resources/tools/refinery/generator/crossreference/undirectedMultiplicity.problem
new file mode 100644
index 00000000..bd9fd147
--- /dev/null
+++ b/subprojects/generator/src/test/resources/tools/refinery/generator/crossreference/undirectedMultiplicity.problem
@@ -0,0 +1,57 @@
1% Copyright (c) 2024 The Refinery Authors <https://refinery.tools/>
2%
3% SPDX-License-Identifier: EPL-2.0
4
5% TEST: upper bound propagation
6
7class Person {
8 Person[0..2] friend opposite friend
9}
10
11friend(a, b).
12friend(a, c).
13friend(b, c).
14!exists(Person::new).
15
16% EXPECT:
17friend(b, a).
18friend(c, a).
19friend(c, b).
20!friend(a, a).
21!friend(b, b).
22!friend(c, c).
23
24% TEST: lower bound propagation
25
26class Person {
27 Person[2..*] friend opposite friend
28}
29
30Person(a).
31!friend(a, a).
32!friend(b, b).
33!friend(c, c).
34!exists(Person::new).
35
36% EXPECT:
37friend(a, b).
38friend(a, c).
39friend(b, c).
40
41% TEST: upper and lower bound propagation
42
43class Person {
44 Person[2] friend opposite friend
45}
46
47friend(a, b).
48friend(a, c).
49!friend(b, b).
50!friend(c, c).
51!exists(Person::new).
52
53% EXPECT:
54friend(b, c).
55!friend(a, a).
56!friend(b, b).
57!friend(c, c).
diff --git a/subprojects/generator/src/test/resources/tools/refinery/generator/sudoku.problem b/subprojects/generator/src/test/resources/tools/refinery/generator/sudoku.problem
new file mode 100644
index 00000000..fa5b7159
--- /dev/null
+++ b/subprojects/generator/src/test/resources/tools/refinery/generator/sudoku.problem
@@ -0,0 +1,384 @@
1% Copyright (c) 2020 Frank McSherry
2% Copyright (c) 2024 The Refinery Authors <https://refinery.tools/>
3%
4% SPDX-License-Identifier: MIT AND EPL-2.0
5%
6% The sudoku example in this file was adapted from Frank McSherry's
7% differential-dataflow tutorial, which is available at
8% https://www.youtube.com/watch?v=DR5V5bNpclg and
9% https://github.com/frankmcsherry/WIP/tree/master/sudoku
10
11class Row {
12 Field[9] field opposite row
13}
14
15class Column {
16 Field[9] field opposite column
17}
18
19class Block {
20 Field[9] field opposite block
21}
22
23class Field {
24 Row[1] row opposite field
25 Column[1] column opposite field
26 Block[1] block opposite field
27 Number[1] number
28}
29
30class Number.
31
32error multipleInRow(r, n) <->
33 row(f1, r),
34 row(f2, r),
35 f1 != f2,
36 number(f1, n),
37 number(f2, n).
38
39propagation rule singleInRow(f, n) <->
40 may number(f, n),
41 row(f, r),
42 !multipleInRow::computed(r, n)
43==>
44 number(f, n).
45
46propagation rule noMoreInRow(f, n) <->
47 row(f, r),
48 number(f2, n),
49 row(f2, r),
50 f != f2
51==>
52 !number(f, n).
53
54error multipleInColumn(c, n) <->
55 column(f1, c),
56 column(f2, c),
57 f1 != f2,
58 number(f1, n),
59 number(f2, n).
60
61propagation rule singleInColumn(f, n) <->
62 may number(f, n),
63 column(n, c),
64 !multipleInColumn::computed(c, n)
65==>
66 number(f, n).
67
68propagation rule noMoreInColumn(f, n) <->
69 column(f, c),
70 number(f2, n),
71 column(f2, c),
72 f != f2
73==>
74 !number(f, n).
75
76error multipleInBlock(b, n) <->
77 block(f1, b),
78 block(f2, b),
79 f1 != f2,
80 number(f1, n),
81 number(f2, n).
82
83propagation rule singleInBlock(f, n) <->
84 may number(f, n),
85 block(f, b),
86 !multipleInBlock::computed(b, n)
87==>
88 number(f, n).
89
90propagation rule noMoreInBlock(f, n) <->
91 block(f, b),
92 number(f2, n),
93 block(f2, b),
94 f != f2
95==>
96 !number(f, n).
97
98Number(n1).
99Number(n2).
100Number(n3).
101Number(n4).
102Number(n5).
103Number(n6).
104Number(n7).
105Number(n8).
106Number(n9).
107
108row(f1_1, r1). column(f1_1, c1). block(f1_1, b1_1).
109row(f1_2, r1). column(f1_2, c2). block(f1_2, b1_1).
110row(f1_3, r1). column(f1_3, c3). block(f1_3, b1_1).
111row(f1_4, r1). column(f1_4, c4). block(f1_4, b1_2).
112row(f1_5, r1). column(f1_5, c5). block(f1_5, b1_2).
113row(f1_6, r1). column(f1_6, c6). block(f1_6, b1_2).
114row(f1_7, r1). column(f1_7, c7). block(f1_7, b1_3).
115row(f1_8, r1). column(f1_8, c8). block(f1_8, b1_3).
116row(f1_9, r1). column(f1_9, c9). block(f1_9, b1_3).
117row(f2_1, r2). column(f2_1, c1). block(f2_1, b1_1).
118row(f2_2, r2). column(f2_2, c2). block(f2_2, b1_1).
119row(f2_3, r2). column(f2_3, c3). block(f2_3, b1_1).
120row(f2_4, r2). column(f2_4, c4). block(f2_4, b1_2).
121row(f2_5, r2). column(f2_5, c5). block(f2_5, b1_2).
122row(f2_6, r2). column(f2_6, c6). block(f2_6, b1_2).
123row(f2_7, r2). column(f2_7, c7). block(f2_7, b1_3).
124row(f2_8, r2). column(f2_8, c8). block(f2_8, b1_3).
125row(f2_9, r2). column(f2_9, c9). block(f2_9, b1_3).
126row(f3_1, r3). column(f3_1, c1). block(f3_1, b1_1).
127row(f3_2, r3). column(f3_2, c2). block(f3_2, b1_1).
128row(f3_3, r3). column(f3_3, c3). block(f3_3, b1_1).
129row(f3_4, r3). column(f3_4, c4). block(f3_4, b1_2).
130row(f3_5, r3). column(f3_5, c5). block(f3_5, b1_2).
131row(f3_6, r3). column(f3_6, c6). block(f3_6, b1_2).
132row(f3_7, r3). column(f3_7, c7). block(f3_7, b1_3).
133row(f3_8, r3). column(f3_8, c8). block(f3_8, b1_3).
134row(f3_9, r3). column(f3_9, c9). block(f3_9, b1_3).
135row(f4_1, r4). column(f4_1, c1). block(f4_1, b2_1).
136row(f4_2, r4). column(f4_2, c2). block(f4_2, b2_1).
137row(f4_3, r4). column(f4_3, c3). block(f4_3, b2_1).
138row(f4_4, r4). column(f4_4, c4). block(f4_4, b2_2).
139row(f4_5, r4). column(f4_5, c5). block(f4_5, b2_2).
140row(f4_6, r4). column(f4_6, c6). block(f4_6, b2_2).
141row(f4_7, r4). column(f4_7, c7). block(f4_7, b2_3).
142row(f4_8, r4). column(f4_8, c8). block(f4_8, b2_3).
143row(f4_9, r4). column(f4_9, c9). block(f4_9, b2_3).
144row(f5_1, r5). column(f5_1, c1). block(f5_1, b2_1).
145row(f5_2, r5). column(f5_2, c2). block(f5_2, b2_1).
146row(f5_3, r5). column(f5_3, c3). block(f5_3, b2_1).
147row(f5_4, r5). column(f5_4, c4). block(f5_4, b2_2).
148row(f5_5, r5). column(f5_5, c5). block(f5_5, b2_2).
149row(f5_6, r5). column(f5_6, c6). block(f5_6, b2_2).
150row(f5_7, r5). column(f5_7, c7). block(f5_7, b2_3).
151row(f5_8, r5). column(f5_8, c8). block(f5_8, b2_3).
152row(f5_9, r5). column(f5_9, c9). block(f5_9, b2_3).
153row(f6_1, r6). column(f6_1, c1). block(f6_1, b2_1).
154row(f6_2, r6). column(f6_2, c2). block(f6_2, b2_1).
155row(f6_3, r6). column(f6_3, c3). block(f6_3, b2_1).
156row(f6_4, r6). column(f6_4, c4). block(f6_4, b2_2).
157row(f6_5, r6). column(f6_5, c5). block(f6_5, b2_2).
158row(f6_6, r6). column(f6_6, c6). block(f6_6, b2_2).
159row(f6_7, r6). column(f6_7, c7). block(f6_7, b2_3).
160row(f6_8, r6). column(f6_8, c8). block(f6_8, b2_3).
161row(f6_9, r6). column(f6_9, c9). block(f6_9, b2_3).
162row(f7_1, r7). column(f7_1, c1). block(f7_1, b3_1).
163row(f7_2, r7). column(f7_2, c2). block(f7_2, b3_1).
164row(f7_3, r7). column(f7_3, c3). block(f7_3, b3_1).
165row(f7_4, r7). column(f7_4, c4). block(f7_4, b3_2).
166row(f7_5, r7). column(f7_5, c5). block(f7_5, b3_2).
167row(f7_6, r7). column(f7_6, c6). block(f7_6, b3_2).
168row(f7_7, r7). column(f7_7, c7). block(f7_7, b3_3).
169row(f7_8, r7). column(f7_8, c8). block(f7_8, b3_3).
170row(f7_9, r7). column(f7_9, c9). block(f7_9, b3_3).
171row(f8_1, r8). column(f8_1, c1). block(f8_1, b3_1).
172row(f8_2, r8). column(f8_2, c2). block(f8_2, b3_1).
173row(f8_3, r8). column(f8_3, c3). block(f8_3, b3_1).
174row(f8_4, r8). column(f8_4, c4). block(f8_4, b3_2).
175row(f8_5, r8). column(f8_5, c5). block(f8_5, b3_2).
176row(f8_6, r8). column(f8_6, c6). block(f8_6, b3_2).
177row(f8_7, r8). column(f8_7, c7). block(f8_7, b3_3).
178row(f8_8, r8). column(f8_8, c8). block(f8_8, b3_3).
179row(f8_9, r8). column(f8_9, c9). block(f8_9, b3_3).
180row(f9_1, r9). column(f9_1, c1). block(f9_1, b3_1).
181row(f9_2, r9). column(f9_2, c2). block(f9_2, b3_1).
182row(f9_3, r9). column(f9_3, c3). block(f9_3, b3_1).
183row(f9_4, r9). column(f9_4, c4). block(f9_4, b3_2).
184row(f9_5, r9). column(f9_5, c5). block(f9_5, b3_2).
185row(f9_6, r9). column(f9_6, c6). block(f9_6, b3_2).
186row(f9_7, r9). column(f9_7, c7). block(f9_7, b3_3).
187row(f9_8, r9). column(f9_8, c8). block(f9_8, b3_3).
188row(f9_9, r9). column(f9_9, c9). block(f9_9, b3_3).
189
190scope Field += 0, Number += 0.
191
192% TEST: initial grid is not filled
193
194pred filled() <-> number(_, _).
195
196% EXPECT EXACTLY:
197
198?filled().
199
200% TEST: sudoku with single solution
201
202% Adapted from Frank McSherry's differential-dataflow tutorial,
203% which is available at https://www.youtube.com/watch?v=DR5V5bNpclg and
204% https://github.com/frankmcsherry/WIP/tree/master/sudoku
205%
206% 53.|.7.|...
207% 6..|195|...
208% .98|...|.6.
209% ---+---+---
210% 8..|.6.|..3
211% 4..|8.3|..1
212% 7..|.2.|..6
213% ---+---+---
214% .6.|...|28.
215% ...|419|..5
216% ...|.8.|.79
217
218number(f1_1, n5).
219number(f1_2, n3).
220number(f1_5, n7).
221number(f2_1, n6).
222number(f2_4, n1).
223number(f2_5, n9).
224number(f2_6, n5).
225number(f3_2, n9).
226number(f3_3, n8).
227number(f3_8, n6).
228number(f4_1, n8).
229number(f4_5, n6).
230number(f4_9, n3).
231number(f5_1, n4).
232number(f5_4, n8).
233number(f5_6, n3).
234number(f5_9, n1).
235number(f6_1, n7).
236number(f6_5, n2).
237number(f6_9, n6).
238number(f7_2, n6).
239number(f7_7, n2).
240number(f7_8, n8).
241number(f8_4, n4).
242number(f8_5, n1).
243number(f8_6, n9).
244number(f8_9, n5).
245number(f9_5, n8).
246number(f9_8, n7).
247number(f9_9, n9).
248
249% EXPECT:
250
251% 534|678|912
252% 672|195|348
253% 198|342|567
254% ---+---+---
255% 859|761|423
256% 426|853|791
257% 713|924|856
258% ---+---+---
259% 961|537|284
260% 287|419|635
261% 345|286|179
262
263number(f1_1, n5).
264number(f1_2, n3).
265number(f1_3, n4).
266number(f1_4, n6).
267number(f1_5, n7).
268number(f1_6, n8).
269number(f1_7, n9).
270number(f1_8, n1).
271number(f1_9, n2).
272number(f2_1, n6).
273number(f2_2, n7).
274number(f2_3, n2).
275number(f2_4, n1).
276number(f2_5, n9).
277number(f2_6, n5).
278number(f2_7, n3).
279number(f2_8, n4).
280number(f2_9, n8).
281number(f3_1, n1).
282number(f3_2, n9).
283number(f3_3, n8).
284number(f3_4, n3).
285number(f3_5, n4).
286number(f3_6, n2).
287number(f3_7, n5).
288number(f3_8, n6).
289number(f3_9, n7).
290number(f4_1, n8).
291number(f4_2, n5).
292number(f4_3, n9).
293number(f4_4, n7).
294number(f4_5, n6).
295number(f4_6, n1).
296number(f4_7, n4).
297number(f4_8, n2).
298number(f4_9, n3).
299number(f5_1, n4).
300number(f5_2, n2).
301number(f5_3, n6).
302number(f5_4, n8).
303number(f5_5, n5).
304number(f5_6, n3).
305number(f5_7, n7).
306number(f5_8, n9).
307number(f5_9, n1).
308number(f6_1, n7).
309number(f6_2, n1).
310number(f6_3, n3).
311number(f6_4, n9).
312number(f6_5, n2).
313number(f6_6, n4).
314number(f6_7, n8).
315number(f6_8, n5).
316number(f6_9, n6).
317number(f7_1, n9).
318number(f7_2, n6).
319number(f7_3, n1).
320number(f7_4, n5).
321number(f7_5, n3).
322number(f7_6, n7).
323number(f7_7, n2).
324number(f7_8, n8).
325number(f7_9, n4).
326number(f8_1, n2).
327number(f8_2, n8).
328number(f8_3, n7).
329number(f8_4, n4).
330number(f8_5, n1).
331number(f8_6, n9).
332number(f8_7, n6).
333number(f8_8, n3).
334number(f8_9, n5).
335number(f9_1, n3).
336number(f9_2, n4).
337number(f9_3, n5).
338number(f9_4, n2).
339number(f9_5, n8).
340number(f9_6, n6).
341number(f9_7, n1).
342number(f9_8, n7).
343number(f9_9, n9).
344
345% TEST: sudoku with multiple solutions
346
347pred notFilled(Field f) <-> !number(f, _).
348
349pred allFilled() <-> !notFilled(_).
350
351number(f1_1, n5).
352number(f1_2, n3).
353number(f1_5, n7).
354number(f2_1, n6).
355number(f2_4, n1).
356number(f2_5, n9).
357number(f2_6, n5).
358number(f3_2, n9).
359number(f3_3, n8).
360number(f3_8, n6).
361number(f4_1, n8).
362number(f4_5, n6).
363number(f4_9, n3).
364number(f5_1, n4).
365number(f5_4, n8).
366number(f5_6, n3).
367number(f5_9, n1).
368number(f6_1, n7).
369number(f6_5, n2).
370number(f6_9, n6).
371number(f7_2, n6).
372% number(f7_7, n2).
373number(f7_8, n8).
374number(f8_4, n4).
375number(f8_5, n1).
376number(f8_6, n9).
377number(f8_9, n5).
378number(f9_5, n8).
379number(f9_8, n7).
380number(f9_9, n9).
381
382% EXPECT EXACTLY:
383
384?allFilled().
diff --git a/subprojects/generator/src/test/resources/tools/refinery/generator/typehierarchy/abstract.problem b/subprojects/generator/src/test/resources/tools/refinery/generator/typehierarchy/abstract.problem
new file mode 100644
index 00000000..559c077d
--- /dev/null
+++ b/subprojects/generator/src/test/resources/tools/refinery/generator/typehierarchy/abstract.problem
@@ -0,0 +1,47 @@
1% SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2%
3% SPDX-License-Identifier: EPL-2.0
4
5abstract class A.
6
7class B extends A.
8
9class C extends A.
10
11class D extends A.
12
13% TEST: negative subclasses
14!B(a).
15!C(a).
16!D(a).
17% EXPECT:
18!A(a).
19
20% TEST: infer subclass by exclusion
21A(a).
22!B(a).
23!C(a).
24% EXPECT:
25D(a).
26
27% TEST: candidate rounding
28A(a).
29% EXPECT EXACTLY:
30?B(a).
31?C(a).
32?D(a).
33% EXPECT CANDIDATE:
34B(a).
35!C(a).
36!D(a).
37
38% TEST: candidate rounding with exclusion
39A(a).
40!B(a).
41% EXPECT EXACTLY:
42?C(a).
43?D(a).
44% EXPECT CANDIDATE:
45!B(a).
46C(a).
47!D(a).
diff --git a/subprojects/generator/src/test/resources/tools/refinery/generator/typehierarchy/basic.problem b/subprojects/generator/src/test/resources/tools/refinery/generator/typehierarchy/basic.problem
new file mode 100644
index 00000000..2d297067
--- /dev/null
+++ b/subprojects/generator/src/test/resources/tools/refinery/generator/typehierarchy/basic.problem
@@ -0,0 +1,24 @@
1% SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
2%
3% SPDX-License-Identifier: EPL-2.0
4
5class A.
6
7class B extends A.
8
9% TEST: positive subclass
10B(b).
11% EXPECT:
12A(b).
13
14% TEST: negative superclass
15!A(b).
16% EXPECT:
17!B(b).
18
19% TEST WITH ERRORS: inconsistent type
20!A(b).
21B(b).
22% EXPECT:
23A(b): error.
24B(b): error.
diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/DynamicTestLoader.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/DynamicTestLoader.java
new file mode 100644
index 00000000..001ee3a4
--- /dev/null
+++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/DynamicTestLoader.java
@@ -0,0 +1,263 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator.tests;
7
8import com.google.inject.Inject;
9import com.google.inject.Provider;
10import org.junit.jupiter.api.DynamicNode;
11import org.junit.jupiter.api.function.Executable;
12import org.opentest4j.TestAbortedException;
13import tools.refinery.generator.ModelSemanticsFactory;
14
15import java.io.IOException;
16import java.net.URI;
17import java.net.URISyntaxException;
18import java.net.URL;
19import java.nio.file.FileSystemNotFoundException;
20import java.nio.file.FileSystems;
21import java.nio.file.Files;
22import java.nio.file.Path;
23import java.util.ArrayList;
24import java.util.Enumeration;
25import java.util.List;
26import java.util.stream.Stream;
27
28import static org.junit.jupiter.api.DynamicContainer.dynamicContainer;
29import static org.junit.jupiter.api.DynamicTest.dynamicTest;
30
31public class DynamicTestLoader {
32 private static final String TEST_SUFFIX = ".problem";
33
34 @Inject
35 private Provider<SemanticsTestLoader> testLoaderProvider;
36
37 private Provider<ModelSemanticsFactory> semanticsFactoryProvider;
38
39 @Inject
40 public void setSemanticsFactoryProvider(Provider<ModelSemanticsFactory> semanticsFactoryProvider) {
41 this.semanticsFactoryProvider = semanticsFactoryProvider;
42 }
43
44 public Stream<DynamicNode> allFromClasspath(Class<?> contextClass) {
45 var paths = getExtraPaths(contextClass);
46 if (paths.isEmpty()) {
47 throw new IllegalArgumentException("No file system paths found for class: " + contextClass);
48 }
49 var loader = getTestLoader(paths);
50 var nodes = new ArrayList<DynamicNode>();
51 for (var path : paths) {
52 List<DynamicNode> childNodes;
53 try {
54 childNodes = nodesFromPath(loader, path);
55 } catch (IOException e) {
56 throw new IllegalArgumentException("Failed to enumerate path: " + path, e);
57 }
58 nodes.addAll(childNodes);
59 }
60 if (nodes.isEmpty()) {
61 throw new TestAbortedException("No tests found for class: " + contextClass);
62 }
63 return nodes.stream();
64 }
65
66 private List<DynamicNode> nodesFromPath(SemanticsTestLoader loader, Path path) throws IOException {
67 var nodes = new ArrayList<DynamicNode>();
68 try (var childList = Files.list(path)) {
69 var iterator = childList.iterator();
70 while (iterator.hasNext()) {
71 var childPath = iterator.next();
72 var fileName = childPath.getFileName().toString();
73 var uri = childPath.toUri();
74 try {
75 if (Files.isDirectory(childPath)) {
76 var childNodes = nodesFromPath(loader, childPath);
77 if (!childNodes.isEmpty()) {
78 nodes.add(dynamicContainer(fileName, uri, childNodes.stream()));
79 }
80 } else if (fileName.endsWith(TEST_SUFFIX)) {
81 SemanticsTest test = loader.loadFile(childPath.toFile());
82 if (test != null) {
83 nodes.add(createDynamicNode(fileName, uri, test));
84 }
85 }
86 } catch (IOException | RuntimeException e) {
87 nodes.add(createErrorNode(fileName, uri, e));
88 }
89 }
90 }
91 return nodes;
92 }
93
94 public Stream<DynamicNode> fromClasspath(Class<?> contextClass, String name) {
95 var loader = getTestLoader(contextClass);
96 URL url;
97 URI uri;
98 try {
99 url = safeGetResource(contextClass, name);
100 uri = url.toURI();
101 } catch (RuntimeException | URISyntaxException e) {
102 return Stream.of(createErrorNode(name, null, e));
103 }
104 SemanticsTest test;
105 try {
106 test = loadFromUrl(loader, uri, url);
107 } catch (IOException | RuntimeException e) {
108 return Stream.of(createErrorNode(name, uri, e));
109 }
110 return createDynamicNodes(uri, test);
111 }
112
113 public Stream<DynamicNode> fromClasspath(Class<?> contextClass, String... names) {
114 return fromClasspath(contextClass, Stream.of(names));
115 }
116
117 public Stream<DynamicNode> fromClasspath(Class<?> contextClass, Stream<String> names) {
118 var loader = getTestLoader(contextClass);
119 return names.map(name -> nodeFromClasspath(loader, contextClass, name));
120 }
121
122 private DynamicNode nodeFromClasspath(SemanticsTestLoader loader, Class<?> contextClass, String name) {
123 URL url;
124 URI uri;
125 try {
126 url = safeGetResource(contextClass, name);
127 uri = url.toURI();
128 } catch (RuntimeException | URISyntaxException e) {
129 return createErrorNode(name, null, e);
130 }
131 SemanticsTest test;
132 try {
133 test = loadFromUrl(loader, uri, url);
134 } catch (IOException | RuntimeException e) {
135 return createErrorNode(name, uri, e);
136 }
137 return createDynamicNode(name, uri, test);
138 }
139
140 private static URL safeGetResource(Class<?> contextClass, String name) {
141 var url = contextClass.getResource(name);
142 if (url == null) {
143 throw new IllegalStateException("Test resource %s was not found.".formatted(name));
144 }
145 return url;
146 }
147
148 private SemanticsTest loadFromUrl(SemanticsTestLoader testLoader, URI uri, URL url) throws IOException {
149 var eclipseUri = org.eclipse.emf.common.util.URI.createURI(uri.toString());
150 try (var inputStream = url.openStream()) {
151 return testLoader.loadStream(inputStream, eclipseUri);
152 }
153 }
154
155 public Stream<DynamicNode> fromString(Class<?> contextClass, String problem) {
156 var testLoader = getTestLoader(contextClass);
157 SemanticsTest test;
158 try {
159 test = testLoader.loadString(problem);
160 } catch (RuntimeException e) {
161 return Stream.of(createErrorNode("<string>", null, e));
162 }
163 return createDynamicNodes(null, test);
164 }
165
166 public Stream<DynamicNode> fromString(String problem) {
167 return fromString(null, problem);
168 }
169
170 private DynamicNode createDynamicNode(String name, URI uri, SemanticsTest test) {
171 var testCases = test.testCases();
172 if (testCases.size() == 1 && testCases.getFirst().name() == null) {
173 var testCase = testCases.getFirst();
174 return dynamicTest(name, uri, asExecutable(testCase));
175 }
176 var children = createDynamicNodes(uri, test);
177 return dynamicContainer(name, uri, children);
178 }
179
180 private Stream<DynamicNode> createDynamicNodes(URI uri, SemanticsTest test) {
181 var testCases = test.testCases();
182 var children = new ArrayList<DynamicNode>();
183 int testCaseCount = testCases.size();
184 for (int i = 0; i < testCaseCount; i++) {
185 var testCase = testCases.get(i);
186 var testCaseName = testCase.name();
187 if (testCaseName == null) {
188 testCaseName = "[%d]".formatted(i + 1);
189 }
190 children.add(dynamicTest(testCaseName, uri, asExecutable(testCase)));
191 }
192 return children.stream();
193 }
194
195 private Executable asExecutable(SemanticsTestCase testCase) {
196 return () -> testCase.execute(semanticsFactoryProvider.get());
197 }
198
199 private DynamicNode createErrorNode(String name, URI uri, Throwable cause) {
200 var messageBuilder = new StringBuilder();
201 messageBuilder.append("Error while reading test '").append(name).append("'");
202 if (uri != null) {
203 messageBuilder.append(" from ").append(uri);
204 }
205 if (cause != null) {
206 messageBuilder.append(": ").append(cause.getMessage());
207 }
208 var message = messageBuilder.toString();
209 return dynamicTest(name, uri, () -> {
210 throw new RuntimeException(message, cause);
211 });
212 }
213
214 private SemanticsTestLoader getTestLoader(Class<?> contextClass) {
215 var extraPaths = getExtraPaths(contextClass);
216 return getTestLoader(extraPaths);
217 }
218
219 private SemanticsTestLoader getTestLoader(List<Path> extraPaths) {
220 var loader = testLoaderProvider.get();
221 extraPaths.forEach(loader::extraPath);
222 return loader;
223 }
224
225 private List<Path> getExtraPaths(Class<?> contextClass) {
226 if (contextClass == null) {
227 return List.of();
228 }
229 var resourceName = contextClass.getPackageName().replace('.', '/');
230 Enumeration<URL> resources;
231 try {
232 resources = contextClass.getClassLoader().getResources(resourceName);
233 } catch (IOException e) {
234 // Failed to find any resources.
235 return List.of();
236 }
237 var directories = new ArrayList<Path>();
238 while (resources.hasMoreElements()) {
239 var url = resources.nextElement();
240 var path = getPath(url);
241 if (path != null && path.getFileSystem() == FileSystems.getDefault()) {
242 directories.add(path);
243 }
244 }
245 return directories;
246 }
247
248 private static Path getPath(URL url) {
249 URI uri;
250 try {
251 uri = url.toURI();
252 } catch (URISyntaxException e) {
253 return null;
254 }
255 Path path;
256 try {
257 path = Path.of(uri);
258 } catch (FileSystemNotFoundException e) {
259 return null;
260 }
261 return path.toAbsolutePath();
262 }
263}
diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsExpectation.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsExpectation.java
new file mode 100644
index 00000000..5cc28cd9
--- /dev/null
+++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsExpectation.java
@@ -0,0 +1,117 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator.tests;
7
8import org.eclipse.core.runtime.AssertionFailedException;
9import tools.refinery.generator.FilteredInterpretation;
10import tools.refinery.generator.ModelSemantics;
11import tools.refinery.language.model.problem.Assertion;
12import tools.refinery.language.model.problem.Node;
13import tools.refinery.language.model.problem.NodeAssertionArgument;
14import tools.refinery.language.model.problem.WildcardAssertionArgument;
15import tools.refinery.language.semantics.SemanticsUtils;
16import tools.refinery.logic.term.truthvalue.TruthValue;
17import tools.refinery.store.reasoning.ReasoningAdapter;
18import tools.refinery.store.reasoning.interpretation.PartialInterpretation;
19import tools.refinery.store.reasoning.literal.Concreteness;
20import tools.refinery.store.tuple.Tuple;
21
22public record SemanticsExpectation(Assertion assertion, Concreteness concreteness, boolean exact,
23 int lineNumber, String description, String source) {
24 public void execute(ModelSemantics semantics) {
25 var trace = semantics.getProblemTrace();
26 var symbol = trace.getPartialRelation(assertion.getRelation());
27 var reasoningAdapter = semantics.getModel().getAdapter(ReasoningAdapter.class);
28 var interpretation = reasoningAdapter.getPartialInterpretation(concreteness, symbol);
29 var existsInterpretation = reasoningAdapter.getPartialInterpretation(concreteness,
30 ReasoningAdapter.EXISTS_SYMBOL);
31 var filteredInterpretation = new FilteredInterpretation<>(interpretation, existsInterpretation);
32
33 var arguments = assertion.getArguments();
34 int arity = arguments.size();
35 var nodeIds = new int[arity];
36 boolean wildcard = false;
37 for (int i = 0; i < arity; i++) {
38 var argument = arguments.get(i);
39 switch (argument) {
40 case NodeAssertionArgument nodeAssertionArgument -> {
41 var nodeOrVariable = nodeAssertionArgument.getNode();
42 if (!(nodeOrVariable instanceof Node node)) {
43 throw new IllegalArgumentException("Invalid Node: " + nodeOrVariable);
44 }
45 nodeIds[i] = trace.getNodeId(node);
46 }
47 case WildcardAssertionArgument ignored -> {
48 nodeIds[i] = 1;
49 wildcard = true;
50 }
51 default -> throw new IllegalArgumentException("Invalid AssertionArgument: " + argument);
52 }
53 }
54
55 var expectedValue = SemanticsUtils.getTruthValue(assertion.getValue());
56 if (wildcard) {
57 checkWildcard(filteredInterpretation, nodeIds, expectedValue);
58 } else {
59 checkSingle(filteredInterpretation, nodeIds, expectedValue);
60 }
61 }
62
63
64 private void checkSingle(PartialInterpretation<TruthValue, Boolean> interpretation, int[] nodeIds,
65 TruthValue expectedValue) {
66 var tuple = Tuple.of(nodeIds);
67 var actual = interpretation.get(tuple);
68 if (assertionFailed(expectedValue, actual)) {
69 throw new AssertionFailedException(getMessage(actual));
70 }
71 }
72
73 private void checkWildcard(PartialInterpretation<TruthValue, Boolean> interpretation, int[] nodeIds,
74 TruthValue expectedValue) {
75 int arity = nodeIds.length;
76 var cursor = interpretation.getAll();
77 while (cursor.move()) {
78 var key = cursor.getKey();
79 boolean matches = true;
80 for (int i = 0; matches && i < arity; i++) {
81 int nodeId = nodeIds[i];
82 if (nodeId >= 0 && key.get(i) != nodeId) {
83 matches = false;
84 }
85 }
86 if (matches && assertionFailed(expectedValue, cursor.getValue())) {
87 throw new AssertionFailedException(getMessage(null));
88 }
89 }
90 }
91
92 private boolean assertionFailed(TruthValue expectedValue, TruthValue actual) {
93 return !(exact ? actual.equals(expectedValue) : actual.isRefinementOf(expectedValue));
94 }
95
96 private String getMessage(TruthValue actual) {
97 var messageBuilder = new StringBuilder();
98 messageBuilder.append("EXPECT");
99 if (concreteness == Concreteness.CANDIDATE) {
100 messageBuilder.append(" CANDIDATE");
101 }
102 if (exact) {
103 messageBuilder.append(" EXACTLY");
104 }
105 messageBuilder.append(" ").append(source);
106 if (description != null) {
107 messageBuilder.append(" (").append(description).append(")");
108 }
109 if (actual == null) {
110 messageBuilder.append(" failed");
111 } else {
112 messageBuilder.append(" was ").append(actual).append(" instead");
113 }
114 messageBuilder.append(" in line ").append(lineNumber);
115 return messageBuilder.toString();
116 }
117}
diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTest.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTest.java
new file mode 100644
index 00000000..6a34f6ef
--- /dev/null
+++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTest.java
@@ -0,0 +1,18 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator.tests;
7
8import tools.refinery.generator.ModelSemanticsFactory;
9
10import java.util.List;
11
12public record SemanticsTest(List<SemanticsTestCase> testCases) {
13 public void execute(ModelSemanticsFactory semanticsFactory) {
14 for (var testCase : testCases) {
15 testCase.execute(semanticsFactory);
16 }
17 }
18}
diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestBuilder.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestBuilder.java
new file mode 100644
index 00000000..2d40af5f
--- /dev/null
+++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestBuilder.java
@@ -0,0 +1,93 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator.tests;
7
8import org.eclipse.emf.common.util.URI;
9import tools.refinery.generator.ProblemLoader;
10import tools.refinery.generator.tests.internal.*;
11
12import java.util.ArrayList;
13import java.util.Collections;
14import java.util.List;
15import java.util.regex.Pattern;
16
17class SemanticsTestBuilder implements ChunkAcceptor {
18 private final Pattern LINE_PATTERN = Pattern.compile("^.+$", Pattern.MULTILINE);
19
20 private final ProblemLoader problemLoader;
21 private final URI uri;
22 private final StringBuilder commonBuilder = new StringBuilder();
23 private final List<SemanticsTestCase> testCases = new ArrayList<>();
24 private SemanticsTestCaseBuilder testCaseBuilder;
25 private boolean singleTestMode;
26
27 public SemanticsTestBuilder(ProblemLoader problemLoader, URI uri) {
28 this.problemLoader = problemLoader;
29 this.uri = uri;
30 }
31
32 @Override
33 public void acceptChunk(ChunkHeader header, String body) {
34 switch (header) {
35 case CommonHeader ignored -> {
36 if (testCaseBuilder != null) {
37 throw new IllegalStateException("Can't accept common test code after the first test case.");
38 }
39 commonBuilder.append(body);
40 }
41 case TestCaseHeader testCaseHeader -> {
42 if (singleTestMode) {
43 throw new IllegalStateException("Can't accept TEST chunk after an EXPECT chunk.");
44 }
45 acceptTestCase(testCaseHeader, body);
46 appendEmptyLines(body);
47 }
48 case ExpectationHeader expectationHeader -> {
49 if (testCaseBuilder == null) {
50 acceptTestCase(new TestCaseHeader(false, null), null);
51 singleTestMode = true;
52 }
53 testCaseBuilder.acceptExpectation(expectationHeader, body);
54 appendEmptyLines(body);
55 }
56 default -> throw new IllegalArgumentException("Unknown ChunkHeader: " + header);
57 }
58 }
59
60 private void appendEmptyLines(String body) {
61 if (singleTestMode) {
62 return;
63 }
64 var placeholder = LINE_PATTERN.matcher(body).replaceAll("");
65 commonBuilder.append(placeholder);
66 }
67
68 private void acceptTestCase(TestCaseHeader header, String body) {
69 if (testCaseBuilder != null) {
70 testCases.add(testCaseBuilder.build());
71 }
72 var problemStringBuilder = new StringBuilder(commonBuilder);
73 if (body != null) {
74 problemStringBuilder.append(body);
75 }
76 testCaseBuilder = new SemanticsTestCaseBuilder(header, problemStringBuilder, problemLoader, uri);
77 }
78
79 @Override
80 public void acceptEnd() {
81 if (testCaseBuilder == null) {
82 throw new IllegalStateException("Test file contained no TEST or EXPECT chunks.");
83 }
84 testCases.add(testCaseBuilder.build());
85 }
86
87 public SemanticsTest build() {
88 if (testCases.isEmpty()) {
89 throw new IllegalStateException("No test cases.");
90 }
91 return new SemanticsTest(Collections.unmodifiableList(testCases));
92 }
93}
diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCase.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCase.java
new file mode 100644
index 00000000..f75cac8e
--- /dev/null
+++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCase.java
@@ -0,0 +1,103 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator.tests;
7
8import org.eclipse.collections.api.factory.primitive.IntObjectMaps;
9import org.eclipse.collections.api.map.primitive.IntObjectMap;
10import org.eclipse.core.runtime.AssertionFailedException;
11import tools.refinery.generator.FilteredInterpretation;
12import tools.refinery.generator.ModelSemantics;
13import tools.refinery.generator.ModelSemanticsFactory;
14import tools.refinery.language.model.problem.Problem;
15import tools.refinery.language.semantics.ProblemTrace;
16import tools.refinery.logic.term.truthvalue.TruthValue;
17import tools.refinery.store.map.Cursor;
18import tools.refinery.store.reasoning.ReasoningAdapter;
19import tools.refinery.store.reasoning.literal.Concreteness;
20import tools.refinery.store.reasoning.representation.PartialRelation;
21import tools.refinery.store.tuple.Tuple;
22
23import java.util.List;
24
25public record SemanticsTestCase(String name, boolean allowErrors, Problem problem,
26 List<SemanticsExpectation> expectations) {
27 public void execute(ModelSemanticsFactory semanticsFactory) {
28 semanticsFactory.withCandidateInterpretations(needsCandidateInterpretations());
29 var semantics = semanticsFactory.createSemantics(problem);
30 if (!allowErrors) {
31 checkNoErrors(semantics);
32 }
33 for (var expectation : expectations) {
34 expectation.execute(semantics);
35 }
36 }
37
38 public boolean needsCandidateInterpretations() {
39 for (var expectation : expectations) {
40 if (expectation.concreteness() == Concreteness.CANDIDATE) {
41 return true;
42 }
43 }
44 return false;
45 }
46
47 private void checkNoErrors(ModelSemantics semantics) {
48 boolean hasError = false;
49 var errorsBuilder = new StringBuilder("Errors found in partial model:\n\n");
50 var trace = semantics.getProblemTrace();
51 IntObjectMap<String> nodeNames = null;
52 var existsInterpretation = semantics.getPartialInterpretation(ReasoningAdapter.EXISTS_SYMBOL);
53 for (var symbol : trace.getRelationTrace().values()) {
54 var interpretation = new FilteredInterpretation<>(semantics.getPartialInterpretation(symbol),
55 existsInterpretation);
56 var cursor = interpretation.getAll();
57 while (cursor.move()) {
58 if (!cursor.getValue().isError()) {
59 continue;
60 }
61 hasError = true;
62 if (nodeNames == null) {
63 nodeNames = getNodeNames(trace);
64 }
65 appendError(symbol, errorsBuilder, cursor, nodeNames);
66 }
67 }
68 if (hasError) {
69 throw new AssertionFailedException(errorsBuilder.toString());
70 }
71 }
72
73 private IntObjectMap<String> getNodeNames(ProblemTrace trace) {
74 var nodeNames = IntObjectMaps.mutable.<String>empty();
75 trace.getNodeTrace().forEachKeyValue((node, i) -> {
76 var name = node.getName();
77 if (name != null) {
78 nodeNames.put(i, name);
79 }
80 });
81 return nodeNames;
82 }
83
84 private static void appendError(PartialRelation symbol, StringBuilder errorsBuilder,
85 Cursor<Tuple, TruthValue> cursor, IntObjectMap<String> nodeNames) {
86 errorsBuilder.append('\t').append(symbol.name()).append("(");
87 var key = cursor.getKey();
88 int arity = key.getSize();
89 for (int i = 0; i < arity; i++) {
90 if (i > 0) {
91 errorsBuilder.append(", ");
92 }
93 int nodeId = key.get(i);
94 var name = nodeNames.get(nodeId);
95 if (name == null) {
96 errorsBuilder.append("::").append(i);
97 } else {
98 errorsBuilder.append(name);
99 }
100 }
101 errorsBuilder.append("): error.\n");
102 }
103}
diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCaseBuilder.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCaseBuilder.java
new file mode 100644
index 00000000..cd163cb8
--- /dev/null
+++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCaseBuilder.java
@@ -0,0 +1,95 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator.tests;
7
8import org.eclipse.emf.common.util.URI;
9import org.eclipse.xtext.nodemodel.INode;
10import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
11import tools.refinery.generator.ProblemLoader;
12import tools.refinery.generator.tests.internal.ExpectationHeader;
13import tools.refinery.generator.tests.internal.TestCaseHeader;
14import tools.refinery.language.model.problem.Assertion;
15import tools.refinery.language.model.problem.Problem;
16import tools.refinery.language.model.problem.Statement;
17
18import java.io.IOException;
19import java.util.ArrayDeque;
20import java.util.ArrayList;
21import java.util.Collections;
22import java.util.Deque;
23
24class SemanticsTestCaseBuilder {
25 private final TestCaseHeader testCaseHeader;
26 private final StringBuilder stringBuilder;
27 private final ProblemLoader problemLoader;
28 private final URI uri;
29 private final Deque<ExpectationHeader> expectationsDeque = new ArrayDeque<>();
30
31 public SemanticsTestCaseBuilder(TestCaseHeader testCaseHeader, StringBuilder stringBuilder,
32 ProblemLoader problemLoader, URI uri) {
33 this.testCaseHeader = testCaseHeader;
34 this.stringBuilder = stringBuilder;
35 this.problemLoader = problemLoader;
36 this.uri = uri;
37 }
38
39 public void acceptExpectation(ExpectationHeader header, String body) {
40 stringBuilder.append(body);
41 expectationsDeque.addLast(header);
42 }
43
44 public SemanticsTestCase build() {
45 Problem problem;
46 try {
47 problem = problemLoader.loadString(stringBuilder.toString(), uri);
48 } catch (IOException e) {
49 throw new IllegalStateException("Failed to parse problem: " + uri, e);
50 }
51 if (expectationsDeque.isEmpty() && testCaseHeader.allowErrors()) {
52 throw new IllegalStateException("Test has no EXPECT chunks.");
53 }
54 var statements = problem.getStatements();
55 int initialStatementCount = 0;
56 ExpectationHeader currentHeader = null;
57 var expectations = new ArrayList<SemanticsExpectation>();
58 for (var statement : statements) {
59 var node = NodeModelUtils.findActualNodeFor(statement);
60 if (node == null) {
61 throw new IllegalStateException("No node for statement: " + statement);
62 }
63 var nextHeader = expectationsDeque.peekFirst();
64 if (nextHeader != null && node.getStartLine() >= nextHeader.startLine()) {
65 currentHeader = nextHeader;
66 expectationsDeque.removeFirst();
67 }
68 if (currentHeader == null) {
69 initialStatementCount++;
70 } else {
71 var expectation = createExpectation(currentHeader, statement, node);
72 expectations.add(expectation);
73 }
74 }
75 int statementCount = statements.size();
76 if (statementCount > initialStatementCount) {
77 statements.subList(initialStatementCount, statementCount).clear();
78 }
79 return new SemanticsTestCase(testCaseHeader.name(), testCaseHeader.allowErrors(), problem,
80 Collections.unmodifiableList(expectations));
81 }
82
83 private static SemanticsExpectation createExpectation(ExpectationHeader header, Statement statement,
84 INode node) {
85 if (!(statement instanceof Assertion assertion)) {
86 throw new IllegalArgumentException("Only assertions are supported in EXPECT chunks, got %s instead."
87 .formatted(statement.eClass().getName()));
88 }
89 if (assertion.isDefault()) {
90 throw new IllegalArgumentException("Default assertions are not supported in EXPECT chunks.");
91 }
92 return new SemanticsExpectation(assertion, header.concreteness(), header.exact(),
93 node.getStartLine(), header.description(), NodeModelUtils.getTokenText(node).strip());
94 }
95}
diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestLoader.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestLoader.java
new file mode 100644
index 00000000..82c8deb1
--- /dev/null
+++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestLoader.java
@@ -0,0 +1,71 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator.tests;
7
8import com.google.inject.Inject;
9import org.eclipse.emf.common.util.URI;
10import tools.refinery.generator.ProblemLoader;
11import tools.refinery.generator.tests.internal.ProblemSplitter;
12
13import java.io.*;
14import java.nio.charset.StandardCharsets;
15import java.nio.file.Path;
16
17public class SemanticsTestLoader {
18 @Inject
19 private ProblemSplitter problemSplitter;
20
21 @Inject
22 private ProblemLoader problemLoader;
23
24 public SemanticsTestLoader extraPath(String path) {
25 problemLoader.extraPath(Path.of(path));
26 return this;
27 }
28
29 public SemanticsTestLoader extraPath(Path path) {
30 problemLoader.extraPath(path);
31 return this;
32 }
33
34 public SemanticsTest loadString(String problemString, URI uri) {
35 var builder = new SemanticsTestBuilder(problemLoader, uri);
36 problemSplitter.transformProblem(problemString, builder);
37 return builder.build();
38 }
39
40 public SemanticsTest loadString(String problemString) {
41 return loadString(problemString, null);
42 }
43
44 public SemanticsTest loadStream(InputStream inputStream, URI uri) throws IOException {
45 byte[] bytes;
46 try (var outputStream = new ByteArrayOutputStream()) {
47 inputStream.transferTo(outputStream);
48 bytes = outputStream.toByteArray();
49 }
50 var problemString = new String(bytes, StandardCharsets.UTF_8);
51 return loadString(problemString, uri);
52 }
53
54 public SemanticsTest loadStream(InputStream inputStream) throws IOException {
55 return loadStream(inputStream, null);
56 }
57
58 public SemanticsTest loadFile(File file) throws IOException {
59 var uri = URI.createFileURI(file.getAbsolutePath());
60 try (var inputStream = new FileInputStream(file)) {
61 return loadStream(inputStream, uri);
62 }
63 }
64
65 public SemanticsTest loadFile(String filePath) throws IOException {
66 var uri = URI.createFileURI(filePath);
67 try (var inputStream = new FileInputStream(filePath)) {
68 return loadStream(inputStream, uri);
69 }
70 }
71}
diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkAcceptor.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkAcceptor.java
new file mode 100644
index 00000000..cf867b19
--- /dev/null
+++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkAcceptor.java
@@ -0,0 +1,12 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator.tests.internal;
7
8public interface ChunkAcceptor {
9 void acceptChunk(ChunkHeader header, String body);
10
11 void acceptEnd();
12}
diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkHeader.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkHeader.java
new file mode 100644
index 00000000..a69668ec
--- /dev/null
+++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ChunkHeader.java
@@ -0,0 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator.tests.internal;
7
8public sealed interface ChunkHeader permits CommonHeader, TestCaseHeader, ExpectationHeader {
9}
diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/CommonHeader.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/CommonHeader.java
new file mode 100644
index 00000000..bec9e748
--- /dev/null
+++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/CommonHeader.java
@@ -0,0 +1,18 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator.tests.internal;
7
8public final class CommonHeader implements ChunkHeader {
9 public static final CommonHeader INSTANCE = new CommonHeader();
10
11 private CommonHeader() {
12 }
13
14 @Override
15 public String toString() {
16 return getClass().getSimpleName() + "[]";
17 }
18}
diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ExpectationHeader.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ExpectationHeader.java
new file mode 100644
index 00000000..00608739
--- /dev/null
+++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ExpectationHeader.java
@@ -0,0 +1,12 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator.tests.internal;
7
8import tools.refinery.store.reasoning.literal.Concreteness;
9
10public record ExpectationHeader(Concreteness concreteness, boolean exact, String description,
11 int startLine) implements ChunkHeader {
12}
diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ProblemSplitter.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ProblemSplitter.java
new file mode 100644
index 00000000..33a0ca6e
--- /dev/null
+++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/ProblemSplitter.java
@@ -0,0 +1,92 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator.tests.internal;
7
8import com.google.inject.Inject;
9import com.google.inject.Injector;
10import com.google.inject.Provider;
11import com.google.inject.Singleton;
12import com.google.inject.name.Named;
13import org.antlr.runtime.ANTLRStringStream;
14import org.antlr.runtime.CommonToken;
15import org.antlr.runtime.Token;
16import org.antlr.runtime.TokenSource;
17import org.eclipse.xtext.parser.antlr.Lexer;
18import tools.refinery.language.parser.antlr.ProblemTokenSource;
19import tools.refinery.language.parser.antlr.lexer.InternalProblemLexer;
20import tools.refinery.store.reasoning.literal.Concreteness;
21
22import java.util.regex.Pattern;
23
24@Singleton
25public class ProblemSplitter {
26 private static final String COMMENT_PREFIX = "(//|%)\\s*";
27
28 private static final Pattern TEST_CASE_PATTERN = Pattern.compile(COMMENT_PREFIX +
29 "TEST(?<allowErrors>\\s+WITH\\s+ERRORS)?(\\s*:\\s*(?<name>\\S.*)?)?");
30
31 private static final Pattern EXPECTATION_PATTERN = Pattern.compile(COMMENT_PREFIX +
32 "EXPECT(?<candidate>\\s+CANDIDATE)?(?<exact>\\s+EXACTLY)?(\\s*:\\s*(?<description>\\S.*)?)?");
33
34 @Inject
35 @Named("org.eclipse.xtext.parser.antlr.Lexer.RUNTIME")
36 private Provider<Lexer> lexerProvider;
37
38 @Inject
39 private Injector injector;
40
41 public void transformProblem(String problemString, ChunkAcceptor acceptor) {
42 var tokenSource = getTokenSource(problemString);
43 Token token = tokenSource.nextToken();
44 ChunkHeader lastHeader = CommonHeader.INSTANCE;
45 int lastStartIndex = 0;
46 do {
47 if (token.getType() == InternalProblemLexer.RULE_SL_COMMENT) {
48 if (!(token instanceof CommonToken commonToken)) {
49 throw new IllegalStateException("Unexpected token: " + token);
50 }
51 var header = parseHeader(token);
52 if (header != null) {
53 int startIndex = commonToken.getStartIndex();
54 var body = problemString.substring(lastStartIndex, startIndex);
55 acceptor.acceptChunk(lastHeader, body);
56 lastHeader = header;
57 lastStartIndex = startIndex;
58 }
59 }
60 token = tokenSource.nextToken();
61 } while (token != null && token.getType() != Token.EOF);
62 acceptor.acceptChunk(lastHeader, problemString.substring(lastStartIndex));
63 acceptor.acceptEnd();
64 }
65
66 private TokenSource getTokenSource(String problemString) {
67 var charStream = new ANTLRStringStream(problemString);
68 var lexer = lexerProvider.get();
69 lexer.setCharStream(charStream);
70 var tokenSource = new ProblemTokenSource(lexer);
71 injector.injectMembers(tokenSource);
72 return tokenSource;
73 }
74
75 private ChunkHeader parseHeader(Token token) {
76 var headerText = token.getText().strip();
77 var testCaseMatcher = TEST_CASE_PATTERN.matcher(headerText);
78 if (testCaseMatcher.matches()) {
79 boolean allowErrors = testCaseMatcher.group("allowErrors") != null;
80 return new TestCaseHeader(allowErrors, testCaseMatcher.group("name"));
81 }
82 var expectationMatcher = EXPECTATION_PATTERN.matcher(headerText);
83 if (expectationMatcher.matches()) {
84 var concreteness = expectationMatcher.group("candidate") == null ? Concreteness.PARTIAL :
85 Concreteness.CANDIDATE;
86 var exact = expectationMatcher.group("exact") != null;
87 return new ExpectationHeader(concreteness, exact, expectationMatcher.group("description"),
88 token.getLine());
89 }
90 return null;
91 }
92}
diff --git a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/TestCaseHeader.java b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/TestCaseHeader.java
new file mode 100644
index 00000000..505b4769
--- /dev/null
+++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/internal/TestCaseHeader.java
@@ -0,0 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.generator.tests.internal;
7
8public record TestCaseHeader(boolean allowErrors, String name) implements ChunkHeader {
9}
diff --git a/subprojects/gradle-plugins/build.gradle.kts b/subprojects/gradle-plugins/build.gradle.kts
new file mode 100644
index 00000000..0c87b67e
--- /dev/null
+++ b/subprojects/gradle-plugins/build.gradle.kts
@@ -0,0 +1,163 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7plugins {
8 `java-gradle-plugin`
9 `maven-publish`
10 id("com.gradle.plugin-publish")
11 id("tools.refinery.gradle.java-conventions")
12 id("tools.refinery.gradle.signing")
13}
14
15val mavenRepositoryDir = rootProject.layout.buildDirectory.map { it.dir("repo") }
16val generatedSourcesDir = project.layout.buildDirectory.dir("generated/sources/refineryVersion")
17val generatedSourceFile = generatedSourcesDir.map {
18 it.file("tools/refinery/gradle/plugins/internal/Versions.java")
19}
20
21java {
22 setSourceCompatibility(11)
23 setTargetCompatibility(11)
24}
25
26sourceSets.main {
27 java.srcDir(generatedSourcesDir)
28}
29
30gradlePlugin {
31 website = "https://refinery.tools/"
32 vcsUrl = "https://github.com/graphs4value/refinery"
33
34 plugins {
35 create("settings") {
36 id = "tools.refinery.settings"
37 displayName = "Refinery settings plugin"
38 description = "Configures common build settings for projects using Refinery"
39 @Suppress("UnstableApiUsage")
40 tags = listOf("refinery", "settings", "conventions")
41 implementationClass = "tools.refinery.gradle.plugins.RefinerySettingsPlugin"
42 }
43
44 create("javaConventions") {
45 id = "tools.refinery.java"
46 displayName = "Refinery Java conventions plugin"
47 description = "Configures common Java settings for projects using Refinery"
48 @Suppress("UnstableApiUsage")
49 tags = listOf("refinery", "java", "conventions")
50 implementationClass = "tools.refinery.gradle.plugins.RefineryJavaPlugin"
51 }
52 }
53}
54
55abstract class GenerateVersionsFileTask : DefaultTask() {
56 @get:OutputFile
57 abstract val outputFile: RegularFileProperty
58
59 @get:Input
60 abstract val refineryVersion: Property<String>
61
62 @get:Input
63 abstract val useMavenLocal: Property<Boolean>
64
65 @get:Input
66 abstract val javaLanguageVersion: Property<Int>
67
68 @TaskAction
69 fun execute() {
70 val file = outputFile.asFile.get()
71 file.parentFile.mkdirs()
72 file.writeText(
73 """
74 package tools.refinery.gradle.plugins.internal;
75
76 public final class Versions {
77 public static final String REFINERY_VERSION = "${refineryVersion.get()}";
78
79 public static final boolean USE_MAVEN_LOCAL = ${useMavenLocal.get()};
80
81 public static final int JAVA_LANGUAGE_VERSION = ${javaLanguageVersion.get()};
82
83 private Versions() {
84 throw new IllegalStateException("This is a static utility class and should not be " +
85 "instantiated directly.");
86 }
87 }
88 """.trimIndent()
89 )
90 }
91}
92
93val generateVersionsFile by tasks.registering(GenerateVersionsFileTask::class) {
94 outputs.dir(generatedSourcesDir)
95 outputFile = generatedSourceFile
96 refineryVersion = version.toString()
97 useMavenLocal = false
98 javaLanguageVersion = java.toolchain.languageVersion.map { it.asInt() }
99}
100
101gradle.taskGraph.whenReady {
102 generateVersionsFile.configure {
103 useMavenLocal = gradle.taskGraph.hasTask(":${project.name}:publishToMavenLocal")
104 }
105}
106
107tasks.compileJava {
108 dependsOn(generateVersionsFile)
109}
110
111tasks.sourcesJar {
112 dependsOn(generateVersionsFile)
113}
114
115publishing {
116 publications {
117 create<MavenPublication>("pluginMaven") {
118 pom {
119 name = "Refinery Gradle Plugins"
120 description = "Gradle convention plugins in Refinery, an efficient graph solver for generating " +
121 "well-formed models"
122 url = "https://refinery.tools/"
123 licenses {
124 license {
125 name = "Eclipse Public License - v 2.0"
126 url = "https://www.eclipse.org/legal/epl-2.0/"
127 }
128 }
129 developers {
130 developer {
131 name = "The Refinery Authors"
132 url = "https://refinery.tools/"
133 }
134 }
135 scm {
136 connection = "scm:git:https://github.com/graphs4value/refinery.git"
137 developerConnection = "scm:git:ssh://github.com:graphs4value/refinery.git"
138 url = "https://github.com/graphs4value/refinery"
139 }
140 issueManagement {
141 url = "https://github.com/graphs4value/refinery/issues"
142 }
143 }
144 }
145 }
146
147 repositories {
148 maven {
149 name = "file"
150 setUrl(mavenRepositoryDir.map { uri(it) })
151 }
152 }
153}
154
155afterEvaluate {
156 for (publication in listOf("pluginMaven", "settingsPluginMarkerMaven", "javaConventionsPluginMarkerMaven")) {
157 val capitalizedName = publication.replaceFirstChar { it.uppercase() }
158 tasks.named("publish${capitalizedName}PublicationToFileRepository") {
159 mustRunAfter(rootProject.tasks.named("cleanMavenRepository"))
160 outputs.dir(mavenRepositoryDir)
161 }
162 }
163}
diff --git a/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/RefineryJavaExtension.java b/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/RefineryJavaExtension.java
new file mode 100644
index 00000000..79f37fbd
--- /dev/null
+++ b/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/RefineryJavaExtension.java
@@ -0,0 +1,26 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.gradle.plugins;
7
8import org.gradle.api.provider.Property;
9
10public abstract class RefineryJavaExtension {
11 public abstract Property<Boolean> getAddBundleSymbolicName();
12
13 public abstract Property<Boolean> getDistTar();
14
15 public abstract Property<Boolean> getDistZip();
16
17 public abstract Property<Boolean> getEnforcePlatform();
18
19 public abstract Property<String> getRefineryVersion();
20
21 public abstract Property<TestDependencies> getTestDependencies();
22
23 public abstract Property<Boolean> getUseSlf4JLog4J();
24
25 public abstract Property<Boolean> getUseSlf4JSimple();
26}
diff --git a/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/RefineryJavaPlugin.java b/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/RefineryJavaPlugin.java
new file mode 100644
index 00000000..39176707
--- /dev/null
+++ b/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/RefineryJavaPlugin.java
@@ -0,0 +1,215 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.gradle.plugins;
7
8import org.gradle.api.Plugin;
9import org.gradle.api.Project;
10import org.gradle.api.artifacts.Configuration;
11import org.gradle.api.component.AdhocComponentWithVariants;
12import org.gradle.api.component.ConfigurationVariantDetails;
13import org.gradle.api.internal.tasks.JvmConstants;
14import org.gradle.api.plugins.ApplicationPlugin;
15import org.gradle.api.plugins.JavaPlugin;
16import org.gradle.api.plugins.JavaPluginExtension;
17import org.gradle.api.tasks.bundling.Tar;
18import org.gradle.api.tasks.bundling.Zip;
19import org.gradle.api.tasks.testing.Test;
20import org.gradle.jvm.tasks.Jar;
21import org.gradle.jvm.toolchain.JavaLanguageVersion;
22import org.jetbrains.annotations.NotNull;
23import tools.refinery.gradle.plugins.internal.RefineryPluginUtils;
24import tools.refinery.gradle.plugins.internal.Versions;
25
26import java.lang.reflect.InvocationTargetException;
27import java.lang.reflect.Method;
28import java.util.Map;
29
30public class RefineryJavaPlugin implements Plugin<Project> {
31 private static final String JUNIT_API = "org.junit.jupiter:junit-jupiter-api";
32 private static final String JUNIT_BOM = "org.junit:junit-bom";
33 private static final String JUNIT_ENGINE = "org.junit.jupiter:junit-jupiter-engine";
34 private static final String JUNIT_LAUNCHER = "org.junit.platform:junit-platform-launcher";
35 private static final String JUNIT_PARAMS = "org.junit.jupiter:junit-jupiter-params";
36 private static final String HAMCREST = "org.hamcrest:hamcrest";
37 private static final String REFINERY_BOM = "tools.refinery:refinery-bom";
38 private static final String SLF4J_LOG4J = "org.slf4j:log4j-over-slf4j";
39 private static final String SLF4J_SIMPLE = "org.slf4j:slf4j-simple";
40
41 @Override
42 public void apply(@NotNull Project target) {
43 target.getPluginManager().apply(JavaPlugin.class);
44 configureJavaLanguageVersion(target);
45 var extension = configureExtension(target);
46 configureDependencies(target, extension);
47 configureTasks(target, extension);
48 RefineryPluginUtils.withShadowPlugin(target, RefineryJavaPlugin::configureShadowPlugin);
49 target.afterEvaluate(RefineryJavaPlugin::configureAfterEvaluate);
50 }
51
52 private static void configureJavaLanguageVersion(Project target) {
53 var javaExtension = target.getExtensions().getByType(JavaPluginExtension.class);
54 javaExtension.getToolchain().getLanguageVersion().set(JavaLanguageVersion.of(Versions.JAVA_LANGUAGE_VERSION));
55 }
56
57 private static RefineryJavaExtension configureExtension(Project target) {
58 var extension = target.getExtensions().create("refineryJava", RefineryJavaExtension.class);
59 extension.getAddBundleSymbolicName().convention(target.getProviders()
60 .gradleProperty("tools.refinery.java.add-bundle-symbolic-name")
61 .map(Boolean::valueOf)
62 .orElse(true));
63 extension.getDistTar().convention(target.getProviders()
64 .gradleProperty("tools.refinery.java.dist-tar")
65 .map(Boolean::valueOf)
66 .orElse(target.provider(() -> target.getPlugins().hasPlugin(ApplicationPlugin.class) &&
67 !RefineryPluginUtils.hasShadowPlugin(target))));
68 extension.getDistZip().convention(target.getProviders()
69 .gradleProperty("tools.refinery.java.dist-zip")
70 .map(Boolean::valueOf)
71 .orElse(false));
72 extension.getEnforcePlatform().convention(target.getProviders()
73 .gradleProperty("tools.refinery.java.enforce-platform")
74 .map(Boolean::valueOf)
75 .orElse(target.provider(() -> target.getPlugins().hasPlugin(ApplicationPlugin.class))));
76 extension.getRefineryVersion().convention(target.getProviders()
77 .gradleProperty(RefineryPluginUtils.VERSION_PROPERTY)
78 .orElse(Versions.REFINERY_VERSION));
79 extension.getTestDependencies().convention(target.getProviders()
80 .gradleProperty("tools.refinery.java.test-dependencies")
81 .map(TestDependencies::valueOfIgnoreCase)
82 .orElse(TestDependencies.FULL));
83 extension.getUseSlf4JLog4J().convention(target.getProviders()
84 .gradleProperty("tools.refinery.java.use-slf4j-logj4")
85 .map(Boolean::valueOf)
86 .orElse(true));
87 extension.getUseSlf4JSimple().convention(target.getProviders()
88 .gradleProperty("tools.refinery.java.use-slf4j-simple")
89 .map(Boolean::valueOf)
90 .orElse(extension.getUseSlf4JLog4J()));
91 return extension;
92 }
93
94 private static void configureDependencies(Project target, RefineryJavaExtension extension) {
95 var dependencies = target.getDependencies();
96 dependencies.add(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME, target.provider(() -> {
97 var artifact = REFINERY_BOM + ":" + extension.getRefineryVersion().get();
98 return Boolean.TRUE.equals(extension.getEnforcePlatform().get()) ?
99 dependencies.enforcedPlatform(artifact) : dependencies.platform(artifact);
100 }));
101
102 RefineryPluginUtils.addConditionalDependency(dependencies, JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME,
103 SLF4J_LOG4J, extension.getUseSlf4JLog4J());
104 RefineryPluginUtils.addConditionalDependency(dependencies, JavaPlugin.TEST_IMPLEMENTATION_CONFIGURATION_NAME,
105 SLF4J_LOG4J, extension.getUseSlf4JLog4J());
106 RefineryPluginUtils.addConditionalDependency(dependencies, JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME,
107 SLF4J_LOG4J, extension.getUseSlf4JLog4J().map(value ->
108 Boolean.TRUE.equals(value) && target.getPlugins().hasPlugin(ApplicationPlugin.class)));
109
110 RefineryPluginUtils.addConditionalDependency(dependencies, JavaPlugin.TEST_RUNTIME_ONLY_CONFIGURATION_NAME,
111 SLF4J_SIMPLE, extension.getUseSlf4JSimple());
112 RefineryPluginUtils.addConditionalDependency(dependencies, JavaPlugin.RUNTIME_ONLY_CONFIGURATION_NAME,
113 SLF4J_SIMPLE, extension.getUseSlf4JSimple().map(value ->
114 Boolean.TRUE.equals(value) && target.getPlugins().hasPlugin(ApplicationPlugin.class)));
115
116 var addJUnit5 = extension.getTestDependencies().map(TestDependencies::isAddJUnit5);
117 RefineryPluginUtils.addConditionalDependency(dependencies, JavaPlugin.TEST_IMPLEMENTATION_CONFIGURATION_NAME,
118 JUNIT_API, addJUnit5);
119 RefineryPluginUtils.addConditionalDependency(dependencies, JavaPlugin.TEST_IMPLEMENTATION_CONFIGURATION_NAME,
120 dependencies.enforcedPlatform(JUNIT_BOM), addJUnit5);
121 RefineryPluginUtils.addConditionalDependency(dependencies, JavaPlugin.TEST_RUNTIME_ONLY_CONFIGURATION_NAME,
122 JUNIT_ENGINE, addJUnit5);
123 RefineryPluginUtils.addConditionalDependency(dependencies, JavaPlugin.TEST_RUNTIME_ONLY_CONFIGURATION_NAME,
124 JUNIT_LAUNCHER, addJUnit5);
125
126 var addOtherTestDependencies = extension.getTestDependencies().map(TestDependencies::isAddOtherDependencies);
127 RefineryPluginUtils.addConditionalDependency(dependencies, JavaPlugin.TEST_IMPLEMENTATION_CONFIGURATION_NAME,
128 HAMCREST, addOtherTestDependencies);
129 RefineryPluginUtils.addConditionalDependency(dependencies, JavaPlugin.TEST_IMPLEMENTATION_CONFIGURATION_NAME,
130 JUNIT_PARAMS, addOtherTestDependencies);
131 }
132
133 private static void configureTasks(Project target, RefineryJavaExtension extension) {
134 var tasks = target.getTasks();
135 tasks.withType(Tar.class, task -> {
136 var name = task.getName();
137 if (ApplicationPlugin.TASK_DIST_TAR_NAME.equals(name)) {
138 task.setOnlyIf("Configured by refineryJava.distTar", ignored -> extension.getDistTar().get());
139 } else if ("shadowDistTar".equals(name)) {
140 task.setEnabled(false);
141 }
142 });
143 tasks.withType(Zip.class, task -> {
144 var name = task.getName();
145 if (ApplicationPlugin.TASK_DIST_ZIP_NAME.equals(name)) {
146 task.setOnlyIf("Configured by refineryJava.distZip", ignored -> extension.getDistZip().get());
147 } else if ("shadowDistZip".equals(name)) {
148 task.setEnabled(false);
149 }
150 });
151 }
152
153 private static void configureShadowPlugin(Project target) {
154 target.getTasks().named("shadowJar", Jar.class, task -> {
155 var shadowJarClass = task.getClass();
156 Method appendMethod;
157 try {
158 appendMethod = shadowJarClass.getMethod("append", String.class);
159 } catch (NoSuchMethodException e) {
160 throw new IllegalStateException("Failed to access ShadowJar task method", e);
161 }
162 try {
163 // Silence Xtext warning.
164 appendMethod.invoke(task, "plugin.properties");
165 } catch (IllegalAccessException | InvocationTargetException e) {
166 throw new IllegalStateException("Failed to add plugin.properties to the ShadowJar task", e);
167 }
168 });
169
170 // See https://github.com/johnrengelman/shadow/issues/586
171 // https://github.com/johnrengelman/shadow/issues/651
172 target.getComponents()
173 .named(JvmConstants.JAVA_MAIN_COMPONENT_NAME, AdhocComponentWithVariants.class, component -> {
174 var configuration = target.getConfigurations().getByName("shadowRuntimeElements");
175 component.withVariantsFromConfiguration(configuration, ConfigurationVariantDetails::skip);
176 });
177 }
178
179 private static void configureAfterEvaluate(Project project) {
180 var extension = project.getExtensions().getByType(RefineryJavaExtension.class);
181 if (Boolean.TRUE.equals(extension.getAddBundleSymbolicName().get())) {
182 addBundleSymbolicName(project);
183 }
184 if (Boolean.TRUE.equals(extension.getUseSlf4JLog4J().get())) {
185 excludeLog4J(project);
186 }
187 if (extension.getTestDependencies().get().isAddJUnit5()) {
188 configureJunitPlatform(project);
189 }
190 }
191
192 private static void addBundleSymbolicName(Project project) {
193 var group = project.getGroup().toString();
194 var name = project.getName();
195 var symbolicName = "".equals(group) ? name : group + "." + name;
196 project.getTasks().named(JavaPlugin.JAR_TASK_NAME, Jar.class, task -> {
197 var attributes = task.getManifest().getAttributes();
198 attributes.put("Bundle-SymbolicName", symbolicName);
199 attributes.put("Bundle-Version", project.getVersion());
200 });
201 }
202
203 private static void excludeLog4J(Project project) {
204 project.getConfigurations().withType(Configuration.class, configuration -> {
205 if (configuration.getName().endsWith("Classpath")) {
206 configuration.exclude(Map.of("group", "log4j", "module", "log4j"));
207 configuration.exclude(Map.of("group", "ch.qos.reload4j", "module", "reload4j"));
208 }
209 });
210 }
211
212 private static void configureJunitPlatform(Project project) {
213 project.getTasks().named(JavaPlugin.TEST_TASK_NAME, Test.class, Test::useJUnitPlatform);
214 }
215}
diff --git a/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/RefinerySettingsPlugin.java b/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/RefinerySettingsPlugin.java
new file mode 100644
index 00000000..54db10e5
--- /dev/null
+++ b/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/RefinerySettingsPlugin.java
@@ -0,0 +1,79 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.gradle.plugins;
7
8import org.gradle.api.Plugin;
9import org.gradle.api.initialization.Settings;
10import org.gradle.api.plugins.JavaPlugin;
11import org.jetbrains.annotations.NotNull;
12import tools.refinery.gradle.plugins.internal.RefineryPluginUtils;
13import tools.refinery.gradle.plugins.internal.Versions;
14
15import java.net.URI;
16import java.net.URISyntaxException;
17
18public class RefinerySettingsPlugin implements Plugin<Settings> {
19 public static final String MAVEN_SNAPSHOTS = "https://refinery.tools/maven/snapshots/";
20
21 @Override
22 public void apply(@NotNull Settings target) {
23 configureRepositories(target);
24 createVersionCatalog(target);
25 configureAllProjects(target);
26 }
27
28 private static void configureRepositories(Settings target) {
29 var dependencyResolutionManagement = target.getDependencyResolutionManagement();
30 // We depend on unstable API to configure dependency management for the version catalog.
31 @SuppressWarnings("UnstableApiUsage")
32 var repositories = dependencyResolutionManagement.getRepositories();
33 var repository = target.getProviders()
34 .gradleProperty("tools.refinery.repository")
35 .map(Repository::valueOfIgnoreCase)
36 .getOrElse(Repository.getDefault());
37 switch (repository) {
38 case LOCAL:
39 repositories.mavenLocal();
40 break;
41 case SNAPSHOT:
42 repositories.maven(mavenArtifactRepository -> {
43 try {
44 mavenArtifactRepository.setUrl(new URI(MAVEN_SNAPSHOTS));
45 } catch (URISyntaxException e) {
46 throw new IllegalStateException(e);
47 }
48 mavenArtifactRepository.setName("refinery-snapshots");
49 });
50 break;
51 case CENTRAL: {
52 // Since the central repository is common for all configurations, we handle it below.
53 }
54 break;
55 default:
56 throw new IllegalArgumentException("Unknown repository: " + repository);
57 }
58 repositories.mavenCentral();
59 }
60
61 private static void createVersionCatalog(Settings target) {
62 var version = target.getProviders()
63 .gradleProperty(RefineryPluginUtils.VERSION_PROPERTY)
64 .getOrElse(Versions.REFINERY_VERSION);
65 var dependencyResolutionManagement = target.getDependencyResolutionManagement();
66 var versionCatalogs = dependencyResolutionManagement.getVersionCatalogs();
67 var versionCatalog = versionCatalogs.create("refinery");
68 versionCatalog.from("tools.refinery:refinery-versions:" + version);
69 }
70
71 private static void configureAllProjects(Settings target) {
72 target.getGradle().allprojects(project -> project.getPlugins().withType(JavaPlugin.class, ignored -> {
73 var autoApply = project.findProperty("tools.refinery.auto-apply");
74 if (autoApply == null || !Boolean.FALSE.equals(Boolean.valueOf(autoApply.toString()))) {
75 project.getPlugins().apply("tools.refinery.java");
76 }
77 }));
78 }
79}
diff --git a/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/Repository.java b/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/Repository.java
new file mode 100644
index 00000000..4d934487
--- /dev/null
+++ b/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/Repository.java
@@ -0,0 +1,32 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.gradle.plugins;
7
8import tools.refinery.gradle.plugins.internal.Versions;
9
10import java.util.Locale;
11
12public enum Repository {
13 LOCAL,
14 SNAPSHOT,
15 CENTRAL;
16
17 public static Repository valueOfIgnoreCase(String value) {
18 return valueOf(value.toUpperCase(Locale.ROOT));
19 }
20
21 // The default value depends on source files generated at build time.
22 @SuppressWarnings("ConstantValue")
23 public static Repository getDefault() {
24 if (Versions.USE_MAVEN_LOCAL) {
25 return LOCAL;
26 }
27 if (Versions.REFINERY_VERSION.endsWith("-SNAPSHOT")) {
28 return SNAPSHOT;
29 }
30 return CENTRAL;
31 }
32}
diff --git a/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/TestDependencies.java b/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/TestDependencies.java
new file mode 100644
index 00000000..aa8afccc
--- /dev/null
+++ b/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/TestDependencies.java
@@ -0,0 +1,35 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.gradle.plugins;
7
8import java.util.Locale;
9
10public enum TestDependencies {
11 NONE(false, false),
12 MINIMAL(true, false),
13 FULL(true, true);
14
15 private final boolean addJUnit5;
16
17 private final boolean addOtherDependencies;
18
19 TestDependencies(boolean addJUnit5, boolean addOtherDependencies) {
20 this.addJUnit5 = addJUnit5;
21 this.addOtherDependencies = addOtherDependencies;
22 }
23
24 public boolean isAddJUnit5() {
25 return addJUnit5;
26 }
27
28 public boolean isAddOtherDependencies() {
29 return addOtherDependencies;
30 }
31
32 public static TestDependencies valueOfIgnoreCase(String value) {
33 return valueOf(value.toUpperCase(Locale.ROOT));
34 }
35}
diff --git a/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/internal/RefineryPluginUtils.java b/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/internal/RefineryPluginUtils.java
new file mode 100644
index 00000000..0004f249
--- /dev/null
+++ b/subprojects/gradle-plugins/src/main/java/tools/refinery/gradle/plugins/internal/RefineryPluginUtils.java
@@ -0,0 +1,53 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.gradle.plugins.internal;
7
8import org.gradle.api.Action;
9import org.gradle.api.Plugin;
10import org.gradle.api.Project;
11import org.gradle.api.artifacts.dsl.DependencyHandler;
12import org.gradle.api.provider.Provider;
13
14import java.util.List;
15
16public final class RefineryPluginUtils {
17 public static final String VERSION_PROPERTY = "tools.refinery.version";
18
19 private static final List<String> SHADOW_PLUGIN_IDS = List.of(
20 "com.github.johnrengelman.shadow",
21 "io.github.goooler.shadow"
22 );
23
24 private RefineryPluginUtils() {
25 throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly.");
26 }
27
28 public static void withShadowPlugin(Project project, Action<? super Project> action) {
29 // Method parameter in Gradle API uses raw type.
30 @SuppressWarnings("rawtypes")
31 Action<? super Plugin> pluginAction = ignored -> action.execute(project);
32 var plugins = project.getPlugins();
33 for (var pluginId : SHADOW_PLUGIN_IDS) {
34 plugins.withId(pluginId, pluginAction);
35 }
36 }
37
38 public static boolean hasShadowPlugin(Project project) {
39 var plugins = project.getPlugins();
40 for (var pluginId : SHADOW_PLUGIN_IDS) {
41 if (plugins.hasPlugin(pluginId)) {
42 return true;
43 }
44 }
45 return false;
46 }
47
48 public static void addConditionalDependency(DependencyHandler dependencies, String configuration,
49 Object dependency, Provider<Boolean> condition) {
50 var provider = condition.map(value -> Boolean.TRUE.equals(value) ? dependency : null);
51 dependencies.add(configuration, provider);
52 }
53}
diff --git a/subprojects/interpreter/build.gradle.kts b/subprojects/interpreter/build.gradle.kts
index 70faa812..f48c48f9 100644
--- a/subprojects/interpreter/build.gradle.kts
+++ b/subprojects/interpreter/build.gradle.kts
@@ -16,5 +16,5 @@ dependencies {
16 implementation(libs.slf4j.log4j) 16 implementation(libs.slf4j.log4j)
17 // Code in this subproject inherits from Eclipse Collection implementation classes, so this can't be `runtimeOnly`. 17 // Code in this subproject inherits from Eclipse Collection implementation classes, so this can't be `runtimeOnly`.
18 implementation(libs.eclipseCollections) 18 implementation(libs.eclipseCollections)
19 implementation(libs.eclipseCollections.api) 19 implementation(libs.eclipseCollections.impl)
20} 20}
diff --git a/subprojects/language-model/problem.aird b/subprojects/language-model/problem.aird
index 7c1f7368..f2495bcf 100644
--- a/subprojects/language-model/problem.aird
+++ b/subprojects/language-model/problem.aird
@@ -7,7 +7,7 @@
7 <semanticResources>build/resources/main/model/problem.genmodel</semanticResources> 7 <semanticResources>build/resources/main/model/problem.genmodel</semanticResources>
8 <ownedViews xmi:type="viewpoint:DView" uid="_CsAAYKA4EeuqkpDnuik1sg"> 8 <ownedViews xmi:type="viewpoint:DView" uid="_CsAAYKA4EeuqkpDnuik1sg">
9 <viewpoint xmi:type="description:Viewpoint" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']"/> 9 <viewpoint xmi:type="description:Viewpoint" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']"/>
10 <ownedRepresentationDescriptors xmi:type="viewpoint:DRepresentationDescriptor" uid="_CsYa4KA4EeuqkpDnuik1sg" name="declarations" repPath="#_CsUwgKA4EeuqkpDnuik1sg" changeId="1719861573100"> 10 <ownedRepresentationDescriptors xmi:type="viewpoint:DRepresentationDescriptor" uid="_CsYa4KA4EeuqkpDnuik1sg" name="declarations" repPath="#_CsUwgKA4EeuqkpDnuik1sg" changeId="1722526715953">
11 <description xmi:type="description_1:DiagramDescription" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']"/> 11 <description xmi:type="description_1:DiagramDescription" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']"/>
12 <target xmi:type="ecore:EPackage" href="src/main/resources/model/problem.ecore#/"/> 12 <target xmi:type="ecore:EPackage" href="src/main/resources/model/problem.ecore#/"/>
13 </ownedRepresentationDescriptors> 13 </ownedRepresentationDescriptors>
@@ -91,10 +91,6 @@
91 <styles xmi:type="notation:FontStyle" xmi:id="_bmoagTrQEe62Q_vL_UTCsA" fontColor="2697711" fontName="Noto Sans" fontHeight="8"/> 91 <styles xmi:type="notation:FontStyle" xmi:id="_bmoagTrQEe62Q_vL_UTCsA" fontColor="2697711" fontName="Noto Sans" fontHeight="8"/>
92 <layoutConstraint xmi:type="notation:Location" xmi:id="_bmoagjrQEe62Q_vL_UTCsA"/> 92 <layoutConstraint xmi:type="notation:Location" xmi:id="_bmoagjrQEe62Q_vL_UTCsA"/>
93 </children> 93 </children>
94 <children xmi:type="notation:Node" xmi:id="_7PR4kDfOEe-Iy-tQWPZJFQ" type="3010" element="_7N28QDfOEe-Iy-tQWPZJFQ">
95 <styles xmi:type="notation:FontStyle" xmi:id="_7PR4kTfOEe-Iy-tQWPZJFQ" fontColor="2697711" fontName="Noto Sans" fontHeight="8"/>
96 <layoutConstraint xmi:type="notation:Location" xmi:id="_7PR4kjfOEe-Iy-tQWPZJFQ"/>
97 </children>
98 <styles xmi:type="notation:SortingStyle" xmi:id="_fit3laA5EeuqkpDnuik1sg"/> 94 <styles xmi:type="notation:SortingStyle" xmi:id="_fit3laA5EeuqkpDnuik1sg"/>
99 <styles xmi:type="notation:FilteringStyle" xmi:id="_fit3lqA5EeuqkpDnuik1sg"/> 95 <styles xmi:type="notation:FilteringStyle" xmi:id="_fit3lqA5EeuqkpDnuik1sg"/>
100 </children> 96 </children>
@@ -494,6 +490,31 @@
494 <styles xmi:type="notation:ShapeStyle" xmi:id="_Z2K9bRO0Ee-4k7CzzL6IsA" fontName="Noto Sans" fontHeight="8"/> 490 <styles xmi:type="notation:ShapeStyle" xmi:id="_Z2K9bRO0Ee-4k7CzzL6IsA" fontName="Noto Sans" fontHeight="8"/>
495 <layoutConstraint xmi:type="notation:Bounds" xmi:id="_Z2K9bhO0Ee-4k7CzzL6IsA" x="2039" y="332" width="120" height="100"/> 491 <layoutConstraint xmi:type="notation:Bounds" xmi:id="_Z2K9bhO0Ee-4k7CzzL6IsA" x="2039" y="332" width="120" height="100"/>
496 </children> 492 </children>
493 <children xmi:type="notation:Node" xmi:id="_94vUUFAbEe-B_MJ4aHA_-Q" type="2003" element="_93bswFAbEe-B_MJ4aHA_-Q">
494 <children xmi:type="notation:Node" xmi:id="_94y-sFAbEe-B_MJ4aHA_-Q" type="5007"/>
495 <children xmi:type="notation:Node" xmi:id="_94zlwFAbEe-B_MJ4aHA_-Q" type="7004">
496 <children xmi:type="notation:Node" xmi:id="_ANvc0FAcEe-B_MJ4aHA_-Q" type="3010" element="_AM69cFAcEe-B_MJ4aHA_-Q">
497 <styles xmi:type="notation:FontStyle" xmi:id="_ANvc0VAcEe-B_MJ4aHA_-Q" fontName="Noto Sans" fontHeight="8"/>
498 <layoutConstraint xmi:type="notation:Location" xmi:id="_ANvc0lAcEe-B_MJ4aHA_-Q"/>
499 </children>
500 <children xmi:type="notation:Node" xmi:id="_BJNmkFAcEe-B_MJ4aHA_-Q" type="3010" element="_BIQkUFAcEe-B_MJ4aHA_-Q">
501 <styles xmi:type="notation:FontStyle" xmi:id="_BJNmkVAcEe-B_MJ4aHA_-Q" fontName="Noto Sans" fontHeight="8"/>
502 <layoutConstraint xmi:type="notation:Location" xmi:id="_BJNmklAcEe-B_MJ4aHA_-Q"/>
503 </children>
504 <children xmi:type="notation:Node" xmi:id="_D2-NUFAcEe-B_MJ4aHA_-Q" type="3010" element="_D2cB0FAcEe-B_MJ4aHA_-Q">
505 <styles xmi:type="notation:FontStyle" xmi:id="_D2-NUVAcEe-B_MJ4aHA_-Q" fontName="Noto Sans" fontHeight="8"/>
506 <layoutConstraint xmi:type="notation:Location" xmi:id="_D2-NUlAcEe-B_MJ4aHA_-Q"/>
507 </children>
508 <children xmi:type="notation:Node" xmi:id="_Eoo60FAcEe-B_MJ4aHA_-Q" type="3010" element="_EoDsAFAcEe-B_MJ4aHA_-Q">
509 <styles xmi:type="notation:FontStyle" xmi:id="_Eoo60VAcEe-B_MJ4aHA_-Q" fontName="Noto Sans" fontHeight="8"/>
510 <layoutConstraint xmi:type="notation:Location" xmi:id="_Eoo60lAcEe-B_MJ4aHA_-Q"/>
511 </children>
512 <styles xmi:type="notation:SortingStyle" xmi:id="_94zlwVAbEe-B_MJ4aHA_-Q"/>
513 <styles xmi:type="notation:FilteringStyle" xmi:id="_94zlwlAbEe-B_MJ4aHA_-Q"/>
514 </children>
515 <styles xmi:type="notation:ShapeStyle" xmi:id="_94vUUVAbEe-B_MJ4aHA_-Q" fontName="Noto Sans" fontHeight="8"/>
516 <layoutConstraint xmi:type="notation:Bounds" xmi:id="_94vUUlAbEe-B_MJ4aHA_-Q" x="1695" y="1288" width="120" height="100"/>
517 </children>
497 <styles xmi:type="notation:DiagramStyle" xmi:id="_CsZB8qA4EeuqkpDnuik1sg"/> 518 <styles xmi:type="notation:DiagramStyle" xmi:id="_CsZB8qA4EeuqkpDnuik1sg"/>
498 <edges xmi:type="notation:Edge" xmi:id="_4eaYwKA8EeuqkpDnuik1sg" type="4001" element="_4eU5TqA8EeuqkpDnuik1sg" source="_D1D6MKA4EeuqkpDnuik1sg" target="_xsq_MKA8EeuqkpDnuik1sg"> 519 <edges xmi:type="notation:Edge" xmi:id="_4eaYwKA8EeuqkpDnuik1sg" type="4001" element="_4eU5TqA8EeuqkpDnuik1sg" source="_D1D6MKA4EeuqkpDnuik1sg" target="_xsq_MKA8EeuqkpDnuik1sg">
499 <children xmi:type="notation:Node" xmi:id="_4ea_06A8EeuqkpDnuik1sg" type="6001"> 520 <children xmi:type="notation:Node" xmi:id="_4ea_06A8EeuqkpDnuik1sg" type="6001">
@@ -1591,22 +1612,14 @@
1591 <description xmi:type="style:FlatContainerStyleDescription" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EClass']/@style"/> 1612 <description xmi:type="style:FlatContainerStyleDescription" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EClass']/@style"/>
1592 </ownedStyle> 1613 </ownedStyle>
1593 <actualMapping xmi:type="description_1:ContainerMapping" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EClass']"/> 1614 <actualMapping xmi:type="description_1:ContainerMapping" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EClass']"/>
1594 <ownedElements xmi:type="diagram:DNodeListElement" uid="_blvCoDrQEe62Q_vL_UTCsA" name="error : EBoolean = false" tooltipText=""> 1615 <ownedElements xmi:type="diagram:DNodeListElement" uid="_blvCoDrQEe62Q_vL_UTCsA" name="kind : PredicateKind = DEFAULT" tooltipText="">
1595 <target xmi:type="ecore:EAttribute" href="src/main/resources/model/problem.ecore#//PredicateDefinition/error"/> 1616 <target xmi:type="ecore:EAttribute" href="src/main/resources/model/problem.ecore#//PredicateDefinition/kind"/>
1596 <semanticElements xmi:type="ecore:EAttribute" href="src/main/resources/model/problem.ecore#//PredicateDefinition/error"/> 1617 <semanticElements xmi:type="ecore:EAttribute" href="src/main/resources/model/problem.ecore#//PredicateDefinition/kind"/>
1597 <ownedStyle xmi:type="diagram:BundledImage" uid="_dFx5EzrQEe62Q_vL_UTCsA" labelAlignment="LEFT"> 1618 <ownedStyle xmi:type="diagram:BundledImage" uid="_dFx5EzrQEe62Q_vL_UTCsA" labelAlignment="LEFT">
1598 <description xmi:type="style:BundledImageDescription" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EClass']/@subNodeMappings[name='EC%20EAttribute']/@style"/> 1619 <description xmi:type="style:BundledImageDescription" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EClass']/@subNodeMappings[name='EC%20EAttribute']/@style"/>
1599 </ownedStyle> 1620 </ownedStyle>
1600 <actualMapping xmi:type="description_1:NodeMapping" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EClass']/@subNodeMappings[name='EC%20EAttribute']"/> 1621 <actualMapping xmi:type="description_1:NodeMapping" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EClass']/@subNodeMappings[name='EC%20EAttribute']"/>
1601 </ownedElements> 1622 </ownedElements>
1602 <ownedElements xmi:type="diagram:DNodeListElement" uid="_7N28QDfOEe-Iy-tQWPZJFQ" name="shadow : EBoolean = false" tooltipText="">
1603 <target xmi:type="ecore:EAttribute" href="src/main/resources/model/problem.ecore#//PredicateDefinition/shadow"/>
1604 <semanticElements xmi:type="ecore:EAttribute" href="src/main/resources/model/problem.ecore#//PredicateDefinition/shadow"/>
1605 <ownedStyle xmi:type="diagram:BundledImage" uid="_t8lBgTfQEe-Iy-tQWPZJFQ" labelAlignment="LEFT">
1606 <description xmi:type="style:BundledImageDescription" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EClass']/@subNodeMappings[name='EC%20EAttribute']/@style"/>
1607 </ownedStyle>
1608 <actualMapping xmi:type="description_1:NodeMapping" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EClass']/@subNodeMappings[name='EC%20EAttribute']"/>
1609 </ownedElements>
1610 </ownedDiagramElements> 1623 </ownedDiagramElements>
1611 <ownedDiagramElements xmi:type="diagram:DNodeList" uid="_QKD2EKA6EeuqkpDnuik1sg" name="Parameter" tooltipText="" outgoingEdges="_oni4rKA6EeuqkpDnuik1sg _iWzpAmTzEe2qdtyPWAtoxA" incomingEdges="_Uy4bWaA6EeuqkpDnuik1sg" width="12" height="10"> 1624 <ownedDiagramElements xmi:type="diagram:DNodeList" uid="_QKD2EKA6EeuqkpDnuik1sg" name="Parameter" tooltipText="" outgoingEdges="_oni4rKA6EeuqkpDnuik1sg _iWzpAmTzEe2qdtyPWAtoxA" incomingEdges="_Uy4bWaA6EeuqkpDnuik1sg" width="12" height="10">
1612 <target xmi:type="ecore:EClass" href="src/main/resources/model/problem.ecore#//Parameter"/> 1625 <target xmi:type="ecore:EClass" href="src/main/resources/model/problem.ecore#//Parameter"/>
@@ -2865,6 +2878,49 @@
2865 </ownedStyle> 2878 </ownedStyle>
2866 <actualMapping xmi:type="description_1:EdgeMapping" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@edgeMappings[name='EC_EReference']"/> 2879 <actualMapping xmi:type="description_1:EdgeMapping" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@edgeMappings[name='EC_EReference']"/>
2867 </ownedDiagramElements> 2880 </ownedDiagramElements>
2881 <ownedDiagramElements xmi:type="diagram:DNodeList" uid="_93bswFAbEe-B_MJ4aHA_-Q" name="PredicateKind" tooltipText="" width="12" height="10">
2882 <target xmi:type="ecore:EEnum" href="src/main/resources/model/problem.ecore#//PredicateKind"/>
2883 <semanticElements xmi:type="ecore:EEnum" href="src/main/resources/model/problem.ecore#//PredicateKind"/>
2884 <arrangeConstraints>KEEP_LOCATION</arrangeConstraints>
2885 <arrangeConstraints>KEEP_SIZE</arrangeConstraints>
2886 <arrangeConstraints>KEEP_RATIO</arrangeConstraints>
2887 <ownedStyle xmi:type="diagram:FlatContainerStyle" uid="_93cT0FAbEe-B_MJ4aHA_-Q" borderSize="1" borderSizeComputationExpression="1" borderColor="125,125,125" backgroundStyle="Liquid" foregroundColor="221,236,202">
2888 <description xmi:type="style:FlatContainerStyleDescription" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EEnum']/@style"/>
2889 </ownedStyle>
2890 <actualMapping xmi:type="description_1:ContainerMapping" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EEnum']"/>
2891 <ownedElements xmi:type="diagram:DNodeListElement" uid="_AM69cFAcEe-B_MJ4aHA_-Q" name="DEFAULT" tooltipText="">
2892 <target xmi:type="ecore:EEnumLiteral" href="src/main/resources/model/problem.ecore#//PredicateKind/DEFAULT"/>
2893 <semanticElements xmi:type="ecore:EEnumLiteral" href="src/main/resources/model/problem.ecore#//PredicateKind/DEFAULT"/>
2894 <ownedStyle xmi:type="diagram:BundledImage" uid="_AM69cVAcEe-B_MJ4aHA_-Q" labelAlignment="LEFT">
2895 <description xmi:type="style:BundledImageDescription" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EEnum']/@subNodeMappings[name='EC%20EEnumLiteral']/@style"/>
2896 </ownedStyle>
2897 <actualMapping xmi:type="description_1:NodeMapping" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EEnum']/@subNodeMappings[name='EC%20EEnumLiteral']"/>
2898 </ownedElements>
2899 <ownedElements xmi:type="diagram:DNodeListElement" uid="_BIQkUFAcEe-B_MJ4aHA_-Q" name="ERROR" tooltipText="">
2900 <target xmi:type="ecore:EEnumLiteral" href="src/main/resources/model/problem.ecore#//PredicateKind/ERROR"/>
2901 <semanticElements xmi:type="ecore:EEnumLiteral" href="src/main/resources/model/problem.ecore#//PredicateKind/ERROR"/>
2902 <ownedStyle xmi:type="diagram:BundledImage" uid="_BIRLYFAcEe-B_MJ4aHA_-Q" labelAlignment="LEFT">
2903 <description xmi:type="style:BundledImageDescription" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EEnum']/@subNodeMappings[name='EC%20EEnumLiteral']/@style"/>
2904 </ownedStyle>
2905 <actualMapping xmi:type="description_1:NodeMapping" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EEnum']/@subNodeMappings[name='EC%20EEnumLiteral']"/>
2906 </ownedElements>
2907 <ownedElements xmi:type="diagram:DNodeListElement" uid="_D2cB0FAcEe-B_MJ4aHA_-Q" name="SHADOW" tooltipText="">
2908 <target xmi:type="ecore:EEnumLiteral" href="src/main/resources/model/problem.ecore#//PredicateKind/SHADOW"/>
2909 <semanticElements xmi:type="ecore:EEnumLiteral" href="src/main/resources/model/problem.ecore#//PredicateKind/SHADOW"/>
2910 <ownedStyle xmi:type="diagram:BundledImage" uid="_D2co4FAcEe-B_MJ4aHA_-Q" labelAlignment="LEFT">
2911 <description xmi:type="style:BundledImageDescription" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EEnum']/@subNodeMappings[name='EC%20EEnumLiteral']/@style"/>
2912 </ownedStyle>
2913 <actualMapping xmi:type="description_1:NodeMapping" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EEnum']/@subNodeMappings[name='EC%20EEnumLiteral']"/>
2914 </ownedElements>
2915 <ownedElements xmi:type="diagram:DNodeListElement" uid="_EoDsAFAcEe-B_MJ4aHA_-Q" name="PARTIAL" tooltipText="">
2916 <target xmi:type="ecore:EEnumLiteral" href="src/main/resources/model/problem.ecore#//PredicateKind/PARTIAL"/>
2917 <semanticElements xmi:type="ecore:EEnumLiteral" href="src/main/resources/model/problem.ecore#//PredicateKind/PARTIAL"/>
2918 <ownedStyle xmi:type="diagram:BundledImage" uid="_EoDsAVAcEe-B_MJ4aHA_-Q" labelAlignment="LEFT">
2919 <description xmi:type="style:BundledImageDescription" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EEnum']/@subNodeMappings[name='EC%20EEnumLiteral']/@style"/>
2920 </ownedStyle>
2921 <actualMapping xmi:type="description_1:NodeMapping" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer/@containerMappings[name='EC%20EEnum']/@subNodeMappings[name='EC%20EEnumLiteral']"/>
2922 </ownedElements>
2923 </ownedDiagramElements>
2868 <description xmi:type="description_1:DiagramDescription" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']"/> 2924 <description xmi:type="description_1:DiagramDescription" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']"/>
2869 <filterVariableHistory xmi:type="diagram:FilterVariableHistory" uid="_CsWlsKA4EeuqkpDnuik1sg"/> 2925 <filterVariableHistory xmi:type="diagram:FilterVariableHistory" uid="_CsWlsKA4EeuqkpDnuik1sg"/>
2870 <activatedLayers xmi:type="description_1:Layer" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer"/> 2926 <activatedLayers xmi:type="description_1:Layer" href="platform:/plugin/org.eclipse.emf.ecoretools.design/description/ecore.odesign#//@ownedViewpoints[name='Design']/@ownedRepresentations[name='Entities']/@defaultLayer"/>
diff --git a/subprojects/language-model/src/main/resources/model/problem.ecore b/subprojects/language-model/src/main/resources/model/problem.ecore
index a9b6f660..0bc8caf9 100644
--- a/subprojects/language-model/src/main/resources/model/problem.ecore
+++ b/subprojects/language-model/src/main/resources/model/problem.ecore
@@ -34,8 +34,7 @@
34 <eClassifiers xsi:type="ecore:EClass" name="PredicateDefinition" eSuperTypes="#//ParametricDefinition #//Relation"> 34 <eClassifiers xsi:type="ecore:EClass" name="PredicateDefinition" eSuperTypes="#//ParametricDefinition #//Relation">
35 <eStructuralFeatures xsi:type="ecore:EReference" name="bodies" upperBound="-1" 35 <eStructuralFeatures xsi:type="ecore:EReference" name="bodies" upperBound="-1"
36 eType="#//Conjunction" containment="true"/> 36 eType="#//Conjunction" containment="true"/>
37 <eStructuralFeatures xsi:type="ecore:EAttribute" name="error" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"/> 37 <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//PredicateKind"/>
38 <eStructuralFeatures xsi:type="ecore:EAttribute" name="shadow" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"/>
39 <eStructuralFeatures xsi:type="ecore:EReference" name="computedValue" eType="#//PredicateDefinition" 38 <eStructuralFeatures xsi:type="ecore:EReference" name="computedValue" eType="#//PredicateDefinition"
40 transient="true" containment="true"/> 39 transient="true" containment="true"/>
41 </eClassifiers> 40 </eClassifiers>
@@ -281,4 +280,10 @@
281 <eStructuralFeatures xsi:type="ecore:EAttribute" name="default" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean" 280 <eStructuralFeatures xsi:type="ecore:EAttribute" name="default" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"
282 defaultValueLiteral="false"/> 281 defaultValueLiteral="false"/>
283 </eClassifiers> 282 </eClassifiers>
283 <eClassifiers xsi:type="ecore:EEnum" name="PredicateKind">
284 <eLiterals name="DEFAULT"/>
285 <eLiterals name="ERROR" value="1"/>
286 <eLiterals name="SHADOW" value="2"/>
287 <eLiterals name="PARTIAL" value="3"/>
288 </eClassifiers>
284</ecore:EPackage> 289</ecore:EPackage>
diff --git a/subprojects/language-model/src/main/resources/model/problem.genmodel b/subprojects/language-model/src/main/resources/model/problem.genmodel
index f3c367e1..e7cf6843 100644
--- a/subprojects/language-model/src/main/resources/model/problem.genmodel
+++ b/subprojects/language-model/src/main/resources/model/problem.genmodel
@@ -81,6 +81,12 @@
81 <genEnumLiterals ecoreEnumLiteral="problem.ecore#//ParameterBinding/FOCUS"/> 81 <genEnumLiterals ecoreEnumLiteral="problem.ecore#//ParameterBinding/FOCUS"/>
82 <genEnumLiterals ecoreEnumLiteral="problem.ecore#//ParameterBinding/MULTI"/> 82 <genEnumLiterals ecoreEnumLiteral="problem.ecore#//ParameterBinding/MULTI"/>
83 </genEnums> 83 </genEnums>
84 <genEnums typeSafeEnumCompatible="false" ecoreEnum="problem.ecore#//PredicateKind">
85 <genEnumLiterals ecoreEnumLiteral="problem.ecore#//PredicateKind/DEFAULT"/>
86 <genEnumLiterals ecoreEnumLiteral="problem.ecore#//PredicateKind/ERROR"/>
87 <genEnumLiterals ecoreEnumLiteral="problem.ecore#//PredicateKind/SHADOW"/>
88 <genEnumLiterals ecoreEnumLiteral="problem.ecore#//PredicateKind/PARTIAL"/>
89 </genEnums>
84 <genClasses ecoreClass="problem.ecore#//Problem"> 90 <genClasses ecoreClass="problem.ecore#//Problem">
85 <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference problem.ecore#//Problem/nodes"/> 91 <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference problem.ecore#//Problem/nodes"/>
86 <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference problem.ecore#//Problem/statements"/> 92 <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference problem.ecore#//Problem/statements"/>
@@ -105,8 +111,7 @@
105 </genClasses> 111 </genClasses>
106 <genClasses ecoreClass="problem.ecore#//PredicateDefinition"> 112 <genClasses ecoreClass="problem.ecore#//PredicateDefinition">
107 <genFeatures children="true" createChild="true" propertySortChoices="true" ecoreFeature="ecore:EReference problem.ecore#//PredicateDefinition/bodies"/> 113 <genFeatures children="true" createChild="true" propertySortChoices="true" ecoreFeature="ecore:EReference problem.ecore#//PredicateDefinition/bodies"/>
108 <genFeatures createChild="false" ecoreFeature="ecore:EAttribute problem.ecore#//PredicateDefinition/error"/> 114 <genFeatures createChild="false" ecoreFeature="ecore:EAttribute problem.ecore#//PredicateDefinition/kind"/>
109 <genFeatures createChild="false" ecoreFeature="ecore:EAttribute problem.ecore#//PredicateDefinition/shadow"/>
110 <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference problem.ecore#//PredicateDefinition/computedValue"/> 115 <genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference problem.ecore#//PredicateDefinition/computedValue"/>
111 </genClasses> 116 </genClasses>
112 <genClasses ecoreClass="problem.ecore#//Parameter"> 117 <genClasses ecoreClass="problem.ecore#//Parameter">
diff --git a/subprojects/language-semantics/build.gradle.kts b/subprojects/language-semantics/build.gradle.kts
index fe223c6d..98e5b366 100644
--- a/subprojects/language-semantics/build.gradle.kts
+++ b/subprojects/language-semantics/build.gradle.kts
@@ -13,13 +13,13 @@ mavenArtifact {
13} 13}
14 14
15dependencies { 15dependencies {
16 api(libs.eclipseCollections.api)
17 api(project(":refinery-language")) 16 api(project(":refinery-language"))
18 api(project(":refinery-store")) 17 api(project(":refinery-store"))
19 api(project(":refinery-store-query")) 18 api(project(":refinery-store-query"))
20 api(project(":refinery-store-reasoning")) 19 api(project(":refinery-store-reasoning"))
20 api(libs.eclipseCollections)
21 implementation(project(":refinery-store-reasoning-scope")) 21 implementation(project(":refinery-store-reasoning-scope"))
22 runtimeOnly(libs.eclipseCollections) 22 runtimeOnly(libs.eclipseCollections.impl)
23 testImplementation(project(":refinery-store-dse-visualization")) 23 testImplementation(project(":refinery-store-dse-visualization"))
24 testImplementation(project(":refinery-store-query-interpreter")) 24 testImplementation(project(":refinery-store-query-interpreter"))
25 testImplementation(testFixtures(project(":refinery-language"))) 25 testImplementation(testFixtures(project(":refinery-language")))
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 d71cf35f..f45acc96 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
@@ -39,7 +39,9 @@ import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslat
39import tools.refinery.store.reasoning.translator.multiplicity.ConstrainedMultiplicity; 39import tools.refinery.store.reasoning.translator.multiplicity.ConstrainedMultiplicity;
40import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; 40import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity;
41import tools.refinery.store.reasoning.translator.multiplicity.UnconstrainedMultiplicity; 41import tools.refinery.store.reasoning.translator.multiplicity.UnconstrainedMultiplicity;
42import tools.refinery.store.reasoning.translator.predicate.BasePredicateTranslator;
42import tools.refinery.store.reasoning.translator.predicate.PredicateTranslator; 43import tools.refinery.store.reasoning.translator.predicate.PredicateTranslator;
44import tools.refinery.store.reasoning.translator.predicate.ShadowPredicateTranslator;
43import tools.refinery.store.statecoding.StateCoderBuilder; 45import tools.refinery.store.statecoding.StateCoderBuilder;
44import tools.refinery.store.tuple.Tuple; 46import tools.refinery.store.tuple.Tuple;
45import tools.refinery.store.tuple.Tuple1; 47import tools.refinery.store.tuple.Tuple1;
@@ -68,6 +70,10 @@ public class ModelInitializer {
68 @Inject 70 @Inject
69 private RuleCompiler ruleCompiler; 71 private RuleCompiler ruleCompiler;
70 72
73 private boolean keepNonExistingObjects;
74
75 private boolean keepShadowPredicates = true;
76
71 private Problem problem; 77 private Problem problem;
72 78
73 private final Set<Problem> importedProblems = new HashSet<>(); 79 private final Set<Problem> importedProblems = new HashSet<>();
@@ -182,7 +188,7 @@ public class ModelInitializer {
182 public void configureStoreBuilder(ModelStoreBuilder storeBuilder) { 188 public void configureStoreBuilder(ModelStoreBuilder storeBuilder) {
183 checkProblem(); 189 checkProblem();
184 try { 190 try {
185 storeBuilder.with(new MultiObjectTranslator()); 191 storeBuilder.with(new MultiObjectTranslator(keepNonExistingObjects));
186 storeBuilder.with(new MetamodelTranslator(metamodel)); 192 storeBuilder.with(new MetamodelTranslator(metamodel));
187 if (scopePropagator != null) { 193 if (scopePropagator != null) {
188 if (storeBuilder.tryGetAdapter(PropagationBuilder.class).isEmpty()) { 194 if (storeBuilder.tryGetAdapter(PropagationBuilder.class).isEmpty()) {
@@ -194,6 +200,9 @@ public class ModelInitializer {
194 collectRules(storeBuilder); 200 collectRules(storeBuilder);
195 storeBuilder.tryGetAdapter(StateCoderBuilder.class) 201 storeBuilder.tryGetAdapter(StateCoderBuilder.class)
196 .ifPresent(stateCoderBuilder -> stateCoderBuilder.individuals(individuals)); 202 .ifPresent(stateCoderBuilder -> stateCoderBuilder.individuals(individuals));
203 if (!keepShadowPredicates) {
204 problemTrace.removeShadowRelations();
205 }
197 } catch (TranslationException e) { 206 } catch (TranslationException e) {
198 throw problemTrace.wrapException(e); 207 throw problemTrace.wrapException(e);
199 } 208 }
@@ -287,7 +296,7 @@ public class ModelInitializer {
287 296
288 private void collectPredicateDefinitionSymbol(PredicateDefinition predicateDefinition) { 297 private void collectPredicateDefinitionSymbol(PredicateDefinition predicateDefinition) {
289 int arity = predicateDefinition.getParameters().size(); 298 int arity = predicateDefinition.getParameters().size();
290 if (predicateDefinition.isError()) { 299 if (predicateDefinition.getKind() == PredicateKind.ERROR) {
291 collectPartialRelation(predicateDefinition, arity, TruthValue.FALSE, TruthValue.FALSE); 300 collectPartialRelation(predicateDefinition, arity, TruthValue.FALSE, TruthValue.FALSE);
292 } else { 301 } else {
293 collectPartialRelation(predicateDefinition, arity, null, TruthValue.UNKNOWN); 302 collectPartialRelation(predicateDefinition, arity, null, TruthValue.UNKNOWN);
@@ -592,26 +601,32 @@ public class ModelInitializer {
592 } 601 }
593 602
594 private void collectPredicateDefinition(PredicateDefinition predicateDefinition, ModelStoreBuilder storeBuilder) { 603 private void collectPredicateDefinition(PredicateDefinition predicateDefinition, ModelStoreBuilder storeBuilder) {
604 if (ProblemUtil.isBasePredicate(predicateDefinition)) {
605 collectBasePredicateDefinition(predicateDefinition, storeBuilder);
606 } else if (predicateDefinition.getKind() == PredicateKind.SHADOW) {
607 collectShadowPredicateDefinition(predicateDefinition, storeBuilder);
608 } else {
609 collectComputedPredicateDefinition(predicateDefinition, storeBuilder);
610 }
611 }
612
613 private void collectComputedPredicateDefinition(PredicateDefinition predicateDefinition,
614 ModelStoreBuilder storeBuilder) {
595 var partialRelation = getPartialRelation(predicateDefinition); 615 var partialRelation = getPartialRelation(predicateDefinition);
596 var query = queryCompiler.toQuery(partialRelation.name(), predicateDefinition); 616 var query = queryCompiler.toQuery(partialRelation.name(), predicateDefinition);
597 boolean mutable; 617 boolean mutable = targetTypes.contains(partialRelation) || isActionTarget(predicateDefinition);
598 TruthValue defaultValue; 618 TruthValue defaultValue;
599 if (predicateDefinition.isShadow()) { 619 if (predicateDefinition.getKind() == PredicateKind.ERROR) {
600 mutable = false; 620 defaultValue = TruthValue.FALSE;
601 defaultValue = TruthValue.UNKNOWN;
602 } else { 621 } else {
603 mutable = targetTypes.contains(partialRelation) || isActionTarget(predicateDefinition); 622 var seed = modelSeed.getSeed(partialRelation);
604 if (predicateDefinition.isError()) { 623 defaultValue = seed.majorityValue() == TruthValue.FALSE ? TruthValue.FALSE : TruthValue.UNKNOWN;
605 defaultValue = TruthValue.FALSE; 624 var cursor = seed.getCursor(defaultValue, problemTrace.getNodeTrace().size());
606 } else { 625 // The symbol should be mutable if there is at least one non-default entry in the seed.
607 var seed = modelSeed.getSeed(partialRelation); 626 mutable = mutable || cursor.move();
608 defaultValue = seed.majorityValue() == TruthValue.FALSE ? TruthValue.FALSE : TruthValue.UNKNOWN; 627 }
609 var cursor = seed.getCursor(defaultValue, problemTrace.getNodeTrace().size()); 628 var parameterTypes = getParameterTypes(predicateDefinition, null);
610 // The symbol should be mutable if there is at least one non-default entry in the seed. 629 var translator = new PredicateTranslator(partialRelation, query, parameterTypes, mutable, defaultValue);
611 mutable = mutable || cursor.move();
612 }
613 }
614 var translator = new PredicateTranslator(partialRelation, query, mutable, defaultValue);
615 storeBuilder.with(translator); 630 storeBuilder.with(translator);
616 } 631 }
617 632
@@ -624,6 +639,36 @@ public class ModelInitializer {
624 return false; 639 return false;
625 } 640 }
626 641
642 private List<PartialRelation> getParameterTypes(ParametricDefinition parametricDefinition,
643 PartialRelation defaultType) {
644 var parameters = parametricDefinition.getParameters();
645 var parameterTypes = new ArrayList<PartialRelation>(parameters.size());
646 for (var parameter : parameters) {
647 var relation = parameter.getParameterType();
648 parameterTypes.add(relation == null ? defaultType : getPartialRelation(relation));
649 }
650 return Collections.unmodifiableList(parameterTypes);
651 }
652
653 private void collectBasePredicateDefinition(PredicateDefinition predicateDefinition,
654 ModelStoreBuilder storeBuilder) {
655 var partialRelation = getPartialRelation(predicateDefinition);
656 var parameterTypes = getParameterTypes(predicateDefinition, nodeRelation);
657 var seed = modelSeed.getSeed(partialRelation);
658 var defaultValue = seed.majorityValue() == TruthValue.FALSE ? TruthValue.FALSE : TruthValue.UNKNOWN;
659 boolean partial = predicateDefinition.getKind() == PredicateKind.PARTIAL;
660 var translator = new BasePredicateTranslator(partialRelation, parameterTypes, defaultValue, partial);
661 storeBuilder.with(translator);
662 }
663
664 private void collectShadowPredicateDefinition(PredicateDefinition predicateDefinition,
665 ModelStoreBuilder storeBuilder) {
666 var partialRelation = getPartialRelation(predicateDefinition);
667 var query = queryCompiler.toQuery(partialRelation.name(), predicateDefinition);
668 var translator = new ShadowPredicateTranslator(partialRelation, query, keepShadowPredicates);
669 storeBuilder.with(translator);
670 }
671
627 private void collectScopes() { 672 private void collectScopes() {
628 for (var importedProblem : importedProblems) { 673 for (var importedProblem : importedProblems) {
629 for (var statement : importedProblem.getStatements()) { 674 for (var statement : importedProblem.getStatements()) {
@@ -672,6 +717,18 @@ public class ModelInitializer {
672 scopePropagator.scope(type, interval); 717 scopePropagator.scope(type, interval);
673 } 718 }
674 719
720 public void setKeepNonExistingObjects(boolean keepNonExistingObjects) {
721 this.keepNonExistingObjects = keepNonExistingObjects;
722 }
723
724 public boolean isKeepShadowPredicates() {
725 return keepShadowPredicates;
726 }
727
728 public void setKeepShadowPredicates(boolean keepShadowPredicates) {
729 this.keepShadowPredicates = keepShadowPredicates;
730 }
731
675 private record RelationInfo(PartialRelation partialRelation, MutableSeed<TruthValue> assertions, 732 private record RelationInfo(PartialRelation partialRelation, MutableSeed<TruthValue> assertions,
676 MutableSeed<TruthValue> defaultAssertions) { 733 MutableSeed<TruthValue> defaultAssertions) {
677 public RelationInfo(String name, int arity, TruthValue value, TruthValue defaultValue) { 734 public RelationInfo(String name, int arity, TruthValue value, TruthValue defaultValue) {
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ProblemTraceImpl.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ProblemTraceImpl.java
index 457f2362..487ac9b9 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ProblemTraceImpl.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/ProblemTraceImpl.java
@@ -113,6 +113,19 @@ class ProblemTraceImpl implements ProblemTrace {
113 } 113 }
114 } 114 }
115 115
116 void removeShadowRelations() {
117 var iterator = mutableRelationTrace.entrySet().iterator();
118 while (iterator.hasNext()) {
119 var entry = iterator.next();
120 var relation = entry.getKey();
121 if (relation instanceof PredicateDefinition predicateDefinition &&
122 predicateDefinition.getKind() == PredicateKind.SHADOW) {
123 iterator.remove();
124 mutableInverseTrace.remove(entry.getValue());
125 }
126 }
127 }
128
116 @Override 129 @Override
117 public Map<AnyPartialSymbol, Relation> getInverseRelationTrace() { 130 public Map<AnyPartialSymbol, Relation> getInverseRelationTrace() {
118 return inverseTrace; 131 return inverseTrace;
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 ed4841c4..16a41824 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
@@ -24,6 +24,7 @@ import tools.refinery.language.naming.NamingUtil;
24import tools.refinery.language.scoping.imports.ImportAdapterProvider; 24import tools.refinery.language.scoping.imports.ImportAdapterProvider;
25import tools.refinery.language.typesystem.SignatureProvider; 25import tools.refinery.language.typesystem.SignatureProvider;
26import tools.refinery.language.utils.ProblemUtil; 26import tools.refinery.language.utils.ProblemUtil;
27import tools.refinery.logic.term.truthvalue.TruthValue;
27import tools.refinery.store.model.Model; 28import tools.refinery.store.model.Model;
28import tools.refinery.store.reasoning.ReasoningAdapter; 29import tools.refinery.store.reasoning.ReasoningAdapter;
29import tools.refinery.store.reasoning.interpretation.PartialInterpretation; 30import tools.refinery.store.reasoning.interpretation.PartialInterpretation;
@@ -31,13 +32,15 @@ import tools.refinery.store.reasoning.literal.Concreteness;
31import tools.refinery.store.reasoning.representation.PartialRelation; 32import tools.refinery.store.reasoning.representation.PartialRelation;
32import tools.refinery.store.reasoning.translator.typehierarchy.InferredType; 33import tools.refinery.store.reasoning.translator.typehierarchy.InferredType;
33import tools.refinery.store.reasoning.translator.typehierarchy.TypeHierarchyTranslator; 34import tools.refinery.store.reasoning.translator.typehierarchy.TypeHierarchyTranslator;
34import tools.refinery.logic.term.truthvalue.TruthValue;
35import tools.refinery.store.tuple.Tuple; 35import tools.refinery.store.tuple.Tuple;
36 36
37import java.io.ByteArrayInputStream; 37import java.io.ByteArrayInputStream;
38import java.io.ByteArrayOutputStream; 38import java.io.ByteArrayOutputStream;
39import java.io.IOException; 39import java.io.IOException;
40import java.util.*; 40import java.util.Map;
41import java.util.Objects;
42import java.util.TreeMap;
43import java.util.UUID;
41import java.util.function.Function; 44import java.util.function.Function;
42import java.util.stream.Collectors; 45import java.util.stream.Collectors;
43 46
@@ -107,6 +110,7 @@ public class SolutionSerializer {
107 addExistsAssertions(); 110 addExistsAssertions();
108 addClassAssertions(); 111 addClassAssertions();
109 addReferenceAssertions(); 112 addReferenceAssertions();
113 addBasePredicateAssertions();
110 if (nodeDeclaration.getNodes().isEmpty()) { 114 if (nodeDeclaration.getNodes().isEmpty()) {
111 problem.getStatements().remove(nodeDeclaration); 115 problem.getStatements().remove(nodeDeclaration);
112 } 116 }
@@ -249,8 +253,8 @@ public class SolutionSerializer {
249 } 253 }
250 254
251 private void addClassAssertions() { 255 private void addClassAssertions() {
252 var types = 256 var types = trace.getMetamodel().typeHierarchy().getPreservedTypes().keySet().stream()
253 trace.getMetamodel().typeHierarchy().getPreservedTypes().keySet().stream().collect(Collectors.toMap(Function.identity(), this::findPartialRelation)); 257 .collect(Collectors.toMap(Function.identity(), this::findPartialRelation));
254 var cursor = model.getInterpretation(TypeHierarchyTranslator.TYPE_SYMBOL).getAll(); 258 var cursor = model.getInterpretation(TypeHierarchyTranslator.TYPE_SYMBOL).getAll();
255 while (cursor.move()) { 259 while (cursor.move()) {
256 var key = cursor.getKey(); 260 var key = cursor.getKey();
@@ -306,6 +310,17 @@ public class SolutionSerializer {
306 } 310 }
307 } 311 }
308 312
313 private void addBasePredicateAssertions() {
314 for (var entry : trace.getRelationTrace().entrySet()) {
315 if (entry.getKey() instanceof PredicateDefinition predicateDefinition &&
316 ProblemUtil.isBasePredicate(predicateDefinition)) {
317 var partialRelation = entry.getValue();
318 addDefaultAssertion(partialRelation);
319 addAssertions(partialRelation);
320 }
321 }
322 }
323
309 private void addAssertions(PartialRelation partialRelation) { 324 private void addAssertions(PartialRelation partialRelation) {
310 var relation = findPartialRelation(partialRelation); 325 var relation = findPartialRelation(partialRelation);
311 var cursor = reasoningAdapter.getPartialInterpretation(Concreteness.CANDIDATE, partialRelation).getAll(); 326 var cursor = reasoningAdapter.getPartialInterpretation(Concreteness.CANDIDATE, partialRelation).getAll();
diff --git a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/ModelGenerationTest.java b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/ModelGenerationTest.java
index b4abce81..44d83cdc 100644
--- a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/ModelGenerationTest.java
+++ b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/ModelGenerationTest.java
@@ -6,14 +6,11 @@
6package tools.refinery.language.semantics; 6package tools.refinery.language.semantics;
7 7
8import com.google.inject.Inject; 8import com.google.inject.Inject;
9import org.eclipse.xtext.testing.InjectWith;
10import org.eclipse.xtext.testing.extensions.InjectionExtension;
11import org.junit.jupiter.api.Disabled; 9import org.junit.jupiter.api.Disabled;
12import org.junit.jupiter.api.Test; 10import org.junit.jupiter.api.Test;
13import org.junit.jupiter.api.extension.ExtendWith;
14import tools.refinery.language.ProblemStandaloneSetup; 11import tools.refinery.language.ProblemStandaloneSetup;
15import tools.refinery.language.model.tests.utils.ProblemParseHelper; 12import tools.refinery.language.tests.InjectWithRefinery;
16import tools.refinery.language.tests.ProblemInjectorProvider; 13import tools.refinery.language.tests.utils.ProblemParseHelper;
17import tools.refinery.store.dse.propagation.PropagationAdapter; 14import tools.refinery.store.dse.propagation.PropagationAdapter;
18import tools.refinery.store.dse.strategy.BestFirstStoreManager; 15import tools.refinery.store.dse.strategy.BestFirstStoreManager;
19import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter; 16import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter;
@@ -33,8 +30,7 @@ import java.util.LinkedHashMap;
33import static org.hamcrest.MatcherAssert.assertThat; 30import static org.hamcrest.MatcherAssert.assertThat;
34import static org.hamcrest.Matchers.empty; 31import static org.hamcrest.Matchers.empty;
35 32
36@ExtendWith(InjectionExtension.class) 33@InjectWithRefinery
37@InjectWith(ProblemInjectorProvider.class)
38@Disabled("For debugging purposes only") 34@Disabled("For debugging purposes only")
39class ModelGenerationTest { 35class ModelGenerationTest {
40 @Inject 36 @Inject
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 9f36445a..fded04bf 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
@@ -7,14 +7,11 @@ package tools.refinery.language.semantics;
7 7
8import com.google.inject.Inject; 8import com.google.inject.Inject;
9import com.google.inject.Provider; 9import com.google.inject.Provider;
10import org.eclipse.xtext.testing.InjectWith;
11import org.eclipse.xtext.testing.extensions.InjectionExtension;
12import org.junit.jupiter.api.extension.ExtendWith;
13import org.junit.jupiter.params.ParameterizedTest; 10import org.junit.jupiter.params.ParameterizedTest;
14import org.junit.jupiter.params.provider.Arguments; 11import org.junit.jupiter.params.provider.Arguments;
15import org.junit.jupiter.params.provider.MethodSource; 12import org.junit.jupiter.params.provider.MethodSource;
16import tools.refinery.language.model.tests.utils.ProblemParseHelper; 13import tools.refinery.language.tests.InjectWithRefinery;
17import tools.refinery.language.tests.ProblemInjectorProvider; 14import tools.refinery.language.tests.utils.ProblemParseHelper;
18import tools.refinery.store.dse.propagation.PropagationAdapter; 15import tools.refinery.store.dse.propagation.PropagationAdapter;
19import tools.refinery.store.dse.strategy.BestFirstStoreManager; 16import tools.refinery.store.dse.strategy.BestFirstStoreManager;
20import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter; 17import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter;
@@ -34,8 +31,7 @@ import java.util.stream.Stream;
34import static org.hamcrest.MatcherAssert.assertThat; 31import static org.hamcrest.MatcherAssert.assertThat;
35import static org.hamcrest.Matchers.is; 32import static org.hamcrest.Matchers.is;
36 33
37@ExtendWith(InjectionExtension.class) 34@InjectWithRefinery
38@InjectWith(ProblemInjectorProvider.class)
39class SolutionSerializerTest { 35class SolutionSerializerTest {
40 @Inject 36 @Inject
41 private ProblemParseHelper parseHelper; 37 private ProblemParseHelper parseHelper;
@@ -238,6 +234,65 @@ class SolutionSerializerTest {
238 !exists(a). 234 !exists(a).
239 !exists(Foo::new). 235 !exists(Foo::new).
240 Foo(foo1). 236 Foo(foo1).
237 """), Arguments.of("""
238 class Foo {
239 partial Bar[] bar
240 }
241
242 class Bar.
243 """, """
244 bar(a, b).
245 scope Foo = 2, Bar = 2.
246 """, """
247 declare a, b, foo1, bar1.
248 !exists(Foo::new).
249 !exists(Bar::new).
250 Foo(foo1).
251 Bar(bar1).
252 Foo(a).
253 Bar(b).
254 default !bar(*, *).
255 ?bar(foo1, bar1).
256 ?bar(foo1, b).
257 ?bar(a, bar1).
258 bar(a, b).
259 """), Arguments.of("""
260 class Foo.
261 class Bar.
262 pred bar(Foo x, Bar y).
263 """, """
264 bar(a, b).
265 scope Foo = 2, Bar = 2.
266 """, """
267 declare a, b, foo1, bar1.
268 !exists(Foo::new).
269 !exists(Bar::new).
270 Foo(foo1).
271 Bar(bar1).
272 Foo(a).
273 Bar(b).
274 default !bar(*, *).
275 bar(a, b).
276 """), Arguments.of("""
277 class Foo.
278 class Bar.
279 partial pred bar(Foo x, Bar y).
280 """, """
281 bar(a, b).
282 scope Foo = 2, Bar = 2.
283 """, """
284 declare a, b, foo1, bar1.
285 !exists(Foo::new).
286 !exists(Bar::new).
287 Foo(foo1).
288 Bar(bar1).
289 Foo(a).
290 Bar(b).
291 default !bar(*, *).
292 ?bar(foo1, bar1).
293 ?bar(foo1, b).
294 ?bar(a, bar1).
295 bar(a, b).
241 """)); 296 """));
242 } 297 }
243} 298}
diff --git a/subprojects/language-web/build.gradle.kts b/subprojects/language-web/build.gradle.kts
index 00570e48..bcc10030 100644
--- a/subprojects/language-web/build.gradle.kts
+++ b/subprojects/language-web/build.gradle.kts
@@ -24,7 +24,7 @@ dependencies {
24 implementation(libs.jetty.servlet) 24 implementation(libs.jetty.servlet)
25 implementation(libs.jetty.websocket.api) 25 implementation(libs.jetty.websocket.api)
26 implementation(libs.jetty.websocket.server) 26 implementation(libs.jetty.websocket.server)
27 implementation(libs.slf4j.api) 27 implementation(libs.slf4j)
28 implementation(libs.xtext.web) 28 implementation(libs.xtext.web)
29 xtextGenerated(project(":refinery-language", "generatedWebSources")) 29 xtextGenerated(project(":refinery-language", "generatedWebSources"))
30 webapp(project(":refinery-frontend", "productionAssets")) 30 webapp(project(":refinery-frontend", "productionAssets"))
@@ -44,18 +44,6 @@ tasks {
44 } 44 }
45 } 45 }
46 46
47 shadowJar {
48 dependsOn(webapp)
49 from(project.sourceSets.main.map { it.output })
50 exclude("META-INF/INDEX.LIST", "META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA", "schema/*",
51 ".options", ".api_description", "*.profile", "about.*", "about_*.html", "about_files/*",
52 "plugin.xml", "systembundle.properties", "profile.list", "META-INF/resources/xtext/**")
53 append("plugin.properties")
54 from(webapp) {
55 into("webapp")
56 }
57 }
58
59 register<JavaExec>("serve") { 47 register<JavaExec>("serve") {
60 dependsOn(webapp) 48 dependsOn(webapp)
61 val mainRuntimeClasspath = sourceSets.main.map { it.runtimeClasspath } 49 val mainRuntimeClasspath = sourceSets.main.map { it.runtimeClasspath }
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java
index 7febce7d..e7facbf7 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java
@@ -9,11 +9,8 @@ import com.google.inject.Inject;
9import org.eclipse.xtext.service.OperationCanceledManager; 9import org.eclipse.xtext.service.OperationCanceledManager;
10import org.slf4j.Logger; 10import org.slf4j.Logger;
11import org.slf4j.LoggerFactory; 11import org.slf4j.LoggerFactory;
12import tools.refinery.generator.ModelGenerator; 12import tools.refinery.generator.*;
13import tools.refinery.generator.ModelGeneratorFactory;
14import tools.refinery.language.web.semantics.metadata.MetadataCreator; 13import tools.refinery.language.web.semantics.metadata.MetadataCreator;
15import tools.refinery.generator.ProblemLoader;
16import tools.refinery.generator.ValidationErrorsException;
17import tools.refinery.language.web.semantics.PartialInterpretation2Json; 14import tools.refinery.language.web.semantics.PartialInterpretation2Json;
18import tools.refinery.language.web.xtext.server.ThreadPoolExecutorServiceProvider; 15import tools.refinery.language.web.xtext.server.ThreadPoolExecutorServiceProvider;
19import tools.refinery.language.web.xtext.server.push.PushWebDocument; 16import tools.refinery.language.web.xtext.server.push.PushWebDocument;
@@ -149,7 +146,7 @@ public class ModelGenerationWorker implements Runnable {
149 } 146 }
150 notifyResult(new ModelGenerationStatusResult(uuid, "Generating model")); 147 notifyResult(new ModelGenerationStatusResult(uuid, "Generating model"));
151 generator.setRandomSeed(randomSeed); 148 generator.setRandomSeed(randomSeed);
152 if (!generator.tryGenerate()) { 149 if (generator.tryGenerate() != GeneratorResult.SUCCESS) {
153 return new ModelGenerationErrorResult(uuid, "Problem is unsatisfiable"); 150 return new ModelGenerationErrorResult(uuid, "Problem is unsatisfiable");
154 } 151 }
155 notifyResult(new ModelGenerationStatusResult(uuid, "Saving generated model")); 152 notifyResult(new ModelGenerationStatusResult(uuid, "Saving generated model"));
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsWorker.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsWorker.java
index a96b68f9..508e716e 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsWorker.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsWorker.java
@@ -72,7 +72,10 @@ class SemanticsWorker implements Callable<SemanticsResult> {
72 cancellationToken.checkCancelled(); 72 cancellationToken.checkCancelled();
73 ModelSemantics semantics; 73 ModelSemantics semantics;
74 try { 74 try {
75 semantics = semanticsFactory.cancellationToken(cancellationToken).tryCreateSemantics(problem); 75 semantics = semanticsFactory
76 .cancellationToken(cancellationToken)
77 .keepNonExistingObjects(true)
78 .tryCreateSemantics(problem);
76 } catch (TranslationException e) { 79 } catch (TranslationException e) {
77 return new SemanticsResult(e.getMessage()); 80 return new SemanticsResult(e.getMessage());
78 } catch (TracedException e) { 81 } catch (TracedException e) {
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/BasePredicateDetail.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/BasePredicateDetail.java
new file mode 100644
index 00000000..6ffaf267
--- /dev/null
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/BasePredicateDetail.java
@@ -0,0 +1,10 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.web.semantics.metadata;
7
8public record BasePredicateDetail() implements RelationDetail {
9 public static final BasePredicateDetail INSTANCE = new BasePredicateDetail();
10}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/MetadataCreator.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/MetadataCreator.java
index 29f8ab8b..11f0a228 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/MetadataCreator.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/MetadataCreator.java
@@ -156,7 +156,10 @@ public class MetadataCreator {
156 } 156 }
157 157
158 private RelationDetail getPredicateDetail(PredicateDefinition predicate) { 158 private RelationDetail getPredicateDetail(PredicateDefinition predicate) {
159 return PredicateDetail.ofError(predicate.isError()); 159 if (ProblemUtil.isBasePredicate(predicate)) {
160 return BasePredicateDetail.INSTANCE;
161 }
162 return PredicateDetail.ofError(predicate.getKind() == PredicateKind.ERROR);
160 } 163 }
161 164
162 private QualifiedName getQualifiedName(EObject eObject) { 165 private QualifiedName getQualifiedName(EObject eObject) {
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/RelationDetail.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/RelationDetail.java
index bbe563cd..00177858 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/RelationDetail.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/RelationDetail.java
@@ -6,5 +6,5 @@
6package tools.refinery.language.web.semantics.metadata; 6package tools.refinery.language.web.semantics.metadata;
7 7
8public sealed interface RelationDetail permits ClassDetail, ReferenceDetail, PredicateDetail, OppositeReferenceDetail, 8public sealed interface RelationDetail permits ClassDetail, ReferenceDetail, PredicateDetail, OppositeReferenceDetail,
9 BuiltInDetail { 9 BuiltInDetail, BasePredicateDetail {
10} 10}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java
index 818bd80e..13ae1221 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java
@@ -37,7 +37,8 @@ public class XtextWebSocket implements ResponseHandler {
37 .registerSubtype(ReferenceDetail.class, "reference") 37 .registerSubtype(ReferenceDetail.class, "reference")
38 .registerSubtype(OppositeReferenceDetail.class, "opposite") 38 .registerSubtype(OppositeReferenceDetail.class, "opposite")
39 .registerSubtype(PredicateDetail.class, "predicate") 39 .registerSubtype(PredicateDetail.class, "predicate")
40 .registerSubtype(BuiltInDetail.class, "builtin")) 40 .registerSubtype(BuiltInDetail.class, "builtin")
41 .registerSubtype(BasePredicateDetail.class, "base"))
41 .create(); 42 .create();
42 43
43 private final TransactionExecutor executor; 44 private final TransactionExecutor executor;
diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java
index 52acee6d..fe4952a9 100644
--- a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java
+++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java
@@ -17,6 +17,13 @@ public class AwaitTerminationExecutorServiceProvider extends ExecutorServiceProv
17 private final List<RestartableCachedThreadPool> servicesToShutDown = new ArrayList<>(); 17 private final List<RestartableCachedThreadPool> servicesToShutDown = new ArrayList<>();
18 18
19 @Override 19 @Override
20 public ExecutorService get(String key) {
21 synchronized (servicesToShutDown) {
22 return super.get(key);
23 }
24 }
25
26 @Override
20 protected ExecutorService createInstance(String key) { 27 protected ExecutorService createInstance(String key) {
21 var instance = new RestartableCachedThreadPool(() -> super.createInstance(key)); 28 var instance = new RestartableCachedThreadPool(() -> super.createInstance(key));
22 synchronized (servicesToShutDown) { 29 synchronized (servicesToShutDown) {
@@ -35,8 +42,8 @@ public class AwaitTerminationExecutorServiceProvider extends ExecutorServiceProv
35 42
36 @Override 43 @Override
37 public void dispose() { 44 public void dispose() {
38 super.dispose();
39 synchronized (servicesToShutDown) { 45 synchronized (servicesToShutDown) {
46 super.dispose();
40 for (var executorService : servicesToShutDown) { 47 for (var executorService : servicesToShutDown) {
41 executorService.waitForTermination(); 48 executorService.waitForTermination();
42 } 49 }
diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java
index 991ff114..4d55e548 100644
--- a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java
+++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java
@@ -13,29 +13,34 @@ import org.slf4j.LoggerFactory;
13import java.util.Collection; 13import java.util.Collection;
14import java.util.List; 14import java.util.List;
15import java.util.concurrent.*; 15import java.util.concurrent.*;
16import java.util.concurrent.atomic.AtomicReference;
16 17
17public class RestartableCachedThreadPool implements ExecutorService { 18public class RestartableCachedThreadPool implements ExecutorService {
18 private static final Logger LOG = LoggerFactory.getLogger(RestartableCachedThreadPool.class); 19 private static final Logger LOG = LoggerFactory.getLogger(RestartableCachedThreadPool.class);
19 20
20 private ExecutorService delegate; 21 private final AtomicReference<ExecutorService> delegate = new AtomicReference<>();
21 22
22 private final Provider<ExecutorService> executorServiceProvider; 23 private final Provider<ExecutorService> executorServiceProvider;
23 24
24 public RestartableCachedThreadPool(Provider<ExecutorService> executorServiceProvider) { 25 public RestartableCachedThreadPool(Provider<ExecutorService> executorServiceProvider) {
25 this.executorServiceProvider = executorServiceProvider; 26 this.executorServiceProvider = executorServiceProvider;
26 delegate = executorServiceProvider.get(); 27 delegate.set(executorServiceProvider.get());
27 } 28 }
28 29
29 public void waitForAllTasksToFinish() { 30 public void waitForAllTasksToFinish() {
30 delegate.shutdown(); 31 var oldDelegate = delegate.getAndSet(executorServiceProvider.get());
31 waitForTermination(); 32 oldDelegate.shutdown();
32 delegate = executorServiceProvider.get(); 33 waitForTermination(oldDelegate);
33 } 34 }
34 35
35 public void waitForTermination() { 36 public void waitForTermination() {
37 waitForTermination(delegate.get());
38 }
39
40 private static void waitForTermination(ExecutorService executorService) {
36 boolean result = false; 41 boolean result = false;
37 try { 42 try {
38 result = delegate.awaitTermination(10, TimeUnit.SECONDS); 43 result = executorService.awaitTermination(10, TimeUnit.SECONDS);
39 } catch (InterruptedException e) { 44 } catch (InterruptedException e) {
40 LOG.warn("Interrupted while waiting for delegate executor to stop", e); 45 LOG.warn("Interrupted while waiting for delegate executor to stop", e);
41 } 46 }
@@ -46,70 +51,71 @@ public class RestartableCachedThreadPool implements ExecutorService {
46 51
47 @Override 52 @Override
48 public boolean awaitTermination(long arg0, @NotNull TimeUnit arg1) throws InterruptedException { 53 public boolean awaitTermination(long arg0, @NotNull TimeUnit arg1) throws InterruptedException {
49 return delegate.awaitTermination(arg0, arg1); 54 return delegate.get().awaitTermination(arg0, arg1);
50 } 55 }
51 56
52 @Override 57 @Override
53 public void execute(@NotNull Runnable arg0) { 58 public void execute(@NotNull Runnable arg0) {
54 delegate.execute(arg0); 59 delegate.get().execute(arg0);
55 } 60 }
56 61
57 @Override 62 @Override
58 public <T> List<Future<T>> invokeAll(@NotNull Collection<? extends Callable<T>> arg0, long arg1, 63 public <T> @NotNull List<Future<T>> invokeAll(@NotNull Collection<? extends Callable<T>> arg0, long arg1,
59 @NotNull TimeUnit arg2) 64 @NotNull TimeUnit arg2)
60 throws InterruptedException { 65 throws InterruptedException {
61 return delegate.invokeAll(arg0, arg1, arg2); 66 return delegate.get().invokeAll(arg0, arg1, arg2);
62 } 67 }
63 68
64 @Override 69 @Override
65 public <T> List<Future<T>> invokeAll(@NotNull Collection<? extends Callable<T>> arg0) throws InterruptedException { 70 public <T> @NotNull List<Future<T>> invokeAll(@NotNull Collection<? extends Callable<T>> arg0)
66 return delegate.invokeAll(arg0); 71 throws InterruptedException {
72 return delegate.get().invokeAll(arg0);
67 } 73 }
68 74
69 @Override 75 @Override
70 public <T> T invokeAny(@NotNull Collection<? extends Callable<T>> arg0, long arg1, @NotNull TimeUnit arg2) 76 public <T> T invokeAny(@NotNull Collection<? extends Callable<T>> arg0, long arg1, @NotNull TimeUnit arg2)
71 throws InterruptedException, ExecutionException, TimeoutException { 77 throws InterruptedException, ExecutionException, TimeoutException {
72 return delegate.invokeAny(arg0, arg1, arg2); 78 return delegate.get().invokeAny(arg0, arg1, arg2);
73 } 79 }
74 80
75 @Override 81 @Override
76 public <T> T invokeAny(@NotNull Collection<? extends Callable<T>> arg0) throws InterruptedException, 82 public <T> @NotNull T invokeAny(@NotNull Collection<? extends Callable<T>> arg0) throws InterruptedException,
77 ExecutionException { 83 ExecutionException {
78 return delegate.invokeAny(arg0); 84 return delegate.get().invokeAny(arg0);
79 } 85 }
80 86
81 @Override 87 @Override
82 public boolean isShutdown() { 88 public boolean isShutdown() {
83 return delegate.isShutdown(); 89 return delegate.get().isShutdown();
84 } 90 }
85 91
86 @Override 92 @Override
87 public boolean isTerminated() { 93 public boolean isTerminated() {
88 return delegate.isTerminated(); 94 return delegate.get().isTerminated();
89 } 95 }
90 96
91 @Override 97 @Override
92 public void shutdown() { 98 public void shutdown() {
93 delegate.shutdown(); 99 delegate.get().shutdown();
94 } 100 }
95 101
96 @Override 102 @Override
97 public List<Runnable> shutdownNow() { 103 public @NotNull List<Runnable> shutdownNow() {
98 return delegate.shutdownNow(); 104 return delegate.get().shutdownNow();
99 } 105 }
100 106
101 @Override 107 @Override
102 public <T> Future<T> submit(@NotNull Callable<T> arg0) { 108 public <T> @NotNull Future<T> submit(@NotNull Callable<T> arg0) {
103 return delegate.submit(arg0); 109 return delegate.get().submit(arg0);
104 } 110 }
105 111
106 @Override 112 @Override
107 public <T> Future<T> submit(@NotNull Runnable arg0, T arg1) { 113 public <T> @NotNull Future<T> submit(@NotNull Runnable arg0, T arg1) {
108 return delegate.submit(arg0, arg1); 114 return delegate.get().submit(arg0, arg1);
109 } 115 }
110 116
111 @Override 117 @Override
112 public Future<?> submit(@NotNull Runnable arg0) { 118 public @NotNull Future<?> submit(@NotNull Runnable arg0) {
113 return delegate.submit(arg0); 119 return delegate.get().submit(arg0);
114 } 120 }
115} 121}
diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java
index d45a9d6b..6ccf1760 100644
--- a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java
+++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java
@@ -18,7 +18,7 @@ import java.util.List;
18import static org.junit.jupiter.api.Assertions.fail; 18import static org.junit.jupiter.api.Assertions.fail;
19 19
20public abstract class WebSocketIntegrationTestClient { 20public abstract class WebSocketIntegrationTestClient {
21 private static final long TIMEOUT_MILLIS = Duration.ofSeconds(30).toMillis(); 21 private static final long TIMEOUT_MILLIS = Duration.ofSeconds(10).toMillis();
22 22
23 private boolean finished = false; 23 private boolean finished = false;
24 24
diff --git a/subprojects/language/build.gradle.kts b/subprojects/language/build.gradle.kts
index dc338686..6cbecaa6 100644
--- a/subprojects/language/build.gradle.kts
+++ b/subprojects/language/build.gradle.kts
@@ -33,6 +33,7 @@ dependencies {
33 api(libs.xtext.core) 33 api(libs.xtext.core)
34 api(libs.xtext.xbase) 34 api(libs.xtext.xbase)
35 api(project(":refinery-language-model")) 35 api(project(":refinery-language-model"))
36 testFixturesApi(libs.junit.api)
36 testFixturesApi(libs.xtext.testing) 37 testFixturesApi(libs.xtext.testing)
37 mwe2(libs.xtext.generator) 38 mwe2(libs.xtext.generator)
38 mwe2(libs.xtext.generator.antlr) 39 mwe2(libs.xtext.generator.antlr)
diff --git a/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext b/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext
index 7e3b3c83..7cd62dcd 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext
+++ b/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext
@@ -57,9 +57,14 @@ ReferenceDeclaration:
57ReferenceMultiplicity returns Multiplicity: 57ReferenceMultiplicity returns Multiplicity:
58 "[" Multiplicity "]"; 58 "[" Multiplicity "]";
59 59
60enum ErrorPredicateKind returns PredicateKind:
61 ERROR="error";
62
63enum PredicateKind:
64 ERROR="error" | PARTIAL="partial" | SHADOW="shadow";
65
60PredicateDefinition: 66PredicateDefinition:
61 shadow?="shadow"? 67 (kind=ErrorPredicateKind | kind=PredicateKind? "pred")
62 ("pred" | error?="error" "pred"?)
63 name=Identifier 68 name=Identifier
64 "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")" 69 "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")"
65 ("<->" bodies+=Conjunction (";" bodies+=Conjunction)*)? 70 ("<->" bodies+=Conjunction (";" bodies+=Conjunction)*)?
@@ -294,7 +299,7 @@ Identifier:
294 299
295NonContainmentIdentifier: 300NonContainmentIdentifier:
296 ID | "atom" | "multi" | "contained" | "problem" | "module" | 301 ID | "atom" | "multi" | "contained" | "problem" | "module" |
297 "datatype" | "aggregator" | "decision" | "propagation" | "computed"; 302 "datatype" | "aggregator" | "decision" | "propagation" | "shadow";
298 303
299Real returns ecore::EDouble: 304Real returns ecore::EDouble:
300 EXPONENTIAL | INT "." (INT | EXPONENTIAL); 305 EXPONENTIAL | INT "." (INT | EXPONENTIAL);
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/state/ProblemDerivedStateComputer.java b/subprojects/language/src/main/java/tools/refinery/language/resource/state/ProblemDerivedStateComputer.java
index 44f55563..97e93d46 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/resource/state/ProblemDerivedStateComputer.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/resource/state/ProblemDerivedStateComputer.java
@@ -102,7 +102,7 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer {
102 if (declaration.getInvalidMultiplicity() == null) { 102 if (declaration.getInvalidMultiplicity() == null) {
103 var invalidMultiplicity = adapter.createInvalidMultiplicityPredicateIfAbsent(declaration, key -> { 103 var invalidMultiplicity = adapter.createInvalidMultiplicityPredicateIfAbsent(declaration, key -> {
104 var predicate = ProblemFactory.eINSTANCE.createPredicateDefinition(); 104 var predicate = ProblemFactory.eINSTANCE.createPredicateDefinition();
105 predicate.setError(true); 105 predicate.setKind(PredicateKind.ERROR);
106 predicate.setName("invalidMultiplicity"); 106 predicate.setName("invalidMultiplicity");
107 var parameter = ProblemFactory.eINSTANCE.createParameter(); 107 var parameter = ProblemFactory.eINSTANCE.createParameter();
108 parameter.setParameterType(containingClassDeclaration); 108 parameter.setParameterType(containingClassDeclaration);
@@ -125,7 +125,7 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer {
125 if (ProblemUtil.hasComputedValue(predicateDefinition)) { 125 if (ProblemUtil.hasComputedValue(predicateDefinition)) {
126 var computedValue = adapter.createComputedValuePredicateIfAbsent(predicateDefinition, key -> { 126 var computedValue = adapter.createComputedValuePredicateIfAbsent(predicateDefinition, key -> {
127 var predicate = ProblemFactory.eINSTANCE.createPredicateDefinition(); 127 var predicate = ProblemFactory.eINSTANCE.createPredicateDefinition();
128 predicate.setShadow(true); 128 predicate.setKind(PredicateKind.SHADOW);
129 predicate.setName("computed"); 129 predicate.setName("computed");
130 return predicate; 130 return predicate;
131 }); 131 });
diff --git a/subprojects/language/src/main/java/tools/refinery/language/typesystem/TypedModule.java b/subprojects/language/src/main/java/tools/refinery/language/typesystem/TypedModule.java
index f1e5a7ac..a8e3a783 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/typesystem/TypedModule.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/typesystem/TypedModule.java
@@ -75,7 +75,7 @@ public class TypedModule {
75 private void checkTypes(PredicateDefinition predicateDefinition) { 75 private void checkTypes(PredicateDefinition predicateDefinition) {
76 for (var conjunction : predicateDefinition.getBodies()) { 76 for (var conjunction : predicateDefinition.getBodies()) {
77 for (var literal : conjunction.getLiterals()) { 77 for (var literal : conjunction.getLiterals()) {
78 coerceIntoLiteral(literal, predicateDefinition.isShadow()); 78 coerceIntoLiteral(literal, predicateDefinition.getKind() == PredicateKind.SHADOW);
79 } 79 }
80 } 80 }
81 } 81 }
diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java
index 067e684a..75e2ded0 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java
@@ -50,17 +50,19 @@ public final class ProblemUtil {
50 } 50 }
51 51
52 public static boolean isError(EObject eObject) { 52 public static boolean isError(EObject eObject) {
53 return eObject instanceof PredicateDefinition predicateDefinition && predicateDefinition.isError(); 53 return eObject instanceof PredicateDefinition predicateDefinition &&
54 predicateDefinition.getKind() == PredicateKind.ERROR;
54 } 55 }
55 56
56 public static boolean isShadow(EObject eObject) { 57 public static boolean isShadow(EObject eObject) {
57 return eObject instanceof PredicateDefinition predicateDefinition && predicateDefinition.isShadow(); 58 return eObject instanceof PredicateDefinition predicateDefinition &&
59 predicateDefinition.getKind() == PredicateKind.SHADOW;
58 } 60 }
59 61
60 public static boolean mayReferToShadow(EObject context) { 62 public static boolean mayReferToShadow(EObject context) {
61 var definitionContext = EcoreUtil2.getContainerOfType(context, ParametricDefinition.class); 63 var definitionContext = EcoreUtil2.getContainerOfType(context, ParametricDefinition.class);
62 return switch (definitionContext) { 64 return switch (definitionContext) {
63 case PredicateDefinition predicateDefinition -> predicateDefinition.isShadow(); 65 case PredicateDefinition predicateDefinition -> predicateDefinition.getKind() == PredicateKind.SHADOW;
64 case RuleDefinition ignored -> true; 66 case RuleDefinition ignored -> true;
65 case null, default -> false; 67 case null, default -> false;
66 }; 68 };
@@ -112,8 +114,26 @@ public final class ProblemUtil {
112 return true; 114 return true;
113 } 115 }
114 116
117 public static boolean isDerivedStatePredicate(PredicateDefinition predicateDefinition) {
118 var containingFeature = predicateDefinition.eContainingFeature();
119 return containingFeature == ProblemPackage.Literals.REFERENCE_DECLARATION__INVALID_MULTIPLICITY ||
120 containingFeature == ProblemPackage.Literals.PREDICATE_DEFINITION__COMPUTED_VALUE;
121 }
122
123 public static boolean isBasePredicate(PredicateDefinition predicateDefinition) {
124 if (isBuiltIn(predicateDefinition) || predicateDefinition == null) {
125 // Built-in predicates have no clauses, but are not base.
126 return false;
127 }
128 return switch (predicateDefinition.getKind()) {
129 case DEFAULT -> predicateDefinition.getBodies().isEmpty();
130 case PARTIAL -> true;
131 default -> false;
132 };
133 }
134
115 public static boolean hasComputedValue(PredicateDefinition predicateDefinition) { 135 public static boolean hasComputedValue(PredicateDefinition predicateDefinition) {
116 return !predicateDefinition.isShadow() && !predicateDefinition.getBodies().isEmpty(); 136 return predicateDefinition.getKind() != PredicateKind.SHADOW && !isBasePredicate(predicateDefinition);
117 } 137 }
118 138
119 public static boolean isTypeLike(Relation relation) { 139 public static boolean isTypeLike(Relation relation) {
diff --git a/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java b/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java
index aef1e71d..74a6a0fc 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java
@@ -47,6 +47,7 @@ public class ProblemValidator extends AbstractProblemValidator {
47 public static final String INVALID_REFERENCE_TYPE_ISSUE = ISSUE_PREFIX + "INVALID_REFERENCE_TYPE"; 47 public static final String INVALID_REFERENCE_TYPE_ISSUE = ISSUE_PREFIX + "INVALID_REFERENCE_TYPE";
48 public static final String INVALID_ARITY_ISSUE = ISSUE_PREFIX + "INVALID_ARITY"; 48 public static final String INVALID_ARITY_ISSUE = ISSUE_PREFIX + "INVALID_ARITY";
49 public static final String INVALID_MODALITY_ISSUE = ISSUE_PREFIX + "INVALID_MODALITY"; 49 public static final String INVALID_MODALITY_ISSUE = ISSUE_PREFIX + "INVALID_MODALITY";
50 public static final String INVALID_PREDICATE_ISSUE = ISSUE_PREFIX + "INVALID_PREDICATE";
50 public static final String INVALID_RULE_ISSUE = ISSUE_PREFIX + "INVALID_RULE"; 51 public static final String INVALID_RULE_ISSUE = ISSUE_PREFIX + "INVALID_RULE";
51 public static final String INVALID_TRANSITIVE_CLOSURE_ISSUE = ISSUE_PREFIX + "INVALID_TRANSITIVE_CLOSURE"; 52 public static final String INVALID_TRANSITIVE_CLOSURE_ISSUE = ISSUE_PREFIX + "INVALID_TRANSITIVE_CLOSURE";
52 public static final String SHADOW_RELATION_ISSUE = ISSUE_PREFIX + "SHADOW_RELATION"; 53 public static final String SHADOW_RELATION_ISSUE = ISSUE_PREFIX + "SHADOW_RELATION";
@@ -381,10 +382,27 @@ public class ProblemValidator extends AbstractProblemValidator {
381 382
382 @Check 383 @Check
383 public void checkPredicateDefinition(PredicateDefinition predicateDefinition) { 384 public void checkPredicateDefinition(PredicateDefinition predicateDefinition) {
384 if (predicateDefinition.isError() && predicateDefinition.isShadow()) { 385 if (ProblemUtil.isBuiltIn(predicateDefinition) || ProblemUtil.isDerivedStatePredicate(predicateDefinition)) {
385 var message = "Shadow predicates cannot be marked as error predicates."; 386 return;
386 acceptError(message, predicateDefinition, ProblemPackage.Literals.PREDICATE_DEFINITION__ERROR, 0, 387 }
387 SHADOW_RELATION_ISSUE); 388 String message = null;
389 if (ProblemUtil.isBasePredicate(predicateDefinition)) {
390 if (!predicateDefinition.getBodies().isEmpty()) {
391 var predicateType = predicateDefinition.getKind() == PredicateKind.PARTIAL ? "Partial base predicate" :
392 "Base predicate";
393 message = "%s '%s' must not have any clauses.".formatted(predicateType, predicateDefinition.getName());
394 }
395 } else if (predicateDefinition.getBodies().isEmpty()) {
396 var predicateType = switch (predicateDefinition.getKind()) {
397 case ERROR -> "Error predicate";
398 case SHADOW -> "Shadow predicate";
399 default -> "Predicate";
400 };
401 message = "%s '%s' must have at least one clause.".formatted(predicateType, predicateDefinition.getName());
402 }
403 if (message != null) {
404 acceptError(message, predicateDefinition, ProblemPackage.Literals.NAMED_ELEMENT__NAME, 0,
405 INVALID_PREDICATE_ISSUE);
388 } 406 }
389 } 407 }
390 408
@@ -504,6 +522,11 @@ public class ProblemValidator extends AbstractProblemValidator {
504 acceptError(message, assertion, ProblemPackage.Literals.ABSTRACT_ASSERTION__RELATION, 0, 522 acceptError(message, assertion, ProblemPackage.Literals.ABSTRACT_ASSERTION__RELATION, 0,
505 SHADOW_RELATION_ISSUE); 523 SHADOW_RELATION_ISSUE);
506 } 524 }
525 if (ProblemUtil.isError(relation)) {
526 var message = "Assertions for error predicates are not supported.";
527 acceptError(message, assertion, ProblemPackage.Literals.ABSTRACT_ASSERTION__RELATION, 0,
528 UNSUPPORTED_ASSERTION_ISSUE);
529 }
507 int argumentCount = assertion.getArguments().size(); 530 int argumentCount = assertion.getArguments().size();
508 checkArity(assertion, ProblemPackage.Literals.ABSTRACT_ASSERTION__RELATION, argumentCount); 531 checkArity(assertion, ProblemPackage.Literals.ABSTRACT_ASSERTION__RELATION, argumentCount);
509 } 532 }
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java
index 17ae5fbb..68c5d31e 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java
@@ -6,17 +6,13 @@
6package tools.refinery.language.tests; 6package tools.refinery.language.tests;
7 7
8import com.google.inject.Inject; 8import com.google.inject.Inject;
9import org.eclipse.xtext.testing.InjectWith;
10import org.eclipse.xtext.testing.extensions.InjectionExtension;
11import org.junit.jupiter.api.Test; 9import org.junit.jupiter.api.Test;
12import org.junit.jupiter.api.extension.ExtendWith; 10import tools.refinery.language.tests.utils.ProblemParseHelper;
13import tools.refinery.language.model.tests.utils.ProblemParseHelper;
14 11
15import static org.hamcrest.MatcherAssert.assertThat; 12import static org.hamcrest.MatcherAssert.assertThat;
16import static org.hamcrest.Matchers.empty; 13import static org.hamcrest.Matchers.empty;
17 14
18@ExtendWith(InjectionExtension.class) 15@InjectWithRefinery
19@InjectWith(ProblemInjectorProvider.class)
20class ProblemParsingTest { 16class ProblemParsingTest {
21 @Inject 17 @Inject
22 private ProblemParseHelper parseHelper; 18 private ProblemParseHelper parseHelper;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/documentation/DocumentationCommentParserTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/documentation/DocumentationCommentParserTest.java
index 0566e7e2..5227a733 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/documentation/DocumentationCommentParserTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/documentation/DocumentationCommentParserTest.java
@@ -6,23 +6,19 @@
6package tools.refinery.language.tests.documentation; 6package tools.refinery.language.tests.documentation;
7 7
8import com.google.inject.Inject; 8import com.google.inject.Inject;
9import org.eclipse.xtext.testing.InjectWith;
10import org.eclipse.xtext.testing.extensions.InjectionExtension;
11import org.junit.jupiter.api.extension.ExtendWith;
12import org.junit.jupiter.params.ParameterizedTest; 9import org.junit.jupiter.params.ParameterizedTest;
13import org.junit.jupiter.params.provider.Arguments; 10import org.junit.jupiter.params.provider.Arguments;
14import org.junit.jupiter.params.provider.MethodSource; 11import org.junit.jupiter.params.provider.MethodSource;
15import tools.refinery.language.documentation.DocumentationCommentParser; 12import tools.refinery.language.documentation.DocumentationCommentParser;
16import tools.refinery.language.model.tests.utils.ProblemParseHelper; 13import tools.refinery.language.tests.InjectWithRefinery;
17import tools.refinery.language.tests.ProblemInjectorProvider; 14import tools.refinery.language.tests.utils.ProblemParseHelper;
18 15
19import java.util.stream.Stream; 16import java.util.stream.Stream;
20 17
21import static org.hamcrest.MatcherAssert.assertThat; 18import static org.hamcrest.MatcherAssert.assertThat;
22import static org.hamcrest.Matchers.is; 19import static org.hamcrest.Matchers.is;
23 20
24@ExtendWith(InjectionExtension.class) 21@InjectWithRefinery
25@InjectWith(ProblemInjectorProvider.class)
26class DocumentationCommentParserTest { 22class DocumentationCommentParserTest {
27 @Inject 23 @Inject
28 private ProblemParseHelper parseHelper; 24 private ProblemParseHelper parseHelper;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java
index 4a15f9de..52806be1 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java
@@ -13,21 +13,17 @@ import org.eclipse.xtext.formatting2.regionaccess.ITextRegionAccess;
13import org.eclipse.xtext.formatting2.regionaccess.ITextReplacement; 13import org.eclipse.xtext.formatting2.regionaccess.ITextReplacement;
14import org.eclipse.xtext.formatting2.regionaccess.TextRegionAccessBuilder; 14import org.eclipse.xtext.formatting2.regionaccess.TextRegionAccessBuilder;
15import org.eclipse.xtext.resource.XtextResource; 15import org.eclipse.xtext.resource.XtextResource;
16import org.eclipse.xtext.testing.InjectWith;
17import org.eclipse.xtext.testing.extensions.InjectionExtension;
18import org.eclipse.xtext.testing.util.ParseHelper; 16import org.eclipse.xtext.testing.util.ParseHelper;
19import org.junit.jupiter.api.Test; 17import org.junit.jupiter.api.Test;
20import org.junit.jupiter.api.extension.ExtendWith;
21import tools.refinery.language.model.problem.Problem; 18import tools.refinery.language.model.problem.Problem;
22import tools.refinery.language.tests.ProblemInjectorProvider; 19import tools.refinery.language.tests.InjectWithRefinery;
23 20
24import java.util.List; 21import java.util.List;
25 22
26import static org.hamcrest.MatcherAssert.assertThat; 23import static org.hamcrest.MatcherAssert.assertThat;
27import static org.hamcrest.Matchers.equalTo; 24import static org.hamcrest.Matchers.equalTo;
28 25
29@ExtendWith(InjectionExtension.class) 26@InjectWithRefinery
30@InjectWith(ProblemInjectorProvider.class)
31class ProblemFormatterTest { 27class ProblemFormatterTest {
32 @Inject 28 @Inject
33 private ParseHelper<Problem> parseHelper; 29 private ParseHelper<Problem> parseHelper;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/linking/AmbiguousReferenceTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/linking/AmbiguousReferenceTest.java
index 464c207c..ffeaace2 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/linking/AmbiguousReferenceTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/linking/AmbiguousReferenceTest.java
@@ -8,19 +8,15 @@ package tools.refinery.language.tests.linking;
8 8
9import com.google.inject.Inject; 9import com.google.inject.Inject;
10import org.eclipse.xtext.diagnostics.Diagnostic; 10import org.eclipse.xtext.diagnostics.Diagnostic;
11import org.eclipse.xtext.testing.InjectWith;
12import org.eclipse.xtext.testing.extensions.InjectionExtension;
13import org.junit.jupiter.api.extension.ExtendWith;
14import org.junit.jupiter.params.ParameterizedTest; 11import org.junit.jupiter.params.ParameterizedTest;
15import org.junit.jupiter.params.provider.ValueSource; 12import org.junit.jupiter.params.provider.ValueSource;
16import tools.refinery.language.model.tests.utils.ProblemParseHelper; 13import tools.refinery.language.tests.InjectWithRefinery;
17import tools.refinery.language.tests.ProblemInjectorProvider; 14import tools.refinery.language.tests.utils.ProblemParseHelper;
18 15
19import static org.hamcrest.MatcherAssert.assertThat; 16import static org.hamcrest.MatcherAssert.assertThat;
20import static org.hamcrest.Matchers.*; 17import static org.hamcrest.Matchers.*;
21 18
22@ExtendWith(InjectionExtension.class) 19@InjectWithRefinery
23@InjectWith(ProblemInjectorProvider.class)
24class AmbiguousReferenceTest { 20class AmbiguousReferenceTest {
25 @Inject 21 @Inject
26 private ProblemParseHelper parseHelper; 22 private ProblemParseHelper parseHelper;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java
index 37d38dd9..e798cc95 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java
@@ -6,23 +6,19 @@
6package tools.refinery.language.tests.parser.antlr; 6package tools.refinery.language.tests.parser.antlr;
7 7
8import com.google.inject.Inject; 8import com.google.inject.Inject;
9import org.eclipse.xtext.testing.InjectWith;
10import org.eclipse.xtext.testing.extensions.InjectionExtension;
11import org.junit.jupiter.api.extension.ExtendWith;
12import org.junit.jupiter.params.ParameterizedTest; 9import org.junit.jupiter.params.ParameterizedTest;
13import org.junit.jupiter.params.provider.Arguments; 10import org.junit.jupiter.params.provider.Arguments;
14import org.junit.jupiter.params.provider.MethodSource; 11import org.junit.jupiter.params.provider.MethodSource;
12import tools.refinery.language.tests.InjectWithRefinery;
15import tools.refinery.language.parser.antlr.IdentifierTokenProvider; 13import tools.refinery.language.parser.antlr.IdentifierTokenProvider;
16import tools.refinery.language.parser.antlr.internal.InternalProblemParser; 14import tools.refinery.language.parser.antlr.internal.InternalProblemParser;
17import tools.refinery.language.tests.ProblemInjectorProvider;
18 15
19import java.util.stream.Stream; 16import java.util.stream.Stream;
20 17
21import static org.hamcrest.MatcherAssert.assertThat; 18import static org.hamcrest.MatcherAssert.assertThat;
22import static org.hamcrest.Matchers.equalTo; 19import static org.hamcrest.Matchers.equalTo;
23 20
24@ExtendWith(InjectionExtension.class) 21@InjectWithRefinery
25@InjectWith(ProblemInjectorProvider.class)
26class IdentifierTokenProviderTest { 22class IdentifierTokenProviderTest {
27 @Inject 23 @Inject
28 private IdentifierTokenProvider identifierTokenProvider; 24 private IdentifierTokenProvider identifierTokenProvider;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java
index 644744a0..d42a5728 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java
@@ -12,18 +12,15 @@ import org.antlr.runtime.ANTLRStringStream;
12import org.antlr.runtime.Token; 12import org.antlr.runtime.Token;
13import org.eclipse.xtext.parser.antlr.Lexer; 13import org.eclipse.xtext.parser.antlr.Lexer;
14import org.eclipse.xtext.parser.antlr.LexerBindings; 14import org.eclipse.xtext.parser.antlr.LexerBindings;
15import org.eclipse.xtext.testing.InjectWith;
16import org.eclipse.xtext.testing.extensions.InjectionExtension;
17import org.hamcrest.Matcher; 15import org.hamcrest.Matcher;
18import org.junit.jupiter.api.extension.ExtendWith;
19import org.junit.jupiter.params.ParameterizedTest; 16import org.junit.jupiter.params.ParameterizedTest;
20import org.junit.jupiter.params.provider.Arguments; 17import org.junit.jupiter.params.provider.Arguments;
21import org.junit.jupiter.params.provider.MethodSource; 18import org.junit.jupiter.params.provider.MethodSource;
22import org.junit.jupiter.params.provider.ValueSource; 19import org.junit.jupiter.params.provider.ValueSource;
20import tools.refinery.language.tests.InjectWithRefinery;
23import tools.refinery.language.parser.antlr.IdentifierTokenProvider; 21import tools.refinery.language.parser.antlr.IdentifierTokenProvider;
24import tools.refinery.language.parser.antlr.ProblemTokenSource; 22import tools.refinery.language.parser.antlr.ProblemTokenSource;
25import tools.refinery.language.parser.antlr.internal.InternalProblemParser; 23import tools.refinery.language.parser.antlr.internal.InternalProblemParser;
26import tools.refinery.language.tests.ProblemInjectorProvider;
27 24
28import java.util.ArrayList; 25import java.util.ArrayList;
29import java.util.List; 26import java.util.List;
@@ -32,8 +29,7 @@ import java.util.stream.Stream;
32import static org.hamcrest.MatcherAssert.assertThat; 29import static org.hamcrest.MatcherAssert.assertThat;
33import static org.hamcrest.Matchers.*; 30import static org.hamcrest.Matchers.*;
34 31
35@ExtendWith(InjectionExtension.class) 32@InjectWithRefinery
36@InjectWith(ProblemInjectorProvider.class)
37class ProblemTokenSourceTest { 33class ProblemTokenSourceTest {
38 @Inject 34 @Inject
39 @Named(LexerBindings.RUNTIME) 35 @Named(LexerBindings.RUNTIME)
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java
index a9c5f62a..bfac1c0c 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java
@@ -6,22 +6,18 @@
6package tools.refinery.language.tests.parser.antlr; 6package tools.refinery.language.tests.parser.antlr;
7 7
8import com.google.inject.Inject; 8import com.google.inject.Inject;
9import org.eclipse.xtext.testing.InjectWith;
10import org.eclipse.xtext.testing.extensions.InjectionExtension;
11import org.junit.jupiter.api.Test; 9import org.junit.jupiter.api.Test;
12import org.junit.jupiter.api.extension.ExtendWith;
13import tools.refinery.language.model.problem.ArithmeticBinaryExpr; 10import tools.refinery.language.model.problem.ArithmeticBinaryExpr;
14import tools.refinery.language.model.problem.Atom; 11import tools.refinery.language.model.problem.Atom;
15import tools.refinery.language.model.problem.BinaryOp; 12import tools.refinery.language.model.problem.BinaryOp;
16import tools.refinery.language.model.problem.ComparisonExpr; 13import tools.refinery.language.model.problem.ComparisonExpr;
17import tools.refinery.language.model.tests.utils.ProblemParseHelper; 14import tools.refinery.language.tests.InjectWithRefinery;
18import tools.refinery.language.tests.ProblemInjectorProvider; 15import tools.refinery.language.tests.utils.ProblemParseHelper;
19 16
20import static org.hamcrest.MatcherAssert.assertThat; 17import static org.hamcrest.MatcherAssert.assertThat;
21import static org.hamcrest.Matchers.*; 18import static org.hamcrest.Matchers.*;
22 19
23@ExtendWith(InjectionExtension.class) 20@InjectWithRefinery
24@InjectWith(ProblemInjectorProvider.class)
25class TransitiveClosureParserTest { 21class TransitiveClosureParserTest {
26 @Inject 22 @Inject
27 private ProblemParseHelper parseHelper; 23 private ProblemParseHelper parseHelper;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java
deleted file mode 100644
index 15636483..00000000
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.tests.rules;
7
8import com.google.inject.Inject;
9import org.eclipse.xtext.testing.InjectWith;
10import org.eclipse.xtext.testing.extensions.InjectionExtension;
11import org.junit.jupiter.api.Disabled;
12import org.junit.jupiter.api.extension.ExtendWith;
13import org.junit.jupiter.params.ParameterizedTest;
14import org.junit.jupiter.params.provider.ValueSource;
15import tools.refinery.language.model.tests.utils.ProblemParseHelper;
16import tools.refinery.language.tests.ProblemInjectorProvider;
17
18import static org.hamcrest.MatcherAssert.assertThat;
19import static org.hamcrest.Matchers.empty;
20
21@Disabled("TODO: Rework transformation rules")
22@ExtendWith(InjectionExtension.class)
23@InjectWith(ProblemInjectorProvider.class)
24class RuleParsingTest {
25 @Inject
26 private ProblemParseHelper parseHelper;
27
28 @ParameterizedTest
29 @ValueSource(strings = { """
30 pred Person(p).
31 rule r(p1): must Person(p1) ==> Person(p1): false.
32 """, """
33 pred Person(p).
34 rule r(p1): must Person(p1) ==> !Person(p1).
35 """ })
36 void simpleTest(String text) {
37 var problem = parseHelper.parse(text);
38 assertThat(problem.getResourceErrors(), empty());
39 }
40}
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java
index 0704e026..ca843734 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java
@@ -6,26 +6,22 @@
6package tools.refinery.language.tests.scoping; 6package tools.refinery.language.tests.scoping;
7 7
8import com.google.inject.Inject; 8import com.google.inject.Inject;
9import org.eclipse.xtext.testing.InjectWith;
10import org.eclipse.xtext.testing.extensions.InjectionExtension;
11import org.junit.jupiter.api.Disabled; 9import org.junit.jupiter.api.Disabled;
12import org.junit.jupiter.api.Test; 10import org.junit.jupiter.api.Test;
13import org.junit.jupiter.api.extension.ExtendWith;
14import org.junit.jupiter.params.ParameterizedTest; 11import org.junit.jupiter.params.ParameterizedTest;
15import org.junit.jupiter.params.provider.Arguments; 12import org.junit.jupiter.params.provider.Arguments;
16import org.junit.jupiter.params.provider.MethodSource; 13import org.junit.jupiter.params.provider.MethodSource;
17import org.junit.jupiter.params.provider.ValueSource; 14import org.junit.jupiter.params.provider.ValueSource;
18import tools.refinery.language.model.tests.utils.ProblemParseHelper; 15import tools.refinery.language.tests.InjectWithRefinery;
19import tools.refinery.language.model.tests.utils.WrappedProblem; 16import tools.refinery.language.tests.utils.ProblemParseHelper;
20import tools.refinery.language.tests.ProblemInjectorProvider; 17import tools.refinery.language.tests.utils.WrappedProblem;
21 18
22import java.util.stream.Stream; 19import java.util.stream.Stream;
23 20
24import static org.hamcrest.MatcherAssert.assertThat; 21import static org.hamcrest.MatcherAssert.assertThat;
25import static org.hamcrest.Matchers.*; 22import static org.hamcrest.Matchers.*;
26 23
27@ExtendWith(InjectionExtension.class) 24@InjectWithRefinery
28@InjectWith(ProblemInjectorProvider.class)
29class NodeScopingTest { 25class NodeScopingTest {
30 @Inject 26 @Inject
31 private ProblemParseHelper parseHelper; 27 private ProblemParseHelper parseHelper;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java
index ad583f8e..2757e08a 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java
@@ -9,17 +9,14 @@ import com.google.inject.Inject;
9import org.eclipse.emf.common.util.URI; 9import org.eclipse.emf.common.util.URI;
10import org.eclipse.emf.ecore.resource.Resource; 10import org.eclipse.emf.ecore.resource.Resource;
11import org.eclipse.emf.ecore.resource.ResourceSet; 11import org.eclipse.emf.ecore.resource.ResourceSet;
12import org.eclipse.xtext.testing.InjectWith;
13import org.eclipse.xtext.testing.extensions.InjectionExtension;
14import org.junit.jupiter.api.BeforeEach; 12import org.junit.jupiter.api.BeforeEach;
15import org.junit.jupiter.api.Test; 13import org.junit.jupiter.api.Test;
16import org.junit.jupiter.api.extension.ExtendWith;
17import org.junit.jupiter.params.ParameterizedTest; 14import org.junit.jupiter.params.ParameterizedTest;
18import org.junit.jupiter.params.provider.Arguments; 15import org.junit.jupiter.params.provider.Arguments;
19import org.junit.jupiter.params.provider.MethodSource; 16import org.junit.jupiter.params.provider.MethodSource;
20import tools.refinery.language.model.problem.*; 17import tools.refinery.language.model.problem.*;
21import tools.refinery.language.model.tests.utils.WrappedProblem; 18import tools.refinery.language.tests.InjectWithRefinery;
22import tools.refinery.language.tests.ProblemInjectorProvider; 19import tools.refinery.language.tests.utils.WrappedProblem;
23 20
24import java.io.ByteArrayOutputStream; 21import java.io.ByteArrayOutputStream;
25import java.io.IOException; 22import java.io.IOException;
@@ -29,8 +26,7 @@ import java.util.stream.Stream;
29import static org.hamcrest.MatcherAssert.assertThat; 26import static org.hamcrest.MatcherAssert.assertThat;
30import static org.hamcrest.Matchers.equalTo; 27import static org.hamcrest.Matchers.equalTo;
31 28
32@ExtendWith(InjectionExtension.class) 29@InjectWithRefinery
33@InjectWith(ProblemInjectorProvider.class)
34class ProblemSerializerTest { 30class ProblemSerializerTest {
35 @Inject 31 @Inject
36 private ResourceSet resourceSet; 32 private ResourceSet resourceSet;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ArityValidationTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ArityValidationTest.java
index 68e9fa8d..84ec19ab 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ArityValidationTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ArityValidationTest.java
@@ -7,16 +7,13 @@ package tools.refinery.language.tests.validation;
7 7
8import com.google.inject.Inject; 8import com.google.inject.Inject;
9import org.eclipse.emf.common.util.Diagnostic; 9import org.eclipse.emf.common.util.Diagnostic;
10import org.eclipse.xtext.testing.InjectWith;
11import org.eclipse.xtext.testing.extensions.InjectionExtension;
12import org.junit.jupiter.api.Test; 10import org.junit.jupiter.api.Test;
13import org.junit.jupiter.api.extension.ExtendWith;
14import org.junit.jupiter.params.ParameterizedTest; 11import org.junit.jupiter.params.ParameterizedTest;
15import org.junit.jupiter.params.provider.Arguments; 12import org.junit.jupiter.params.provider.Arguments;
16import org.junit.jupiter.params.provider.MethodSource; 13import org.junit.jupiter.params.provider.MethodSource;
17import org.junit.jupiter.params.provider.ValueSource; 14import org.junit.jupiter.params.provider.ValueSource;
18import tools.refinery.language.model.tests.utils.ProblemParseHelper; 15import tools.refinery.language.tests.InjectWithRefinery;
19import tools.refinery.language.tests.ProblemInjectorProvider; 16import tools.refinery.language.tests.utils.ProblemParseHelper;
20import tools.refinery.language.validation.ProblemValidator; 17import tools.refinery.language.validation.ProblemValidator;
21 18
22import java.util.stream.Stream; 19import java.util.stream.Stream;
@@ -24,8 +21,7 @@ import java.util.stream.Stream;
24import static org.hamcrest.MatcherAssert.assertThat; 21import static org.hamcrest.MatcherAssert.assertThat;
25import static org.hamcrest.Matchers.*; 22import static org.hamcrest.Matchers.*;
26 23
27@ExtendWith(InjectionExtension.class) 24@InjectWithRefinery
28@InjectWith(ProblemInjectorProvider.class)
29class ArityValidationTest { 25class ArityValidationTest {
30 @Inject 26 @Inject
31 private ProblemParseHelper parseHelper; 27 private ProblemParseHelper parseHelper;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssertionValidationTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssertionValidationTest.java
index b995d0bb..67bea5d6 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssertionValidationTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssertionValidationTest.java
@@ -6,22 +6,17 @@
6package tools.refinery.language.tests.validation; 6package tools.refinery.language.tests.validation;
7 7
8import com.google.inject.Inject; 8import com.google.inject.Inject;
9import org.eclipse.xtext.testing.InjectWith;
10import org.eclipse.xtext.testing.extensions.InjectionExtension;
11import org.junit.jupiter.api.Test; 9import org.junit.jupiter.api.Test;
12import org.junit.jupiter.api.extension.ExtendWith;
13import org.junit.jupiter.params.ParameterizedTest; 10import org.junit.jupiter.params.ParameterizedTest;
14import org.junit.jupiter.params.provider.ValueSource; 11import org.junit.jupiter.params.provider.ValueSource;
15import tools.refinery.language.model.tests.utils.ProblemParseHelper; 12import tools.refinery.language.tests.InjectWithRefinery;
16import tools.refinery.language.tests.ProblemInjectorProvider; 13import tools.refinery.language.tests.utils.ProblemParseHelper;
17import tools.refinery.language.validation.ProblemValidator; 14import tools.refinery.language.validation.ProblemValidator;
18 15
19import static org.hamcrest.MatcherAssert.assertThat; 16import static org.hamcrest.MatcherAssert.assertThat;
20import static org.hamcrest.Matchers.*; 17import static org.hamcrest.Matchers.*;
21import static org.hamcrest.Matchers.is;
22 18
23@ExtendWith(InjectionExtension.class) 19@InjectWithRefinery
24@InjectWith(ProblemInjectorProvider.class)
25class AssertionValidationTest { 20class AssertionValidationTest {
26 @Inject 21 @Inject
27 private ProblemParseHelper parseHelper; 22 private ProblemParseHelper parseHelper;
@@ -107,4 +102,18 @@ class AssertionValidationTest {
107 assertThat(issues, not(hasItem(hasProperty("issueCode", 102 assertThat(issues, not(hasItem(hasProperty("issueCode",
108 is(ProblemValidator.UNSUPPORTED_ASSERTION_ISSUE))))); 103 is(ProblemValidator.UNSUPPORTED_ASSERTION_ISSUE)))));
109 } 104 }
105
106 @Test
107 void errorPredicateAssertionTest() {
108 var problem = parseHelper.parse("""
109 class Foo.
110
111 error bar(x) <-> Foo(x).
112
113 bar(f1).
114 """);
115 var issues = problem.validate();
116 assertThat(issues, hasItem(hasProperty("issueCode",
117 is(ProblemValidator.UNSUPPORTED_ASSERTION_ISSUE))));
118 }
110} 119}
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssignmentValidationTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssignmentValidationTest.java
index a9e0e311..ef0c62ec 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssignmentValidationTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/AssignmentValidationTest.java
@@ -7,21 +7,17 @@ package tools.refinery.language.tests.validation;
7 7
8 8
9import com.google.inject.Inject; 9import com.google.inject.Inject;
10import org.eclipse.xtext.testing.InjectWith;
11import org.eclipse.xtext.testing.extensions.InjectionExtension;
12import org.junit.jupiter.api.Test; 10import org.junit.jupiter.api.Test;
13import org.junit.jupiter.api.extension.ExtendWith;
14import org.junit.jupiter.params.ParameterizedTest; 11import org.junit.jupiter.params.ParameterizedTest;
15import org.junit.jupiter.params.provider.ValueSource; 12import org.junit.jupiter.params.provider.ValueSource;
16import tools.refinery.language.model.tests.utils.ProblemParseHelper; 13import tools.refinery.language.tests.InjectWithRefinery;
17import tools.refinery.language.tests.ProblemInjectorProvider; 14import tools.refinery.language.tests.utils.ProblemParseHelper;
18import tools.refinery.language.validation.ProblemValidator; 15import tools.refinery.language.validation.ProblemValidator;
19 16
20import static org.hamcrest.MatcherAssert.assertThat; 17import static org.hamcrest.MatcherAssert.assertThat;
21import static org.hamcrest.Matchers.*; 18import static org.hamcrest.Matchers.*;
22 19
23@ExtendWith(InjectionExtension.class) 20@InjectWithRefinery
24@InjectWith(ProblemInjectorProvider.class)
25class AssignmentValidationTest { 21class AssignmentValidationTest {
26 @Inject 22 @Inject
27 private ProblemParseHelper parseHelper; 23 private ProblemParseHelper parseHelper;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ModuleValidationTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ModuleValidationTest.java
index 00ad051b..6dc16029 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ModuleValidationTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/ModuleValidationTest.java
@@ -6,15 +6,12 @@
6package tools.refinery.language.tests.validation; 6package tools.refinery.language.tests.validation;
7 7
8import com.google.inject.Inject; 8import com.google.inject.Inject;
9import org.eclipse.xtext.testing.InjectWith;
10import org.eclipse.xtext.testing.extensions.InjectionExtension;
11import org.junit.jupiter.api.Test; 9import org.junit.jupiter.api.Test;
12import org.junit.jupiter.api.extension.ExtendWith;
13import org.junit.jupiter.params.ParameterizedTest; 10import org.junit.jupiter.params.ParameterizedTest;
14import org.junit.jupiter.params.provider.Arguments; 11import org.junit.jupiter.params.provider.Arguments;
15import org.junit.jupiter.params.provider.MethodSource; 12import org.junit.jupiter.params.provider.MethodSource;
16import tools.refinery.language.model.tests.utils.ProblemParseHelper; 13import tools.refinery.language.tests.InjectWithRefinery;
17import tools.refinery.language.tests.ProblemInjectorProvider; 14import tools.refinery.language.tests.utils.ProblemParseHelper;
18import tools.refinery.language.validation.ProblemValidator; 15import tools.refinery.language.validation.ProblemValidator;
19 16
20import java.util.stream.Stream; 17import java.util.stream.Stream;
@@ -22,8 +19,7 @@ import java.util.stream.Stream;
22import static org.hamcrest.MatcherAssert.assertThat; 19import static org.hamcrest.MatcherAssert.assertThat;
23import static org.hamcrest.Matchers.*; 20import static org.hamcrest.Matchers.*;
24 21
25@ExtendWith(InjectionExtension.class) 22@InjectWithRefinery
26@InjectWith(ProblemInjectorProvider.class)
27class ModuleValidationTest { 23class ModuleValidationTest {
28 @Inject 24 @Inject
29 private ProblemParseHelper parseHelper; 25 private ProblemParseHelper parseHelper;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/MultiplicityValidationTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/MultiplicityValidationTest.java
index a8bcb1a6..81264d3a 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/MultiplicityValidationTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/MultiplicityValidationTest.java
@@ -7,20 +7,16 @@ package tools.refinery.language.tests.validation;
7 7
8import com.google.inject.Inject; 8import com.google.inject.Inject;
9import org.eclipse.emf.common.util.Diagnostic; 9import org.eclipse.emf.common.util.Diagnostic;
10import org.eclipse.xtext.testing.InjectWith;
11import org.eclipse.xtext.testing.extensions.InjectionExtension;
12import org.junit.jupiter.api.extension.ExtendWith;
13import org.junit.jupiter.params.ParameterizedTest; 10import org.junit.jupiter.params.ParameterizedTest;
14import org.junit.jupiter.params.provider.ValueSource; 11import org.junit.jupiter.params.provider.ValueSource;
15import tools.refinery.language.model.tests.utils.ProblemParseHelper; 12import tools.refinery.language.tests.InjectWithRefinery;
16import tools.refinery.language.tests.ProblemInjectorProvider; 13import tools.refinery.language.tests.utils.ProblemParseHelper;
17import tools.refinery.language.validation.ProblemValidator; 14import tools.refinery.language.validation.ProblemValidator;
18 15
19import static org.hamcrest.MatcherAssert.assertThat; 16import static org.hamcrest.MatcherAssert.assertThat;
20import static org.hamcrest.Matchers.*; 17import static org.hamcrest.Matchers.*;
21 18
22@ExtendWith(InjectionExtension.class) 19@InjectWithRefinery
23@InjectWith(ProblemInjectorProvider.class)
24class MultiplicityValidationTest { 20class MultiplicityValidationTest {
25 @Inject 21 @Inject
26 private ProblemParseHelper parseHelper; 22 private ProblemParseHelper parseHelper;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/OppositeValidationTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/OppositeValidationTest.java
index d73ef8e7..7844f49c 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/validation/OppositeValidationTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/validation/OppositeValidationTest.java
@@ -7,14 +7,11 @@ package tools.refinery.language.tests.validation;
7 7
8import com.google.inject.Inject; 8import com.google.inject.Inject;
9import org.eclipse.emf.common.util.Diagnostic; 9import org.eclipse.emf.common.util.Diagnostic;
10import org.eclipse.xtext.testing.InjectWith;
11import org.eclipse.xtext.testing.extensions.InjectionExtension;
12import org.junit.jupiter.api.Test; 10import org.junit.jupiter.api.Test;
13import org.junit.jupiter.api.extension.ExtendWith;
14import org.junit.jupiter.params.ParameterizedTest; 11import org.junit.jupiter.params.ParameterizedTest;
15import org.junit.jupiter.params.provider.ValueSource; 12import org.junit.jupiter.params.provider.ValueSource;
16import tools.refinery.language.model.tests.utils.ProblemParseHelper; 13import tools.refinery.language.tests.InjectWithRefinery;
17import tools.refinery.language.tests.ProblemInjectorProvider; 14import tools.refinery.language.tests.utils.ProblemParseHelper;
18import tools.refinery.language.validation.ProblemValidator; 15import tools.refinery.language.validation.ProblemValidator;
19 16
20import java.util.Set; 17import java.util.Set;
@@ -22,8 +19,7 @@ import java.util.Set;
22import static org.hamcrest.MatcherAssert.assertThat; 19import static org.hamcrest.MatcherAssert.assertThat;
23import static org.hamcrest.Matchers.*; 20import static org.hamcrest.Matchers.*;
24 21
25@ExtendWith(InjectionExtension.class) 22@InjectWithRefinery
26@InjectWith(ProblemInjectorProvider.class)
27class OppositeValidationTest { 23class OppositeValidationTest {
28 @Inject 24 @Inject
29 private ProblemParseHelper parseHelper; 25 private ProblemParseHelper parseHelper;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/InjectWithRefinery.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/InjectWithRefinery.java
new file mode 100644
index 00000000..c9fb453e
--- /dev/null
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/InjectWithRefinery.java
@@ -0,0 +1,22 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.tests;
7
8import org.eclipse.xtext.testing.InjectWith;
9import org.eclipse.xtext.testing.extensions.InjectionExtension;
10import org.junit.jupiter.api.extension.ExtendWith;
11
12import java.lang.annotation.ElementType;
13import java.lang.annotation.Retention;
14import java.lang.annotation.RetentionPolicy;
15import java.lang.annotation.Target;
16
17@Target(ElementType.TYPE)
18@Retention(RetentionPolicy.RUNTIME)
19@ExtendWith(InjectionExtension.class)
20@InjectWith(ProblemInjectorProvider.class)
21public @interface InjectWithRefinery {
22}
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemNavigationUtil.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/ProblemNavigationUtil.java
index d92011a9..7033dd45 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemNavigationUtil.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/ProblemNavigationUtil.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import java.util.List; 8import java.util.List;
9import java.util.stream.Stream; 9import java.util.stream.Stream;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemParseHelper.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/ProblemParseHelper.java
index f1535716..02fefa78 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemParseHelper.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/ProblemParseHelper.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import com.google.inject.Inject; 8import com.google.inject.Inject;
9import org.eclipse.emf.ecore.util.EcoreUtil; 9import org.eclipse.emf.ecore.util.EcoreUtil;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAction.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAction.java
index 4987cb89..1128b9ef 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAction.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAction.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import tools.refinery.language.model.problem.Action; 8import tools.refinery.language.model.problem.Action;
9 9
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedArgument.java
index ed749fed..c396cab3 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedArgument.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import tools.refinery.language.model.problem.*; 8import tools.refinery.language.model.problem.*;
9 9
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertion.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAssertion.java
index b2ef6e48..b94e164d 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertion.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAssertion.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import tools.refinery.language.model.problem.Assertion; 8import tools.refinery.language.model.problem.Assertion;
9 9
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAssertionArgument.java
index 50cb958d..bdc3dd49 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAssertionArgument.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import tools.refinery.language.model.problem.AssertionArgument; 8import tools.refinery.language.model.problem.AssertionArgument;
9import tools.refinery.language.model.problem.Node; 9import tools.refinery.language.model.problem.Node;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAtom.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAtom.java
index c02f447b..c88b899e 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAtom.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedAtom.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import tools.refinery.language.model.problem.Atom; 8import tools.refinery.language.model.problem.Atom;
9 9
@@ -11,7 +11,7 @@ public record WrappedAtom(Atom atom) {
11 public Atom get() { 11 public Atom get() {
12 return atom; 12 return atom;
13 } 13 }
14 14
15 public WrappedArgument arg(int i) { 15 public WrappedArgument arg(int i) {
16 return new WrappedArgument(atom.getArguments().get(i)); 16 return new WrappedArgument(atom.getArguments().get(i));
17 } 17 }
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedClassDeclaration.java
index 14ac7bfc..2f20b3bd 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedClassDeclaration.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import tools.refinery.language.model.problem.ClassDeclaration; 8import tools.refinery.language.model.problem.ClassDeclaration;
9import tools.refinery.language.model.problem.ReferenceDeclaration; 9import tools.refinery.language.model.problem.ReferenceDeclaration;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConjunction.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedConjunction.java
index b126b1ce..a01594da 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConjunction.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedConjunction.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import tools.refinery.language.model.problem.Conjunction; 8import tools.refinery.language.model.problem.Conjunction;
9 9
@@ -11,7 +11,7 @@ public record WrappedConjunction(Conjunction conjunction) {
11 public Conjunction get() { 11 public Conjunction get() {
12 return conjunction; 12 return conjunction;
13 } 13 }
14 14
15 public WrappedLiteral lit(int i) { 15 public WrappedLiteral lit(int i) {
16 return new WrappedLiteral(conjunction.getLiterals().get(i)); 16 return new WrappedLiteral(conjunction.getLiterals().get(i));
17 } 17 }
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConsequent.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedConsequent.java
index 8d6a92f8..5af3f352 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConsequent.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedConsequent.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import tools.refinery.language.model.problem.Consequent; 8import tools.refinery.language.model.problem.Consequent;
9 9
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedEnumDeclaration.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedEnumDeclaration.java
index 229a8c0a..d20382d7 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedEnumDeclaration.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedEnumDeclaration.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import tools.refinery.language.model.problem.EnumDeclaration; 8import tools.refinery.language.model.problem.EnumDeclaration;
9import tools.refinery.language.model.problem.Node; 9import tools.refinery.language.model.problem.Node;
@@ -12,7 +12,7 @@ public record WrappedEnumDeclaration(EnumDeclaration enumDeclaration) {
12 public EnumDeclaration get() { 12 public EnumDeclaration get() {
13 return enumDeclaration; 13 return enumDeclaration;
14 } 14 }
15 15
16 public Node literal(String name) { 16 public Node literal(String name) {
17 return ProblemNavigationUtil.named(enumDeclaration.getLiterals(), name); 17 return ProblemNavigationUtil.named(enumDeclaration.getLiterals(), name);
18 } 18 }
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedLiteral.java
index 160e5dd8..f62fb630 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedLiteral.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import tools.refinery.language.model.problem.Atom; 8import tools.refinery.language.model.problem.Atom;
9import tools.refinery.language.model.problem.Expr; 9import tools.refinery.language.model.problem.Expr;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedParametricDefinition.java
index d44b79ed..598ff1f4 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedParametricDefinition.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import tools.refinery.language.model.problem.Parameter; 8import tools.refinery.language.model.problem.Parameter;
9import tools.refinery.language.model.problem.ParametricDefinition; 9import tools.refinery.language.model.problem.ParametricDefinition;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedPredicateDefinition.java
index 2cf5fd89..15268d0d 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedPredicateDefinition.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import tools.refinery.language.model.problem.PredicateDefinition; 8import tools.refinery.language.model.problem.PredicateDefinition;
9 9
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedProblem.java
index b31eed6d..174f66e7 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedProblem.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import org.eclipse.emf.ecore.resource.Resource.Diagnostic; 8import org.eclipse.emf.ecore.resource.Resource.Diagnostic;
9import org.eclipse.emf.ecore.util.Diagnostician; 9import org.eclipse.emf.ecore.util.Diagnostician;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedRuleDefinition.java
index 326d8ec3..e66b1030 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/tests/utils/WrappedRuleDefinition.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.tests.utils;
7 7
8import tools.refinery.language.model.problem.RuleDefinition; 8import tools.refinery.language.model.problem.RuleDefinition;
9 9
diff --git a/subprojects/logic/src/main/java/tools/refinery/logic/term/truthvalue/TruthValue.java b/subprojects/logic/src/main/java/tools/refinery/logic/term/truthvalue/TruthValue.java
index 59bdeab3..671e1a05 100644
--- a/subprojects/logic/src/main/java/tools/refinery/logic/term/truthvalue/TruthValue.java
+++ b/subprojects/logic/src/main/java/tools/refinery/logic/term/truthvalue/TruthValue.java
@@ -50,7 +50,6 @@ public enum TruthValue implements AbstractValue<TruthValue, Boolean> {
50 return !isError(); 50 return !isError();
51 } 51 }
52 52
53
54 public boolean isComplete() { 53 public boolean isComplete() {
55 return this != UNKNOWN; 54 return this != UNKNOWN;
56 } 55 }
diff --git a/subprojects/store-dse-visualization/build.gradle.kts b/subprojects/store-dse-visualization/build.gradle.kts
index 98918863..099c9cce 100644
--- a/subprojects/store-dse-visualization/build.gradle.kts
+++ b/subprojects/store-dse-visualization/build.gradle.kts
@@ -15,5 +15,5 @@ mavenArtifact {
15 15
16dependencies { 16dependencies {
17 api(project(":refinery-store-query")) 17 api(project(":refinery-store-query"))
18 implementation(libs.slf4j.api) 18 implementation(libs.slf4j)
19} 19}
diff --git a/subprojects/store-dse/build.gradle.kts b/subprojects/store-dse/build.gradle.kts
index 3cc44fe6..f4cca199 100644
--- a/subprojects/store-dse/build.gradle.kts
+++ b/subprojects/store-dse/build.gradle.kts
@@ -16,7 +16,7 @@ mavenArtifact {
16dependencies { 16dependencies {
17 api(project(":refinery-store-query")) 17 api(project(":refinery-store-query"))
18 implementation(project(":refinery-store-dse-visualization")) 18 implementation(project(":refinery-store-dse-visualization"))
19 implementation(libs.eclipseCollections.api) 19 implementation(libs.eclipseCollections)
20 runtimeOnly(libs.eclipseCollections) 20 runtimeOnly(libs.eclipseCollections.impl)
21 testImplementation(project(":refinery-store-query-interpreter")) 21 testImplementation(project(":refinery-store-query-interpreter"))
22} 22}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/RuleBuilder.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/RuleBuilder.java
index c2e43e0d..b38774b5 100644
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/RuleBuilder.java
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/RuleBuilder.java
@@ -65,6 +65,9 @@ public class RuleBuilder extends AbstractQueryBuilder<RuleBuilder> {
65 } 65 }
66 66
67 public Rule build() { 67 public Rule build() {
68 if (action == null) {
69 throw new IllegalStateException("Rule '%s' has no action".formatted(name));
70 }
68 var precondition = dnfBuilder.build().asRelation(); 71 var precondition = dnfBuilder.build().asRelation();
69 return new Rule(name, precondition, Action.ofPrecondition(precondition, action)); 72 return new Rule(name, precondition, Action.ofPrecondition(precondition, action));
70 } 73 }
diff --git a/subprojects/store-reasoning-scope/build.gradle.kts b/subprojects/store-reasoning-scope/build.gradle.kts
index 8906c444..8c146cbf 100644
--- a/subprojects/store-reasoning-scope/build.gradle.kts
+++ b/subprojects/store-reasoning-scope/build.gradle.kts
@@ -14,8 +14,8 @@ mavenArtifact {
14 14
15dependencies { 15dependencies {
16 api(project(":refinery-store-reasoning")) 16 api(project(":refinery-store-reasoning"))
17 implementation(libs.eclipseCollections.api) 17 implementation(libs.eclipseCollections)
18 implementation(libs.ortools) 18 implementation(libs.ortools)
19 runtimeOnly(libs.eclipseCollections) 19 runtimeOnly(libs.eclipseCollections.impl)
20 testImplementation(project(":refinery-store-query-interpreter")) 20 testImplementation(project(":refinery-store-query-interpreter"))
21} 21}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java
index 386ae1d8..8994ac6e 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java
@@ -18,6 +18,7 @@ import tools.refinery.store.reasoning.refinement.PartialInterpretationRefiner;
18import tools.refinery.store.reasoning.refinement.StorageRefiner; 18import tools.refinery.store.reasoning.refinement.StorageRefiner;
19import tools.refinery.store.reasoning.representation.AnyPartialSymbol; 19import tools.refinery.store.reasoning.representation.AnyPartialSymbol;
20import tools.refinery.store.reasoning.representation.PartialSymbol; 20import tools.refinery.store.reasoning.representation.PartialSymbol;
21import tools.refinery.store.reasoning.seed.ModelSeed;
21import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator; 22import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator;
22import tools.refinery.store.representation.Symbol; 23import tools.refinery.store.representation.Symbol;
23import tools.refinery.logic.term.cardinalityinterval.CardinalityInterval; 24import tools.refinery.logic.term.cardinalityinterval.CardinalityInterval;
@@ -106,6 +107,9 @@ class ReasoningAdapterImpl implements ReasoningAdapter {
106 var refiner = createRefiner(factory, partialSymbol); 107 var refiner = createRefiner(factory, partialSymbol);
107 refiners.put(partialSymbol, refiner); 108 refiners.put(partialSymbol, refiner);
108 } 109 }
110 for (var refiner : refiners.values()) {
111 refiner.afterCreate();
112 }
109 } 113 }
110 114
111 private <A extends AbstractValue<A, C>, C> PartialInterpretationRefiner<A, C> createRefiner( 115 private <A extends AbstractValue<A, C>, C> PartialInterpretationRefiner<A, C> createRefiner(
@@ -204,6 +208,8 @@ class ReasoningAdapterImpl implements ReasoningAdapter {
204 if (nodeToDelete == currentModelSize - 1) { 208 if (nodeToDelete == currentModelSize - 1) {
205 nodeCountInterpretation.put(Tuple.of(), nodeToDelete); 209 nodeCountInterpretation.put(Tuple.of(), nodeToDelete);
206 } 210 }
211 // We mustn't reuse the ID of {@code nodeToDelete} in any circumstance, because clients may depend on stable
212 // node IDs for nodes in the initial partial model.
207 return true; 213 return true;
208 } 214 }
209 215
@@ -212,4 +218,10 @@ class ReasoningAdapterImpl implements ReasoningAdapter {
212 Integer nodeCount = nodeCountInterpretation.get(Tuple.of()); 218 Integer nodeCount = nodeCountInterpretation.get(Tuple.of());
213 return nodeCount == null ? 0 : nodeCount; 219 return nodeCount == null ? 0 : nodeCount;
214 } 220 }
221
222 void afterInitialize(ModelSeed modelSeed) {
223 for (var refiner : refiners.values()) {
224 refiner.afterInitialize(modelSeed);
225 }
226 }
215} 227}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java
index df4b6457..57cbb5d0 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java
@@ -10,6 +10,7 @@ import tools.refinery.store.dse.propagation.PropagationResult;
10import tools.refinery.store.model.Model; 10import tools.refinery.store.model.Model;
11import tools.refinery.store.model.ModelStore; 11import tools.refinery.store.model.ModelStore;
12import tools.refinery.store.query.ModelQueryAdapter; 12import tools.refinery.store.query.ModelQueryAdapter;
13import tools.refinery.store.reasoning.ReasoningAdapter;
13import tools.refinery.store.reasoning.ReasoningStoreAdapter; 14import tools.refinery.store.reasoning.ReasoningStoreAdapter;
14import tools.refinery.store.reasoning.interpretation.PartialInterpretation; 15import tools.refinery.store.reasoning.interpretation.PartialInterpretation;
15import tools.refinery.store.reasoning.literal.Concreteness; 16import tools.refinery.store.reasoning.literal.Concreteness;
@@ -107,6 +108,8 @@ class ReasoningStoreAdapterImpl implements ReasoningStoreAdapter {
107 for (var initializer : initializers) { 108 for (var initializer : initializers) {
108 initializer.initialize(model, modelSeed); 109 initializer.initialize(model, modelSeed);
109 } 110 }
111 var reasoningAdapter = ((ReasoningAdapterImpl) model.getAdapter(ReasoningAdapter.class));
112 reasoningAdapter.afterInitialize(modelSeed);
110 var propagationResult = model.tryGetAdapter(PropagationAdapter.class) 113 var propagationResult = model.tryGetAdapter(PropagationAdapter.class)
111 .map(PropagationAdapter::propagate) 114 .map(PropagationAdapter::propagate)
112 .orElse(PropagationResult.UNCHANGED); 115 .orElse(PropagationResult.UNCHANGED);
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/refinement/AnyPartialInterpretationRefiner.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/refinement/AnyPartialInterpretationRefiner.java
index 6c381511..7fd17a3a 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/refinement/AnyPartialInterpretationRefiner.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/refinement/AnyPartialInterpretationRefiner.java
@@ -5,11 +5,44 @@
5 */ 5 */
6package tools.refinery.store.reasoning.refinement; 6package tools.refinery.store.reasoning.refinement;
7 7
8import tools.refinery.logic.AbstractValue;
9import tools.refinery.store.model.Model;
8import tools.refinery.store.reasoning.ReasoningAdapter; 10import tools.refinery.store.reasoning.ReasoningAdapter;
9import tools.refinery.store.reasoning.representation.AnyPartialSymbol; 11import tools.refinery.store.reasoning.representation.AnyPartialSymbol;
12import tools.refinery.store.reasoning.seed.ModelSeed;
13import tools.refinery.store.tuple.Tuple;
10 14
11public sealed interface AnyPartialInterpretationRefiner permits PartialInterpretationRefiner { 15public sealed interface AnyPartialInterpretationRefiner permits PartialInterpretationRefiner {
12 ReasoningAdapter getAdapter(); 16 ReasoningAdapter getAdapter();
13 17
14 AnyPartialSymbol getPartialSymbol(); 18 AnyPartialSymbol getPartialSymbol();
19
20 /**
21 * Called after all {@link PartialInterpretationRefiner} instances have been created for symbols registered to
22 * the {@link tools.refinery.store.reasoning.ReasoningStoreAdapter}.
23 * <p>
24 * Override this method to access other {@link PartialInterpretationRefiner} instances associated to the
25 * {@link ReasoningAdapter} that are required for propagations executed by this
26 * {@link PartialInterpretationRefiner}.
27 */
28 default void afterCreate() {
29 }
30
31 /**
32 * Execute propagations based on the contents of the {@code modelSeed} that would by executed if the
33 * {@code modelSeed} were written to the model as a sequence of
34 * {@link PartialInterpretationRefiner#merge(Tuple, AbstractValue)} calls.
35 * <p>
36 * This method is called only after {@link PartialModelInitializer#initialize(Model, ModelSeed)} was called on all
37 * {@link PartialModelInitializer} instances registered to the
38 * {@link tools.refinery.store.reasoning.ReasoningStoreAdapter}.
39 * <p>
40 * The default implementation of this method performs no actions. Override it make the behavior consistent with
41 * your {@link PartialInterpretationRefiner#merge(Tuple, AbstractValue)} implementation.
42 *
43 * @param modelSeed The model seed which was written by a previous call of
44 * {@link PartialModelInitializer#initialize(Model, ModelSeed)}.
45 */
46 default void afterInitialize(ModelSeed modelSeed) {
47 }
15} 48}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/refinement/ConcreteSymbolRefiner.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/refinement/ConcreteSymbolRefiner.java
index d6ac0e9d..5474a4ff 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/refinement/ConcreteSymbolRefiner.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/refinement/ConcreteSymbolRefiner.java
@@ -26,14 +26,22 @@ public class ConcreteSymbolRefiner<A extends AbstractValue<A, C>, C>
26 26
27 @Override 27 @Override
28 public boolean merge(Tuple key, A value) { 28 public boolean merge(Tuple key, A value) {
29 var currentValue = interpretation.get(key); 29 var currentValue = get(key);
30 var mergedValue = currentValue.meet(value); 30 var mergedValue = currentValue.meet(value);
31 if (!Objects.equals(currentValue, mergedValue)) { 31 if (!Objects.equals(currentValue, mergedValue)) {
32 interpretation.put(key, mergedValue); 32 put(key, mergedValue);
33 } 33 }
34 return true; 34 return true;
35 } 35 }
36 36
37 protected A get(Tuple key) {
38 return interpretation.get(key);
39 }
40
41 protected A put(Tuple key, A value) {
42 return interpretation.put(key, value);
43 }
44
37 public static <A1 extends AbstractValue<A1, C1>, C1> Factory<A1, C1> of(Symbol<A1> concreteSymbol) { 45 public static <A1 extends AbstractValue<A1, C1>, C1> Factory<A1, C1> of(Symbol<A1> concreteSymbol) {
38 return (adapter, partialSymbol) -> new ConcreteSymbolRefiner<>(adapter, partialSymbol, concreteSymbol); 46 return (adapter, partialSymbol) -> new ConcreteSymbolRefiner<>(adapter, partialSymbol, concreteSymbol);
39 } 47 }
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/MapBasedSeed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/MapBasedSeed.java
index 3b78db02..03111574 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/MapBasedSeed.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/MapBasedSeed.java
@@ -64,6 +64,10 @@ record MapBasedSeed<T>(int arity, Class<T> valueType, T majorityValue, Map<Tuple
64 public boolean move() { 64 public boolean move() {
65 return switch (state) { 65 return switch (state) {
66 case INITIAL -> { 66 case INITIAL -> {
67 if (nodeCount == 0) {
68 state = State.TERMINATED;
69 yield false;
70 }
67 state = State.STARTED; 71 state = State.STARTED;
68 yield checkValue() || moveToNext(); 72 yield checkValue() || moveToNext();
69 } 73 }
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/ModelSeed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/ModelSeed.java
index 9cd4862b..31f6fa04 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/ModelSeed.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/ModelSeed.java
@@ -54,6 +54,10 @@ public class ModelSeed {
54 return getSeed(partialSymbol).getCursor(defaultValue, nodeCount); 54 return getSeed(partialSymbol).getCursor(defaultValue, nodeCount);
55 } 55 }
56 56
57 public <A extends AbstractValue<A, ?>> Cursor<Tuple, A> getCursor(PartialSymbol<A, ?> partialSymbol) {
58 return getCursor(partialSymbol, partialSymbol.defaultValue());
59 }
60
57 public static Builder builder(int nodeCount) { 61 public static Builder builder(int nodeCount) {
58 return new Builder(nodeCount); 62 return new Builder(nodeCount);
59 } 63 }
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/SeedInitializer.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/SeedInitializer.java
index 138e3a64..adc6421f 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/SeedInitializer.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/SeedInitializer.java
@@ -20,6 +20,14 @@ public class SeedInitializer<T extends AbstractValue<T, ?>> implements PartialMo
20 this.partialSymbol = partialSymbol; 20 this.partialSymbol = partialSymbol;
21 } 21 }
22 22
23 protected Symbol<T> getSymbol() {
24 return symbol;
25 }
26
27 protected PartialSymbol<T, ?> getPartialSymbol() {
28 return partialSymbol;
29 }
30
23 @Override 31 @Override
24 public void initialize(Model model, ModelSeed modelSeed) { 32 public void initialize(Model model, ModelSeed modelSeed) {
25 var interpretation = model.getInterpretation(symbol); 33 var interpretation = model.getInterpretation(symbol);
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentLinkRefiner.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentLinkRefiner.java
index adbea26b..14331dfc 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentLinkRefiner.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentLinkRefiner.java
@@ -21,14 +21,19 @@ import java.util.Set;
21class ContainmentLinkRefiner extends AbstractPartialInterpretationRefiner<TruthValue, Boolean> { 21class ContainmentLinkRefiner extends AbstractPartialInterpretationRefiner<TruthValue, Boolean> {
22 private final Factory factory; 22 private final Factory factory;
23 private final Interpretation<InferredContainment> interpretation; 23 private final Interpretation<InferredContainment> interpretation;
24 private final PartialInterpretationRefiner<TruthValue, Boolean> sourceRefiner; 24 private PartialInterpretationRefiner<TruthValue, Boolean> sourceRefiner;
25 private final PartialInterpretationRefiner<TruthValue, Boolean> targetRefiner; 25 private PartialInterpretationRefiner<TruthValue, Boolean> targetRefiner;
26 26
27 private ContainmentLinkRefiner(ReasoningAdapter adapter, PartialSymbol<TruthValue, Boolean> partialSymbol, 27 private ContainmentLinkRefiner(ReasoningAdapter adapter, PartialSymbol<TruthValue, Boolean> partialSymbol,
28 Factory factory) { 28 Factory factory) {
29 super(adapter, partialSymbol); 29 super(adapter, partialSymbol);
30 this.factory = factory; 30 this.factory = factory;
31 interpretation = adapter.getModel().getInterpretation(factory.symbol); 31 interpretation = adapter.getModel().getInterpretation(factory.symbol);
32 }
33
34 @Override
35 public void afterCreate() {
36 var adapter = getAdapter();
32 sourceRefiner = adapter.getRefiner(factory.sourceType); 37 sourceRefiner = adapter.getRefiner(factory.sourceType);
33 targetRefiner = adapter.getRefiner(factory.targetType); 38 targetRefiner = adapter.getRefiner(factory.targetType);
34 } 39 }
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainsRefiner.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainsRefiner.java
index 024774bc..4e5029bf 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainsRefiner.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainsRefiner.java
@@ -30,13 +30,18 @@ class ContainsRefiner extends AbstractPartialInterpretationRefiner<TruthValue, B
30 } 30 }
31 31
32 private final Interpretation<InferredContainment> interpretation; 32 private final Interpretation<InferredContainment> interpretation;
33 private final PartialInterpretationRefiner<TruthValue, Boolean> containerRefiner; 33 private PartialInterpretationRefiner<TruthValue, Boolean> containerRefiner;
34 private final PartialInterpretationRefiner<TruthValue, Boolean> containedRefiner; 34 private PartialInterpretationRefiner<TruthValue, Boolean> containedRefiner;
35 35
36 private ContainsRefiner(ReasoningAdapter adapter, PartialSymbol<TruthValue, Boolean> partialSymbol, 36 private ContainsRefiner(ReasoningAdapter adapter, PartialSymbol<TruthValue, Boolean> partialSymbol,
37 Symbol<InferredContainment> containsStorage) { 37 Symbol<InferredContainment> containsStorage) {
38 super(adapter, partialSymbol); 38 super(adapter, partialSymbol);
39 interpretation = adapter.getModel().getInterpretation(containsStorage); 39 interpretation = adapter.getModel().getInterpretation(containsStorage);
40 }
41
42 @Override
43 public void afterCreate() {
44 var adapter = getAdapter();
40 containerRefiner = adapter.getRefiner(ContainmentHierarchyTranslator.CONTAINER_SYMBOL); 45 containerRefiner = adapter.getRefiner(ContainmentHierarchyTranslator.CONTAINER_SYMBOL);
41 containedRefiner = adapter.getRefiner(ContainmentHierarchyTranslator.CONTAINED_SYMBOL); 46 containedRefiner = adapter.getRefiner(ContainmentHierarchyTranslator.CONTAINED_SYMBOL);
42 } 47 }
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceInitializer.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceInitializer.java
deleted file mode 100644
index 7cb16a28..00000000
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceInitializer.java
+++ /dev/null
@@ -1,52 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.crossreference;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.reasoning.ReasoningAdapter;
10import tools.refinery.store.reasoning.refinement.PartialModelInitializer;
11import tools.refinery.store.reasoning.representation.PartialRelation;
12import tools.refinery.store.reasoning.seed.ModelSeed;
13import tools.refinery.store.representation.Symbol;
14import tools.refinery.logic.term.truthvalue.TruthValue;
15import tools.refinery.store.tuple.Tuple;
16
17class DirectedCrossReferenceInitializer implements PartialModelInitializer {
18 private final PartialRelation linkType;
19 private final PartialRelation sourceType;
20 private final PartialRelation targetType;
21 private final Symbol<TruthValue> symbol;
22
23 public DirectedCrossReferenceInitializer(PartialRelation linkType, PartialRelation sourceType,
24 PartialRelation targetType, Symbol<TruthValue> symbol) {
25 this.linkType = linkType;
26 this.sourceType = sourceType;
27 this.targetType = targetType;
28 this.symbol = symbol;
29 }
30
31 @Override
32 public void initialize(Model model, ModelSeed modelSeed) {
33 var reasoningAdapter = model.getAdapter(ReasoningAdapter.class);
34 var sourceRefiner = reasoningAdapter.getRefiner(sourceType);
35 var targetRefiner = reasoningAdapter.getRefiner(targetType);
36 var interpretation = model.getInterpretation(symbol);
37 var cursor = modelSeed.getCursor(linkType, symbol.defaultValue());
38 while (cursor.move()) {
39 var key = cursor.getKey();
40 var value = cursor.getValue();
41 interpretation.put(key, value);
42 if (value.must()) {
43 boolean merged = sourceRefiner.merge(Tuple.of(key.get(0)), TruthValue.TRUE) &&
44 targetRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE);
45 if (!merged) {
46 throw new IllegalArgumentException("Failed to merge end types of reference %s for key %s"
47 .formatted(linkType, key));
48 }
49 }
50 }
51 }
52}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceRefiner.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceRefiner.java
index 75dd5dad..4471b193 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceRefiner.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceRefiner.java
@@ -5,27 +5,35 @@
5 */ 5 */
6package tools.refinery.store.reasoning.translator.crossreference; 6package tools.refinery.store.reasoning.translator.crossreference;
7 7
8import tools.refinery.logic.term.truthvalue.TruthValue;
8import tools.refinery.store.reasoning.ReasoningAdapter; 9import tools.refinery.store.reasoning.ReasoningAdapter;
9import tools.refinery.store.reasoning.refinement.ConcreteSymbolRefiner; 10import tools.refinery.store.reasoning.refinement.ConcreteSymbolRefiner;
10import tools.refinery.store.reasoning.refinement.PartialInterpretationRefiner; 11import tools.refinery.store.reasoning.refinement.PartialInterpretationRefiner;
11import tools.refinery.store.reasoning.representation.PartialRelation; 12import tools.refinery.store.reasoning.representation.PartialRelation;
12import tools.refinery.store.reasoning.representation.PartialSymbol; 13import tools.refinery.store.reasoning.representation.PartialSymbol;
14import tools.refinery.store.reasoning.seed.ModelSeed;
13import tools.refinery.store.representation.Symbol; 15import tools.refinery.store.representation.Symbol;
14import tools.refinery.logic.term.truthvalue.TruthValue;
15import tools.refinery.store.tuple.Tuple; 16import tools.refinery.store.tuple.Tuple;
16 17
17class DirectedCrossReferenceRefiner extends ConcreteSymbolRefiner<TruthValue, Boolean> { 18class DirectedCrossReferenceRefiner extends ConcreteSymbolRefiner<TruthValue, Boolean> {
19 private final PartialRelation sourceType;
18 private final PartialRelation targetType; 20 private final PartialRelation targetType;
19 private final PartialInterpretationRefiner<TruthValue, Boolean> sourceRefiner; 21 private PartialInterpretationRefiner<TruthValue, Boolean> sourceRefiner;
20 private PartialInterpretationRefiner<TruthValue, Boolean> targetRefiner; 22 private PartialInterpretationRefiner<TruthValue, Boolean> targetRefiner;
21 23
22 public DirectedCrossReferenceRefiner(ReasoningAdapter adapter, PartialSymbol<TruthValue, Boolean> partialSymbol, 24 protected DirectedCrossReferenceRefiner(ReasoningAdapter adapter, PartialSymbol<TruthValue, Boolean> partialSymbol,
23 Symbol<TruthValue> concreteSymbol, PartialRelation sourceType, 25 Symbol<TruthValue> concreteSymbol, PartialRelation sourceType,
24 PartialRelation targetType) { 26 PartialRelation targetType) {
25 super(adapter, partialSymbol, concreteSymbol); 27 super(adapter, partialSymbol, concreteSymbol);
28 this.sourceType = sourceType;
26 this.targetType = targetType; 29 this.targetType = targetType;
27 // Source is always a class, so we can rely on the fact that it is always constructed before this refiner. 30 }
31
32 @Override
33 public void afterCreate() {
34 var adapter = getAdapter();
28 sourceRefiner = adapter.getRefiner(sourceType); 35 sourceRefiner = adapter.getRefiner(sourceType);
36 targetRefiner = adapter.getRefiner(targetType);
29 } 37 }
30 38
31 @Override 39 @Override
@@ -34,16 +42,30 @@ class DirectedCrossReferenceRefiner extends ConcreteSymbolRefiner<TruthValue, Bo
34 return false; 42 return false;
35 } 43 }
36 if (value.must()) { 44 if (value.must()) {
37 if (targetRefiner == null) {
38 // Access the target refinery lazily, since it may be constructed after this refiner.
39 targetRefiner = getAdapter().getRefiner(targetType);
40 }
41 return sourceRefiner.merge(Tuple.of(key.get(0)), TruthValue.TRUE) && 45 return sourceRefiner.merge(Tuple.of(key.get(0)), TruthValue.TRUE) &&
42 targetRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE); 46 targetRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE);
43 } 47 }
44 return true; 48 return true;
45 } 49 }
46 50
51 @Override
52 public void afterInitialize(ModelSeed modelSeed) {
53 var linkType = getPartialSymbol();
54 var cursor = modelSeed.getCursor(linkType);
55 while (cursor.move()) {
56 var value = cursor.getValue();
57 if (value.must()) {
58 var key = cursor.getKey();
59 boolean merged = sourceRefiner.merge(Tuple.of(key.get(0)), TruthValue.TRUE) &&
60 targetRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE);
61 if (!merged) {
62 throw new IllegalArgumentException("Failed to merge end types of reference %s for key %s"
63 .formatted(linkType, key));
64 }
65 }
66 }
67 }
68
47 public static Factory<TruthValue, Boolean> of(Symbol<TruthValue> concreteSymbol, PartialRelation sourceType, 69 public static Factory<TruthValue, Boolean> of(Symbol<TruthValue> concreteSymbol, PartialRelation sourceType,
48 PartialRelation targetType) { 70 PartialRelation targetType) {
49 return (adapter, partialSymbol) -> new DirectedCrossReferenceRefiner(adapter, partialSymbol, concreteSymbol, 71 return (adapter, partialSymbol) -> new DirectedCrossReferenceRefiner(adapter, partialSymbol, concreteSymbol,
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceTranslator.java
index d4c2afd2..c98971d9 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceTranslator.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceTranslator.java
@@ -47,7 +47,7 @@ public class DirectedCrossReferenceTranslator implements ModelStoreConfiguration
47 var targetType = info.targetType(); 47 var targetType = info.targetType();
48 var defaultValue = info.defaultValue(); 48 var defaultValue = info.defaultValue();
49 if (defaultValue.must()) { 49 if (defaultValue.must()) {
50 throw new TranslationException(linkType, "Unsupported default value %s for directed cross references %s" 50 throw new TranslationException(linkType, "Unsupported default value %s for directed cross reference %s"
51 .formatted(defaultValue, linkType)); 51 .formatted(defaultValue, linkType));
52 } 52 }
53 var translator = PartialRelationTranslator.of(linkType); 53 var translator = PartialRelationTranslator.of(linkType);
@@ -58,7 +58,6 @@ public class DirectedCrossReferenceTranslator implements ModelStoreConfiguration
58 configureWithDefaultFalse(storeBuilder); 58 configureWithDefaultFalse(storeBuilder);
59 } 59 }
60 translator.refiner(DirectedCrossReferenceRefiner.of(symbol, sourceType, targetType)); 60 translator.refiner(DirectedCrossReferenceRefiner.of(symbol, sourceType, targetType));
61 translator.initializer(new DirectedCrossReferenceInitializer(linkType, sourceType, targetType, symbol));
62 if (info.partial()) { 61 if (info.partial()) {
63 translator.roundingMode(RoundingMode.NONE); 62 translator.roundingMode(RoundingMode.NONE);
64 } else { 63 } else {
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceInitializer.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceInitializer.java
index 84dcfdc5..d0784c27 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceInitializer.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceInitializer.java
@@ -6,48 +6,34 @@
6package tools.refinery.store.reasoning.translator.crossreference; 6package tools.refinery.store.reasoning.translator.crossreference;
7 7
8import org.jetbrains.annotations.NotNull; 8import org.jetbrains.annotations.NotNull;
9import tools.refinery.logic.term.truthvalue.TruthValue;
9import tools.refinery.store.model.Model; 10import tools.refinery.store.model.Model;
10import tools.refinery.store.reasoning.ReasoningAdapter;
11import tools.refinery.store.reasoning.refinement.PartialModelInitializer; 11import tools.refinery.store.reasoning.refinement.PartialModelInitializer;
12import tools.refinery.store.reasoning.representation.PartialRelation; 12import tools.refinery.store.reasoning.representation.PartialRelation;
13import tools.refinery.store.reasoning.seed.ModelSeed; 13import tools.refinery.store.reasoning.seed.ModelSeed;
14import tools.refinery.store.reasoning.translator.TranslationException; 14import tools.refinery.store.reasoning.translator.TranslationException;
15import tools.refinery.store.representation.Symbol; 15import tools.refinery.store.representation.Symbol;
16import tools.refinery.logic.term.truthvalue.TruthValue;
17import tools.refinery.store.tuple.Tuple; 16import tools.refinery.store.tuple.Tuple;
18 17
19import java.util.LinkedHashMap; 18import java.util.LinkedHashMap;
20 19
21class UndirectedCrossReferenceInitializer implements PartialModelInitializer { 20class UndirectedCrossReferenceInitializer implements PartialModelInitializer {
22 private final PartialRelation linkType; 21 private final PartialRelation linkType;
23 private final PartialRelation sourceType;
24 private final Symbol<TruthValue> symbol; 22 private final Symbol<TruthValue> symbol;
25 23
26 UndirectedCrossReferenceInitializer(PartialRelation linkType, PartialRelation sourceType, 24 UndirectedCrossReferenceInitializer(PartialRelation linkType, Symbol<TruthValue> symbol) {
27 Symbol<TruthValue> symbol) {
28 this.linkType = linkType; 25 this.linkType = linkType;
29 this.sourceType = sourceType;
30 this.symbol = symbol; 26 this.symbol = symbol;
31 } 27 }
32 28
33 @Override 29 @Override
34 public void initialize(Model model, ModelSeed modelSeed) { 30 public void initialize(Model model, ModelSeed modelSeed) {
35 var reasoningAdapter = model.getAdapter(ReasoningAdapter.class);
36 var mergedMap = getMergedMap(modelSeed); 31 var mergedMap = getMergedMap(modelSeed);
37 var sourceRefiner = reasoningAdapter.getRefiner(sourceType);
38 var interpretation = model.getInterpretation(symbol); 32 var interpretation = model.getInterpretation(symbol);
39 for (var entry : mergedMap.entrySet()) { 33 for (var entry : mergedMap.entrySet()) {
40 var key = entry.getKey(); 34 var key = entry.getKey();
41 var value = entry.getValue(); 35 var value = entry.getValue();
42 interpretation.put(key, value); 36 interpretation.put(key, value);
43 if (value.must()) {
44 boolean merged = sourceRefiner.merge(Tuple.of(key.get(0)), TruthValue.TRUE) &&
45 sourceRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE);
46 if (!merged) {
47 throw new IllegalArgumentException("Failed to merge end types of reference %s for key %s"
48 .formatted(linkType, key));
49 }
50 }
51 } 37 }
52 } 38 }
53 39
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceRefiner.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceRefiner.java
index 54aca80f..116ac7ad 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceRefiner.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceRefiner.java
@@ -5,30 +5,48 @@
5 */ 5 */
6package tools.refinery.store.reasoning.translator.crossreference; 6package tools.refinery.store.reasoning.translator.crossreference;
7 7
8import tools.refinery.logic.term.truthvalue.TruthValue;
8import tools.refinery.store.reasoning.ReasoningAdapter; 9import tools.refinery.store.reasoning.ReasoningAdapter;
9import tools.refinery.store.reasoning.refinement.ConcreteSymbolRefiner; 10import tools.refinery.store.reasoning.refinement.ConcreteSymbolRefiner;
10import tools.refinery.store.reasoning.refinement.PartialInterpretationRefiner; 11import tools.refinery.store.reasoning.refinement.PartialInterpretationRefiner;
11import tools.refinery.store.reasoning.representation.PartialRelation; 12import tools.refinery.store.reasoning.representation.PartialRelation;
12import tools.refinery.store.reasoning.representation.PartialSymbol; 13import tools.refinery.store.reasoning.representation.PartialSymbol;
14import tools.refinery.store.reasoning.seed.ModelSeed;
13import tools.refinery.store.representation.Symbol; 15import tools.refinery.store.representation.Symbol;
14import tools.refinery.logic.term.truthvalue.TruthValue;
15import tools.refinery.store.tuple.Tuple; 16import tools.refinery.store.tuple.Tuple;
16 17
18import java.util.Objects;
19
17class UndirectedCrossReferenceRefiner extends ConcreteSymbolRefiner<TruthValue, Boolean> { 20class UndirectedCrossReferenceRefiner extends ConcreteSymbolRefiner<TruthValue, Boolean> {
18 private final PartialInterpretationRefiner<TruthValue, Boolean> sourceRefiner; 21 private final PartialRelation sourceType;
22 private PartialInterpretationRefiner<TruthValue, Boolean> sourceRefiner;
19 23
20 public UndirectedCrossReferenceRefiner(ReasoningAdapter adapter, PartialSymbol<TruthValue, Boolean> partialSymbol, 24 protected UndirectedCrossReferenceRefiner(ReasoningAdapter adapter,
21 Symbol<TruthValue> concreteSymbol, PartialRelation sourceType) { 25 PartialSymbol<TruthValue, Boolean> partialSymbol,
26 Symbol<TruthValue> concreteSymbol, PartialRelation sourceType) {
22 super(adapter, partialSymbol, concreteSymbol); 27 super(adapter, partialSymbol, concreteSymbol);
23 sourceRefiner = adapter.getRefiner(sourceType); 28 this.sourceType = sourceType;
29 }
30
31 @Override
32 public void afterCreate() {
33 sourceRefiner = getAdapter().getRefiner(sourceType);
24 } 34 }
25 35
26 @Override 36 @Override
27 public boolean merge(Tuple key, TruthValue value) { 37 public boolean merge(Tuple key, TruthValue value) {
28 int source = key.get(0); 38 int source = key.get(0);
29 int target = key.get(1); 39 int target = key.get(1);
30 if (!super.merge(key, value) || !super.merge(Tuple.of(target, source), value)) { 40 var currentValue = get(key);
31 return false; 41 var mergedValue = currentValue.meet(value);
42 if (!Objects.equals(currentValue, mergedValue)) {
43 var oldValue = put(key, mergedValue);
44 if (source != target) {
45 var inverseOldValue = put(Tuple.of(target, source), mergedValue);
46 if (!Objects.equals(oldValue, inverseOldValue)) {
47 return false;
48 }
49 }
32 } 50 }
33 if (value.must()) { 51 if (value.must()) {
34 return sourceRefiner.merge(Tuple.of(source), TruthValue.TRUE) && 52 return sourceRefiner.merge(Tuple.of(source), TruthValue.TRUE) &&
@@ -37,6 +55,24 @@ class UndirectedCrossReferenceRefiner extends ConcreteSymbolRefiner<TruthValue,
37 return true; 55 return true;
38 } 56 }
39 57
58 @Override
59 public void afterInitialize(ModelSeed modelSeed) {
60 var linkType = getPartialSymbol();
61 var cursor = modelSeed.getCursor(linkType);
62 while (cursor.move()) {
63 var value = cursor.getValue();
64 if (value.must()) {
65 var key = cursor.getKey();
66 boolean merged = sourceRefiner.merge(Tuple.of(key.get(0)), TruthValue.TRUE) &&
67 sourceRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE);
68 if (!merged) {
69 throw new IllegalArgumentException("Failed to merge end types of reference %s for key %s"
70 .formatted(linkType, key));
71 }
72 }
73 }
74 }
75
40 public static Factory<TruthValue, Boolean> of(Symbol<TruthValue> concreteSymbol, PartialRelation sourceType) { 76 public static Factory<TruthValue, Boolean> of(Symbol<TruthValue> concreteSymbol, PartialRelation sourceType) {
41 return (adapter, partialSymbol) -> new UndirectedCrossReferenceRefiner(adapter, partialSymbol, concreteSymbol, 77 return (adapter, partialSymbol) -> new UndirectedCrossReferenceRefiner(adapter, partialSymbol, concreteSymbol,
42 sourceType); 78 sourceType);
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceTranslator.java
index 494211fe..0de1deac 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceTranslator.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceTranslator.java
@@ -44,7 +44,7 @@ public class UndirectedCrossReferenceTranslator implements ModelStoreConfigurati
44 var type = info.type(); 44 var type = info.type();
45 var defaultValue = info.defaultValue(); 45 var defaultValue = info.defaultValue();
46 if (defaultValue.must()) { 46 if (defaultValue.must()) {
47 throw new TranslationException(linkType, "Unsupported default value %s for directed cross references %s" 47 throw new TranslationException(linkType, "Unsupported default value %s for undirected cross reference %s"
48 .formatted(defaultValue, linkType)); 48 .formatted(defaultValue, linkType));
49 } 49 }
50 var translator = PartialRelationTranslator.of(linkType); 50 var translator = PartialRelationTranslator.of(linkType);
@@ -54,8 +54,8 @@ public class UndirectedCrossReferenceTranslator implements ModelStoreConfigurati
54 } else { 54 } else {
55 configureWithDefaultFalse(storeBuilder); 55 configureWithDefaultFalse(storeBuilder);
56 } 56 }
57 translator.initializer(new UndirectedCrossReferenceInitializer(linkType, symbol));
57 translator.refiner(UndirectedCrossReferenceRefiner.of(symbol, type)); 58 translator.refiner(UndirectedCrossReferenceRefiner.of(symbol, type));
58 translator.initializer(new UndirectedCrossReferenceInitializer(linkType, type, symbol));
59 if (info.partial()) { 59 if (info.partial()) {
60 translator.roundingMode(RoundingMode.NONE); 60 translator.roundingMode(RoundingMode.NONE);
61 } else { 61 } else {
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/CleanupPropagator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/CleanupPropagator.java
index f14b4783..6feccae3 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/CleanupPropagator.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/CleanupPropagator.java
@@ -11,6 +11,7 @@ import tools.refinery.logic.term.uppercardinality.UpperCardinalities;
11import tools.refinery.logic.term.uppercardinality.UpperCardinality; 11import tools.refinery.logic.term.uppercardinality.UpperCardinality;
12import tools.refinery.logic.term.uppercardinality.UpperCardinalityTerms; 12import tools.refinery.logic.term.uppercardinality.UpperCardinalityTerms;
13import tools.refinery.store.dse.propagation.BoundPropagator; 13import tools.refinery.store.dse.propagation.BoundPropagator;
14import tools.refinery.store.dse.propagation.PropagationRejectedResult;
14import tools.refinery.store.dse.propagation.PropagationResult; 15import tools.refinery.store.dse.propagation.PropagationResult;
15import tools.refinery.store.dse.propagation.Propagator; 16import tools.refinery.store.dse.propagation.Propagator;
16import tools.refinery.store.model.Model; 17import tools.refinery.store.model.Model;
@@ -48,7 +49,7 @@ public class CleanupPropagator implements Propagator {
48 return new BoundCleanupPropagator(model); 49 return new BoundCleanupPropagator(model);
49 } 50 }
50 51
51 private static class BoundCleanupPropagator implements BoundPropagator { 52 private class BoundCleanupPropagator implements BoundPropagator {
52 private final Model model; 53 private final Model model;
53 private final ModelQueryAdapter queryEngine; 54 private final ModelQueryAdapter queryEngine;
54 private final ResultSet<Boolean> resultSet; 55 private final ResultSet<Boolean> resultSet;
@@ -70,7 +71,11 @@ public class CleanupPropagator implements Propagator {
70 var cursor = resultSet.getAll(); 71 var cursor = resultSet.getAll();
71 while (cursor.move()) { 72 while (cursor.move()) {
72 propagated = true; 73 propagated = true;
73 reasoningAdapter.cleanup(cursor.getKey().get(0)); 74 var nodeToDelete = cursor.getKey().get(0);
75 if (!reasoningAdapter.cleanup(nodeToDelete)) {
76 return new PropagationRejectedResult(CleanupPropagator.this,
77 "Failed to remove node: " + nodeToDelete, true);
78 }
74 } 79 }
75 return propagated ? PropagationResult.PROPAGATED : PropagationResult.UNCHANGED; 80 return propagated ? PropagationResult.PROPAGATED : PropagationResult.UNCHANGED;
76 } 81 }
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiObjectTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiObjectTranslator.java
index 05d96689..7b3be76d 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiObjectTranslator.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiObjectTranslator.java
@@ -41,6 +41,16 @@ public class MultiObjectTranslator implements ModelStoreConfiguration {
41 public static final PartialFunction<CardinalityInterval, Integer> COUNT_SYMBOL = new PartialFunction<>("COUNT", 1, 41 public static final PartialFunction<CardinalityInterval, Integer> COUNT_SYMBOL = new PartialFunction<>("COUNT", 1,
42 CardinalityDomain.INSTANCE); 42 CardinalityDomain.INSTANCE);
43 43
44 private final boolean keepNonExistingObjects;
45
46 public MultiObjectTranslator(boolean keepNonExistingObjects) {
47 this.keepNonExistingObjects = keepNonExistingObjects;
48 }
49
50 public MultiObjectTranslator() {
51 this(true);
52 }
53
44 @Override 54 @Override
45 public void apply(ModelStoreBuilder storeBuilder) { 55 public void apply(ModelStoreBuilder storeBuilder) {
46 storeBuilder.symbol(COUNT_STORAGE); 56 storeBuilder.symbol(COUNT_STORAGE);
@@ -90,7 +100,9 @@ public class MultiObjectTranslator implements ModelStoreConfiguration {
90 reasoningBuilder.initializer(new MultiObjectInitializer(COUNT_STORAGE)); 100 reasoningBuilder.initializer(new MultiObjectInitializer(COUNT_STORAGE));
91 reasoningBuilder.storageRefiner(COUNT_STORAGE, MultiObjectStorageRefiner::new); 101 reasoningBuilder.storageRefiner(COUNT_STORAGE, MultiObjectStorageRefiner::new);
92 102
93 storeBuilder.tryGetAdapter(PropagationBuilder.class) 103 if (!keepNonExistingObjects) {
94 .ifPresent(propagationBuilder -> propagationBuilder.propagator(new CleanupPropagator())); 104 storeBuilder.tryGetAdapter(PropagationBuilder.class)
105 .ifPresent(propagationBuilder -> propagationBuilder.propagator(new CleanupPropagator()));
106 }
95 } 107 }
96} 108}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/BasePredicateTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/BasePredicateTranslator.java
new file mode 100644
index 00000000..fb4521dd
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/BasePredicateTranslator.java
@@ -0,0 +1,143 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.predicate;
7
8import tools.refinery.logic.dnf.AbstractQueryBuilder;
9import tools.refinery.logic.dnf.Query;
10import tools.refinery.logic.literal.Literal;
11import tools.refinery.logic.term.NodeVariable;
12import tools.refinery.logic.term.truthvalue.TruthValue;
13import tools.refinery.store.dse.propagation.PropagationBuilder;
14import tools.refinery.store.dse.transition.Rule;
15import tools.refinery.store.model.ModelStoreBuilder;
16import tools.refinery.store.model.ModelStoreConfiguration;
17import tools.refinery.store.query.view.ForbiddenView;
18import tools.refinery.store.reasoning.lifting.DnfLifter;
19import tools.refinery.store.reasoning.literal.Concreteness;
20import tools.refinery.store.reasoning.literal.Modality;
21import tools.refinery.store.reasoning.representation.PartialRelation;
22import tools.refinery.store.reasoning.translator.PartialRelationTranslator;
23import tools.refinery.store.reasoning.translator.RoundingMode;
24import tools.refinery.store.reasoning.translator.TranslationException;
25import tools.refinery.store.representation.Symbol;
26
27import java.util.ArrayList;
28import java.util.List;
29
30import static tools.refinery.logic.literal.Literals.not;
31import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add;
32import static tools.refinery.store.reasoning.actions.PartialActionLiterals.remove;
33import static tools.refinery.store.reasoning.literal.PartialLiterals.*;
34import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.MULTI_VIEW;
35
36public class BasePredicateTranslator implements ModelStoreConfiguration {
37 private final PartialRelation predicate;
38 private final List<PartialRelation> parameterTypes;
39 private final TruthValue defaultValue;
40 private final boolean partial;
41 private final Symbol<TruthValue> symbol;
42
43 public BasePredicateTranslator(PartialRelation predicate, List<PartialRelation> parameterTypes,
44 TruthValue defaultValue, boolean partial) {
45 this.predicate = predicate;
46 this.parameterTypes = parameterTypes;
47 this.defaultValue = defaultValue;
48 this.partial = partial;
49 symbol = Symbol.of(predicate.name(), predicate.arity(), TruthValue.class, defaultValue);
50 }
51
52 @Override
53 public void apply(ModelStoreBuilder storeBuilder) {
54 int arity = predicate.arity();
55 if (arity != parameterTypes.size()) {
56 throw new TranslationException(predicate,
57 "Expected %d parameter type for base predicate %s, got %d instead"
58 .formatted(arity, predicate, parameterTypes.size()));
59 }
60 if (defaultValue.must()) {
61 throw new TranslationException(predicate, "Unsupported default value %s for base predicate %s"
62 .formatted(defaultValue, predicate));
63 }
64 var translator = PartialRelationTranslator.of(predicate);
65 translator.symbol(symbol);
66 if (defaultValue.may()) {
67 configureWithDefaultUnknown(translator);
68 } else {
69 configureWithDefaultFalse(storeBuilder);
70 }
71 translator.refiner(PredicateRefiner.of(symbol, parameterTypes));
72 if (partial) {
73 translator.roundingMode(RoundingMode.NONE);
74 } else {
75 translator.decision(Rule.of(predicate.name(), builder -> {
76 var parameters = createParameters(builder);
77 var literals = new ArrayList<Literal>(arity + 2);
78 literals.add(may(predicate.call(parameters)));
79 literals.add(not(candidateMust(predicate.call(parameters))));
80 for (int i = 0; i < arity; i++) {
81 literals.add(not(MULTI_VIEW.call(parameters[i])));
82 }
83 builder.clause(literals);
84 builder.action(add(predicate, parameters));
85 }));
86 }
87 storeBuilder.with(translator);
88 }
89
90 private NodeVariable[] createParameters(AbstractQueryBuilder<?> builder) {
91 int arity = predicate.arity();
92 var parameters = new NodeVariable[arity];
93 for (int i = 0; i < arity; i++) {
94 parameters[i] = builder.parameter("p" + (i + 1));
95 }
96 return parameters;
97 }
98
99 private void configureWithDefaultUnknown(PartialRelationTranslator translator) {
100 var name = predicate.name();
101 var mayName = DnfLifter.decorateName(name, Modality.MAY, Concreteness.PARTIAL);
102 int arity = predicate.arity();
103 var forbiddenView = new ForbiddenView(symbol);
104 translator.may(Query.of(mayName, builder -> {
105 var parameters = createParameters(builder);
106 var literals = new ArrayList<Literal>(arity + 1);
107 for (int i = 0; i < arity; i++) {
108 literals.add(may(parameterTypes.get(i).call(parameters[i])));
109 }
110 literals.add(not(forbiddenView.call(parameters)));
111 builder.clause(literals);
112 }));
113 if (partial) {
114 var candidateMayName = DnfLifter.decorateName(name, Modality.MAY, Concreteness.CANDIDATE);
115 translator.candidateMay(Query.of(candidateMayName, builder -> {
116 var parameters = createParameters(builder);
117 var literals = new ArrayList<Literal>(arity + 1);
118 for (int i = 0; i < arity; i++) {
119 literals.add(candidateMay(parameterTypes.get(i).call(parameters[i])));
120 }
121 literals.add(not(forbiddenView.call(parameters)));
122 builder.clause(literals);
123 }));
124 }
125 }
126
127 private void configureWithDefaultFalse(ModelStoreBuilder storeBuilder) {
128 var name = predicate.name();
129 // Fail if there is no {@link PropagationBuilder}, since it is required for soundness.
130 var propagationBuilder = storeBuilder.getAdapter(PropagationBuilder.class);
131 propagationBuilder.rule(Rule.of(name + "#invalid", builder -> {
132 var parameters = createParameters(builder);
133 int arity = parameters.length;
134 for (int i = 0; i < arity; i++) {
135 builder.clause(
136 may(predicate.call(parameters)),
137 not(may(parameterTypes.get(i).call(parameters[i])))
138 );
139 }
140 builder.action(remove(predicate, parameters));
141 }));
142 }
143}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/PredicateRefiner.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/PredicateRefiner.java
new file mode 100644
index 00000000..0fccced2
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/PredicateRefiner.java
@@ -0,0 +1,94 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.predicate;
7
8import org.jetbrains.annotations.Nullable;
9import tools.refinery.logic.term.truthvalue.TruthValue;
10import tools.refinery.store.reasoning.ReasoningAdapter;
11import tools.refinery.store.reasoning.refinement.ConcreteSymbolRefiner;
12import tools.refinery.store.reasoning.refinement.PartialInterpretationRefiner;
13import tools.refinery.store.reasoning.representation.PartialRelation;
14import tools.refinery.store.reasoning.representation.PartialSymbol;
15import tools.refinery.store.reasoning.seed.ModelSeed;
16import tools.refinery.store.representation.Symbol;
17import tools.refinery.store.tuple.Tuple;
18
19import java.util.List;
20import java.util.Objects;
21
22class PredicateRefiner extends ConcreteSymbolRefiner<TruthValue, Boolean> {
23 private final List<PartialRelation> parameterTypes;
24 private @Nullable PartialInterpretationRefiner<TruthValue, Boolean>[] parameterTypeRefiners;
25
26 protected PredicateRefiner(ReasoningAdapter adapter, PartialSymbol<TruthValue, Boolean> partialSymbol,
27 Symbol<TruthValue> concreteSymbol, List<PartialRelation> parameterTypes) {
28 super(adapter, partialSymbol, concreteSymbol);
29 this.parameterTypes = parameterTypes;
30 }
31
32 @Override
33 public void afterCreate() {
34 int arity = parameterTypes.size();
35 // Generic array creation.
36 @SuppressWarnings("unchecked")
37 PartialInterpretationRefiner<TruthValue, Boolean>[] array = new PartialInterpretationRefiner[arity];
38 parameterTypeRefiners = array;
39 var adapter = getAdapter();
40 for (int i = 0; i < arity; i++) {
41 var parameterType = parameterTypes.get(i);
42 if (parameterType != null) {
43 array[i] = adapter.getRefiner(parameterType);
44 }
45 }
46 }
47
48 @Override
49 public boolean merge(Tuple key, TruthValue value) {
50 var currentValue = get(key);
51 var mergedValue = currentValue.meet(value);
52 if (!Objects.equals(currentValue, mergedValue)) {
53 put(key, mergedValue);
54 }
55 // Avoid cyclic propagation between parameter types by avoiding propagation after reaching a fixed point.
56 if (mergedValue.must() && !currentValue.must()) {
57 return refineParameters(key);
58 }
59 return true;
60 }
61
62 @Override
63 public void afterInitialize(ModelSeed modelSeed) {
64 var predicate = getPartialSymbol();
65 var cursor = modelSeed.getCursor(predicate);
66 while (cursor.move()) {
67 var value = cursor.getValue();
68 if (value.must()) {
69 var key = cursor.getKey();
70 if (!refineParameters(key)) {
71 throw new IllegalArgumentException("Failed to merge parameter types of predicate %s for key %s"
72 .formatted(predicate, key));
73 }
74 }
75 }
76 }
77
78 private boolean refineParameters(Tuple key) {
79 int arity = parameterTypeRefiners.length;
80 for (int i = 0; i < arity; i++) {
81 var refiner = parameterTypeRefiners[i];
82 if (refiner != null && !refiner.merge(Tuple.of(key.get(i)), TruthValue.TRUE)) {
83 return false;
84 }
85 }
86 return true;
87 }
88
89 public static Factory<TruthValue, Boolean> of(Symbol<TruthValue> concreteSymbol,
90 List<PartialRelation> parameterTypes) {
91 return (adapter, partialSymbol) -> new PredicateRefiner(adapter, partialSymbol, concreteSymbol,
92 parameterTypes);
93 }
94}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/PredicateTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/PredicateTranslator.java
index 010ce977..8dd9cff6 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/PredicateTranslator.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/PredicateTranslator.java
@@ -21,6 +21,9 @@ import tools.refinery.store.reasoning.translator.PartialRelationTranslator;
21import tools.refinery.store.reasoning.translator.TranslationException; 21import tools.refinery.store.reasoning.translator.TranslationException;
22import tools.refinery.store.representation.Symbol; 22import tools.refinery.store.representation.Symbol;
23 23
24import java.util.List;
25import java.util.Objects;
26
24import static tools.refinery.logic.literal.Literals.not; 27import static tools.refinery.logic.literal.Literals.not;
25import static tools.refinery.store.reasoning.literal.PartialLiterals.may; 28import static tools.refinery.store.reasoning.literal.PartialLiterals.may;
26import static tools.refinery.store.reasoning.literal.PartialLiterals.must; 29import static tools.refinery.store.reasoning.literal.PartialLiterals.must;
@@ -30,9 +33,11 @@ public class PredicateTranslator implements ModelStoreConfiguration {
30 private final RelationalQuery query; 33 private final RelationalQuery query;
31 private final boolean mutable; 34 private final boolean mutable;
32 private final TruthValue defaultValue; 35 private final TruthValue defaultValue;
36 private final List<PartialRelation> parameterTypes;
33 37
34 public PredicateTranslator(PartialRelation relation, RelationalQuery query, boolean mutable, 38 public PredicateTranslator(PartialRelation relation, RelationalQuery query, List<PartialRelation> parameterTypes,
35 TruthValue defaultValue) { 39 boolean mutable, TruthValue defaultValue) {
40 this.parameterTypes = parameterTypes;
36 if (relation.arity() != query.arity()) { 41 if (relation.arity() != query.arity()) {
37 throw new TranslationException(relation, "Expected arity %d query for partial relation %s, got %d instead" 42 throw new TranslationException(relation, "Expected arity %d query for partial relation %s, got %d instead"
38 .formatted(relation.arity(), relation, query.arity())); 43 .formatted(relation.arity(), relation, query.arity()));
@@ -78,6 +83,10 @@ public class PredicateTranslator implements ModelStoreConfiguration {
78 .clause(mayLiterals) 83 .clause(mayLiterals)
79 .build(); 84 .build();
80 translator.may(may); 85 translator.may(may);
86
87 if (parameterTypes != null && parameterTypes.stream().anyMatch(Objects::nonNull)) {
88 translator.refiner(PredicateRefiner.of(symbol, parameterTypes));
89 }
81 } else if (defaultValue.may()) { 90 } else if (defaultValue.may()) {
82 // If all values are permitted, we don't need to check for any forbidden values in the model. 91 // If all values are permitted, we don't need to check for any forbidden values in the model.
83 // If the result of this predicate of {@code ERROR}, some other partial relation (that we check for) 92 // If the result of this predicate of {@code ERROR}, some other partial relation (that we check for)
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/ShadowPredicateTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/ShadowPredicateTranslator.java
new file mode 100644
index 00000000..08cc9235
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/ShadowPredicateTranslator.java
@@ -0,0 +1,71 @@
1/*
2 * SPDX-FileCopyrightText: 2024 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.predicate;
7
8import tools.refinery.logic.dnf.RelationalQuery;
9import tools.refinery.logic.term.truthvalue.TruthValue;
10import tools.refinery.store.map.Cursor;
11import tools.refinery.store.model.ModelStoreBuilder;
12import tools.refinery.store.model.ModelStoreConfiguration;
13import tools.refinery.store.reasoning.ReasoningAdapter;
14import tools.refinery.store.reasoning.ReasoningBuilder;
15import tools.refinery.store.reasoning.interpretation.AbstractPartialInterpretation;
16import tools.refinery.store.reasoning.interpretation.QueryBasedComputedRewriter;
17import tools.refinery.store.reasoning.literal.Concreteness;
18import tools.refinery.store.reasoning.literal.Modality;
19import tools.refinery.store.reasoning.representation.PartialRelation;
20import tools.refinery.store.reasoning.representation.PartialSymbol;
21import tools.refinery.store.reasoning.translator.PartialRelationTranslator;
22import tools.refinery.store.tuple.Tuple;
23
24public class ShadowPredicateTranslator implements ModelStoreConfiguration {
25 private final PartialRelation relation;
26 private final RelationalQuery query;
27 private final boolean hasInterpretation;
28
29 public ShadowPredicateTranslator(PartialRelation relation, RelationalQuery query, boolean hasInterpretation) {
30 this.relation = relation;
31 this.query = query;
32 this.hasInterpretation = hasInterpretation;
33 }
34
35 @Override
36 public void apply(ModelStoreBuilder storeBuilder) {
37 var reasoningBuilder = storeBuilder.getAdapter(ReasoningBuilder.class);
38 var may = reasoningBuilder.lift(Modality.MAY, Concreteness.PARTIAL, query);
39 var must = reasoningBuilder.lift(Modality.MAY, Concreteness.PARTIAL, query);
40 // Do not let {@link PartialRelationTranslator} merge the partial queries into the candidate ones.
41 var candidateMay = reasoningBuilder.lift(Modality.MAY, Concreteness.PARTIAL, query);
42 var candidateMust = reasoningBuilder.lift(Modality.MAY, Concreteness.PARTIAL, query);
43 var translator = PartialRelationTranslator.of(relation)
44 .rewriter(new QueryBasedComputedRewriter(may, must, candidateMay, candidateMust, query));
45 if (!hasInterpretation) {
46 translator.interpretation(MissingInterpretation::new);
47 }
48 storeBuilder.with(translator);
49 }
50
51 private static class MissingInterpretation extends AbstractPartialInterpretation<TruthValue, Boolean> {
52 public MissingInterpretation(ReasoningAdapter adapter, Concreteness concreteness,
53 PartialSymbol<TruthValue, Boolean> partialSymbol) {
54 super(adapter, concreteness, partialSymbol);
55 }
56
57 @Override
58 public TruthValue get(Tuple key) {
59 return fail();
60 }
61
62 @Override
63 public Cursor<Tuple, TruthValue> getAll() {
64 return fail();
65 }
66
67 private <T> T fail() {
68 throw new UnsupportedOperationException("No interpretation for shadow predicate: " + getPartialSymbol());
69 }
70 }
71}
diff --git a/subprojects/store/build.gradle.kts b/subprojects/store/build.gradle.kts
index ac4b92f6..e0742cbe 100644
--- a/subprojects/store/build.gradle.kts
+++ b/subprojects/store/build.gradle.kts
@@ -14,6 +14,6 @@ mavenArtifact {
14} 14}
15 15
16dependencies { 16dependencies {
17 implementation(libs.eclipseCollections.api) 17 implementation(libs.eclipseCollections)
18 runtimeOnly(libs.eclipseCollections) 18 runtimeOnly(libs.eclipseCollections.impl)
19} 19}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java
index 3b55434c..45922fa7 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java
@@ -76,6 +76,7 @@ class MultiThreadFuzzTest {
76 @MethodSource 76 @MethodSource
77 @Timeout(value = 10) 77 @Timeout(value = 10)
78 @Tag("fuzz") 78 @Tag("fuzz")
79 @Tag("slow")
79 void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, 80 void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull,
80 int commitFrequency, int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) { 81 int commitFrequency, int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) {
81 runFuzzTest("MultiThreadS" + steps + "K" + noKeys + "V" + noValues + defaultNull + "CF" + commitFrequency + 82 runFuzzTest("MultiThreadS" + steps + "K" + noKeys + "V" + noValues + defaultNull + "CF" + commitFrequency +
diff --git a/subprojects/versions/build.gradle.kts b/subprojects/versions/build.gradle.kts
index 0cc9e811..054158cb 100644
--- a/subprojects/versions/build.gradle.kts
+++ b/subprojects/versions/build.gradle.kts
@@ -17,8 +17,9 @@ mavenArtifact {
17} 17}
18 18
19val refineryVersion = "refinery" 19val refineryVersion = "refinery"
20val interpreterVersion = "refineryInterpreter" 20val interpreterVersion = "refinery-interpreter"
21val interpreterGroup = property("tools.refinery.interpreter.group").toString() 21val interpreterGroup = property("tools.refinery.interpreter.group").toString()
22val shadowVersion = "shadow"
22 23
23catalog.versionCatalog { 24catalog.versionCatalog {
24 from(files("../../gradle/libs.versions.toml")) 25 from(files("../../gradle/libs.versions.toml"))
@@ -26,6 +27,10 @@ catalog.versionCatalog {
26 version(interpreterVersion, property("tools.refinery.interpreter.version").toString()) 27 version(interpreterVersion, property("tools.refinery.interpreter.version").toString())
27 library("bom", group.toString(), "refinery-bom").versionRef(refineryVersion) 28 library("bom", group.toString(), "refinery-bom").versionRef(refineryVersion)
28 library("bom-dependencies", group.toString(), "refinery-bom-dependencies").versionRef(refineryVersion) 29 library("bom-dependencies", group.toString(), "refinery-bom-dependencies").versionRef(refineryVersion)
30
31 // Let downstream users add the shadow plugin to bundle their dependencies.
32 version(shadowVersion, pluginLibs.versions.shadow.get())
33 plugin("shadow", "io.github.goooler.shadow").versionRef(shadowVersion)
29} 34}
30 35
31publishing.publications.named<MavenPublication>("mavenJava") { 36publishing.publications.named<MavenPublication>("mavenJava") {