diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3ef535e73..9ba843ea7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,7 +39,7 @@ jdt-core = "3.38.0" jdt-debug = "3.21.400" jdt-launching = "3.22.0" jetbrainsAnnotations = "24.1.0" -jetty = "12.0.11" +jetty = "12.0.12" jmh = "1.37" jna = "5.14.0" junit = "5.10.3" diff --git a/package.json b/package.json index 32c0f23c6..478ae120b 100644 --- a/package.json +++ b/package.json @@ -36,10 +36,10 @@ }, "devDependencies": { "@types/eslint": "^8.56.11", - "@types/node": "^20.14.12", + "@types/node": "^20.14.14", "@types/react": "^18.3.3", - "@typescript-eslint/eslint-plugin": "^7.17.0", - "@typescript-eslint/parser": "^7.17.0", + "@typescript-eslint/eslint-plugin": "^7.18.0", + "@typescript-eslint/parser": "^7.18.0", "corepack": "^0.29.3", "eslint": "^8.57.0", "eslint-config-airbnb": "^19.0.4", diff --git a/subprojects/docs/package.json b/subprojects/docs/package.json index 3f8a8cdb2..0ba80c2c5 100644 --- a/subprojects/docs/package.json +++ b/subprojects/docs/package.json @@ -44,7 +44,7 @@ "@fontsource/open-sans": "^5.0.28", "@material-icons/svg": "^1.0.33", "@mdx-js/react": "^3.0.1", - "@swc/core": "^1.7.2", + "@swc/core": "^1.7.5", "clsx": "^2.1.1", "java-properties": "^1.0.2", "mdast-util-mdx": "^3.0.0", @@ -68,7 +68,7 @@ "@docusaurus/types": "^3.4.0", "@types/babel__core": "^7.20.5", "@types/mdast": "^4.0.4", - "@types/node": "^20.14.12", + "@types/node": "^20.14.14", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@types/unist": "^3.0.2" diff --git a/subprojects/frontend/package.json b/subprojects/frontend/package.json index 638b205da..9fa73cc78 100644 --- a/subprojects/frontend/package.json +++ b/subprojects/frontend/package.json @@ -34,7 +34,7 @@ "@codemirror/lint": "^6.8.1", "@codemirror/search": "^6.5.6", "@codemirror/state": "^6.4.1", - "@codemirror/view": "^6.29.0", + "@codemirror/view": "^6.29.1", "@emotion/cache": "^11.13.1", "@emotion/react": "^11.13.0", "@emotion/serialize": "^1.3.0", @@ -46,12 +46,12 @@ "@hpcc-js/wasm": "^2.18.0", "@lezer/common": "^1.2.1", "@lezer/highlight": "^1.2.0", - "@lezer/lr": "^1.4.1", + "@lezer/lr": "^1.4.2", "@material-icons/svg": "^1.0.33", - "@mui/icons-material": "^5.16.5", - "@mui/material": "^5.16.5", - "@mui/system": "^5.16.5", - "@mui/x-data-grid": "^7.11.1", + "@mui/icons-material": "^5.16.6", + "@mui/material": "^5.16.6", + "@mui/system": "^5.16.6", + "@mui/x-data-grid": "^7.12.0", "ansi-styles": "^6.2.1", "csstype": "^3.1.3", "d3": "^7.9.0", @@ -88,7 +88,7 @@ "@types/lodash-es": "^4.17.12", "@types/micromatch": "^4.0.9", "@types/ms": "^0.7.34", - "@types/node": "^20.14.12", + "@types/node": "^20.14.14", "@types/pnpapi": "^0.0.5", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", diff --git a/subprojects/frontend/src/graph/GraphStore.ts b/subprojects/frontend/src/graph/GraphStore.ts index 30d0a2f33..a133d636a 100644 --- a/subprojects/frontend/src/graph/GraphStore.ts +++ b/subprojects/frontend/src/graph/GraphStore.ts @@ -25,6 +25,7 @@ export function getDefaultVisibility( case 'class': case 'reference': case 'opposite': + case 'base': return 'all'; case 'predicate': return detail.error ? 'must' : 'none'; diff --git a/subprojects/frontend/src/language/problem.grammar b/subprojects/frontend/src/language/problem.grammar index b8038b70c..56867964b 100644 --- a/subprojects/frontend/src/language/problem.grammar +++ b/subprojects/frontend/src/language/problem.grammar @@ -52,8 +52,7 @@ statement { kw<"extern"> ckw<"aggregator"> AggregatorName "." } | PredicateDefinition { - ckw<"shadow">? - (kw<"error">? kw<"pred"> | kw<"error">) + ((kw<"error"> | kw<"partial"> | ckw<"shadow">)* kw<"pred"> | kw<"error">) RelationName ParameterList? PredicateBody { ("<->" sep)? "." } } | diff --git a/subprojects/frontend/src/xtext/xtextServiceResults.ts b/subprojects/frontend/src/xtext/xtextServiceResults.ts index c5bc13205..7c2fb8ec4 100644 --- a/subprojects/frontend/src/xtext/xtextServiceResults.ts +++ b/subprojects/frontend/src/xtext/xtextServiceResults.ts @@ -156,6 +156,7 @@ export const RelationMetadata = z.object({ opposite: z.string(), }), z.object({ type: z.literal('predicate'), error: z.boolean() }), + z.object({ type: z.literal('base') }), z.object({ type: z.literal('builtin') }), ]), }); diff --git a/subprojects/generator/src/main/java/tools/refinery/generator/ModelFacadeFactory.java b/subprojects/generator/src/main/java/tools/refinery/generator/ModelFacadeFactory.java index 75ca5082d..173be38e4 100644 --- a/subprojects/generator/src/main/java/tools/refinery/generator/ModelFacadeFactory.java +++ b/subprojects/generator/src/main/java/tools/refinery/generator/ModelFacadeFactory.java @@ -10,6 +10,8 @@ import tools.refinery.language.semantics.ModelInitializer; import tools.refinery.store.util.CancellationToken; +// This class is used as a fluent builder, so it's not necessary to use the return value of all of its methods. +@SuppressWarnings("UnusedReturnValue") public abstract sealed class ModelFacadeFactory> permits ModelSemanticsFactory, ModelGeneratorFactory { @Inject @@ -17,7 +19,9 @@ public abstract sealed class ModelFacadeFactory> private CancellationToken cancellationToken = CancellationToken.NONE; - private boolean keepNonExistingObjects = false; + private boolean keepNonExistingObjects; + + private boolean keepShadowPredicates = true; protected abstract T getSelf(); @@ -26,13 +30,21 @@ public T cancellationToken(CancellationToken cancellationToken) { return getSelf(); } - public T keepNonExistingObjects(boolean removeNonExistentObjects) { - this.keepNonExistingObjects = removeNonExistentObjects; + public T keepNonExistingObjects(boolean keepNonExistentObjects) { + this.keepNonExistingObjects = keepNonExistentObjects; + return getSelf(); + } + + public T keepShadowPredicates(boolean keepShadowPredicates) { + this.keepShadowPredicates = keepShadowPredicates; return getSelf(); } protected ModelInitializer createModelInitializer() { - return initializerProvider.get(); + var initializer = initializerProvider.get(); + initializer.setKeepNonExistingObjects(keepNonExistingObjects); + initializer.setKeepShadowPredicates(keepShadowPredicates); + return initializer; } protected CancellationToken getCancellationToken() { 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 b041c8f6b..3205eca29 100644 --- a/subprojects/generator/src/main/java/tools/refinery/generator/ModelGeneratorFactory.java +++ b/subprojects/generator/src/main/java/tools/refinery/generator/ModelGeneratorFactory.java @@ -35,6 +35,10 @@ public final class ModelGeneratorFactory extends ModelFacadeFactory { private boolean withCandidateInterpretations; @@ -45,7 +47,7 @@ public ModelSemantics tryCreateSemantics(Problem problem) { .throwOnFatalRejection(false)) .with(ReasoningAdapter.builder() .requiredInterpretations(getRequiredInterpretations())); - initializer.configureStoreBuilder(storeBuilder, isKeepNonExistingObjects()); + initializer.configureStoreBuilder(storeBuilder); var store = storeBuilder.build(); return new ModelSemantics(initializer.getProblemTrace(), store, initializer.getModelSeed()); } diff --git a/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java b/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java index 6e954188a..42ae94668 100644 --- a/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java +++ b/subprojects/generator/src/test/java/tools/refinery/generator/FileBasedSemanticsTest.java @@ -6,6 +6,7 @@ package tools.refinery.generator; import com.google.inject.Inject; +import com.google.inject.Provider; import org.junit.jupiter.api.DynamicNode; import org.junit.jupiter.api.TestFactory; import tools.refinery.generator.tests.DynamicTestLoader; @@ -18,8 +19,23 @@ class FileBasedSemanticsTest { @Inject private DynamicTestLoader loader; + @Inject + private Provider semanticsFactoryProvider; + @TestFactory - Stream fileBasedTests() { + Stream testWithNonExistingObjects() { + return getFileBasedTests(true, true); + } + + @TestFactory + Stream testWithoutNonExistingObjects() { + return getFileBasedTests(false, false); + } + + private Stream getFileBasedTests(boolean keepNonExistingObjects, boolean keepShadowPredicates) { + loader.setSemanticsFactoryProvider(() -> semanticsFactoryProvider.get() + .keepNonExistingObjects(keepNonExistingObjects) + .keepShadowPredicates(keepShadowPredicates)); return loader.allFromClasspath(getClass()); } } 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 000000000..4c24fa5ae --- /dev/null +++ b/subprojects/generator/src/test/resources/tools/refinery/generator/crossreference/typeConstraint.problem @@ -0,0 +1,85 @@ +% Copyright (c) 2024 The Refinery Authors +% +% SPDX-License-Identifier: EPL-2.0 + +% TEST WITH ERRORS: directed cross reference type constraint + +class A { + B[] foo +} + +class B. + +foo(a1, b1). +!foo(a2, b2). +?foo(a3, b3). +foo(a4, b4): error. + +% EXPECT EXACTLY: +foo(a1, b1). +!foo(a2, b2). +?foo(a3, b3). +foo(a4, b4): error. +A(a1). +B(b1). +?A(a2). +?B(b2). +?A(a3). +?B(b3). +A(a4). +B(b4). + +% TEST: directed cross reference with predicate type + +class A { + bar[] foo +} + +pred bar(A a) <-> !foo(a, _). + +foo(a1, b1). + +% EXPECT: +A(a1). +bar(b1). + +% TEST WITH ERRORS: directed cross reference with predicate type and assertion + +class A { + bar[] foo +} + +pred bar(A a) <-> !foo(a, _). + +!bar(b1). +foo(a1, b1). + +% EXPECT EXACTLY: +foo(a1, b1): error. +A(a1). +bar(b1): error. + +% TEST WITH ERRORS: undirected cross reference type constraint + +class A { + A[] bar opposite bar +} + +bar(a1, b1). +!bar(a2, b2). +?bar(a3, b3). +bar(a4, b4): error. + +% EXPECT EXACTLY: +bar(a1, b1). +!bar(a2, b2). +?bar(a3, b3). +bar(a4, b4): error. +A(a1). +A(b1). +?A(a2). +?A(b2). +?A(a3). +?A(b3). +A(a4). +A(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 000000000..bd9fd1476 --- /dev/null +++ b/subprojects/generator/src/test/resources/tools/refinery/generator/crossreference/undirectedMultiplicity.problem @@ -0,0 +1,57 @@ +% Copyright (c) 2024 The Refinery Authors +% +% SPDX-License-Identifier: EPL-2.0 + +% TEST: upper bound propagation + +class Person { + Person[0..2] friend opposite friend +} + +friend(a, b). +friend(a, c). +friend(b, c). +!exists(Person::new). + +% EXPECT: +friend(b, a). +friend(c, a). +friend(c, b). +!friend(a, a). +!friend(b, b). +!friend(c, c). + +% TEST: lower bound propagation + +class Person { + Person[2..*] friend opposite friend +} + +Person(a). +!friend(a, a). +!friend(b, b). +!friend(c, c). +!exists(Person::new). + +% EXPECT: +friend(a, b). +friend(a, c). +friend(b, c). + +% TEST: upper and lower bound propagation + +class Person { + Person[2] friend opposite friend +} + +friend(a, b). +friend(a, c). +!friend(b, b). +!friend(c, c). +!exists(Person::new). + +% EXPECT: +friend(b, c). +!friend(a, a). +!friend(b, b). +!friend(c, c). 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 index 7886ec0ae..001ee3a4d 100644 --- a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/DynamicTestLoader.java +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/DynamicTestLoader.java @@ -34,9 +34,13 @@ public class DynamicTestLoader { @Inject private Provider testLoaderProvider; - @Inject private Provider semanticsFactoryProvider; + @Inject + public void setSemanticsFactoryProvider(Provider semanticsFactoryProvider) { + this.semanticsFactoryProvider = semanticsFactoryProvider; + } + public Stream allFromClasspath(Class contextClass) { var paths = getExtraPaths(contextClass); if (paths.isEmpty()) { 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 index 952924e2e..f75cac8e3 100644 --- a/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCase.java +++ b/subprojects/generator/src/testFixtures/java/tools/refinery/generator/tests/SemanticsTestCase.java @@ -8,12 +8,14 @@ import org.eclipse.collections.api.factory.primitive.IntObjectMaps; import org.eclipse.collections.api.map.primitive.IntObjectMap; import org.eclipse.core.runtime.AssertionFailedException; +import tools.refinery.generator.FilteredInterpretation; import tools.refinery.generator.ModelSemantics; import tools.refinery.generator.ModelSemanticsFactory; import tools.refinery.language.model.problem.Problem; import tools.refinery.language.semantics.ProblemTrace; import tools.refinery.logic.term.truthvalue.TruthValue; import tools.refinery.store.map.Cursor; +import tools.refinery.store.reasoning.ReasoningAdapter; import tools.refinery.store.reasoning.literal.Concreteness; import tools.refinery.store.reasoning.representation.PartialRelation; import tools.refinery.store.tuple.Tuple; @@ -47,8 +49,10 @@ private void checkNoErrors(ModelSemantics semantics) { var errorsBuilder = new StringBuilder("Errors found in partial model:\n\n"); var trace = semantics.getProblemTrace(); IntObjectMap nodeNames = null; + var existsInterpretation = semantics.getPartialInterpretation(ReasoningAdapter.EXISTS_SYMBOL); for (var symbol : trace.getRelationTrace().values()) { - var interpretation = semantics.getPartialInterpretation(symbol); + var interpretation = new FilteredInterpretation<>(semantics.getPartialInterpretation(symbol), + existsInterpretation); var cursor = interpretation.getAll(); while (cursor.move()) { if (!cursor.getValue().isError()) { diff --git a/subprojects/language-model/problem.aird b/subprojects/language-model/problem.aird index 7c1f7368e..f2495bcf5 100644 --- a/subprojects/language-model/problem.aird +++ b/subprojects/language-model/problem.aird @@ -7,7 +7,7 @@ build/resources/main/model/problem.genmodel - + @@ -91,10 +91,6 @@ - - - - @@ -494,6 +490,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1591,22 +1612,14 @@ - - - + + + - - - - - - - - @@ -2865,6 +2878,49 @@ + + + + KEEP_LOCATION + KEEP_SIZE + KEEP_RATIO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/subprojects/language-model/src/main/resources/model/problem.ecore b/subprojects/language-model/src/main/resources/model/problem.ecore index a9b6f660b..0bc8caf9d 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 @@ - - + @@ -281,4 +280,10 @@ + + + + + + diff --git a/subprojects/language-model/src/main/resources/model/problem.genmodel b/subprojects/language-model/src/main/resources/model/problem.genmodel index f3c367e1a..e7cf6843d 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 @@ + + + + + + @@ -105,8 +111,7 @@ - - + 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 6aea31327..f45acc960 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.multiplicity.ConstrainedMultiplicity; import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; import tools.refinery.store.reasoning.translator.multiplicity.UnconstrainedMultiplicity; +import tools.refinery.store.reasoning.translator.predicate.BasePredicateTranslator; import tools.refinery.store.reasoning.translator.predicate.PredicateTranslator; +import tools.refinery.store.reasoning.translator.predicate.ShadowPredicateTranslator; import tools.refinery.store.statecoding.StateCoderBuilder; import tools.refinery.store.tuple.Tuple; import tools.refinery.store.tuple.Tuple1; @@ -68,6 +70,10 @@ public class ModelInitializer { @Inject private RuleCompiler ruleCompiler; + private boolean keepNonExistingObjects; + + private boolean keepShadowPredicates = true; + private Problem problem; private final Set importedProblems = new HashSet<>(); @@ -180,10 +186,6 @@ private void loadImportedProblems() { } public void configureStoreBuilder(ModelStoreBuilder storeBuilder) { - configureStoreBuilder(storeBuilder, false); - } - - public void configureStoreBuilder(ModelStoreBuilder storeBuilder, boolean keepNonExistingObjects) { checkProblem(); try { storeBuilder.with(new MultiObjectTranslator(keepNonExistingObjects)); @@ -198,6 +200,9 @@ public void configureStoreBuilder(ModelStoreBuilder storeBuilder, boolean keepNo collectRules(storeBuilder); storeBuilder.tryGetAdapter(StateCoderBuilder.class) .ifPresent(stateCoderBuilder -> stateCoderBuilder.individuals(individuals)); + if (!keepShadowPredicates) { + problemTrace.removeShadowRelations(); + } } catch (TranslationException e) { throw problemTrace.wrapException(e); } @@ -291,7 +296,7 @@ private void collectClassDeclarationSymbols(ClassDeclaration classDeclaration) { private void collectPredicateDefinitionSymbol(PredicateDefinition predicateDefinition) { int arity = predicateDefinition.getParameters().size(); - if (predicateDefinition.isError()) { + if (predicateDefinition.getKind() == PredicateKind.ERROR) { collectPartialRelation(predicateDefinition, arity, TruthValue.FALSE, TruthValue.FALSE); } else { collectPartialRelation(predicateDefinition, arity, null, TruthValue.UNKNOWN); @@ -596,26 +601,32 @@ private void collectPredicateDefinitionTraced(PredicateDefinition predicateDefin } private void collectPredicateDefinition(PredicateDefinition predicateDefinition, ModelStoreBuilder storeBuilder) { + if (ProblemUtil.isBasePredicate(predicateDefinition)) { + collectBasePredicateDefinition(predicateDefinition, storeBuilder); + } else if (predicateDefinition.getKind() == PredicateKind.SHADOW) { + collectShadowPredicateDefinition(predicateDefinition, storeBuilder); + } else { + collectComputedPredicateDefinition(predicateDefinition, storeBuilder); + } + } + + private void collectComputedPredicateDefinition(PredicateDefinition predicateDefinition, + ModelStoreBuilder storeBuilder) { var partialRelation = getPartialRelation(predicateDefinition); var query = queryCompiler.toQuery(partialRelation.name(), predicateDefinition); - boolean mutable; + boolean mutable = targetTypes.contains(partialRelation) || isActionTarget(predicateDefinition); TruthValue defaultValue; - if (predicateDefinition.isShadow()) { - mutable = false; - defaultValue = TruthValue.UNKNOWN; + if (predicateDefinition.getKind() == PredicateKind.ERROR) { + defaultValue = TruthValue.FALSE; } else { - mutable = targetTypes.contains(partialRelation) || isActionTarget(predicateDefinition); - if (predicateDefinition.isError()) { - defaultValue = TruthValue.FALSE; - } else { - var seed = modelSeed.getSeed(partialRelation); - defaultValue = seed.majorityValue() == TruthValue.FALSE ? TruthValue.FALSE : TruthValue.UNKNOWN; - var cursor = seed.getCursor(defaultValue, problemTrace.getNodeTrace().size()); - // The symbol should be mutable if there is at least one non-default entry in the seed. - mutable = mutable || cursor.move(); - } - } - var translator = new PredicateTranslator(partialRelation, query, mutable, defaultValue); + var seed = modelSeed.getSeed(partialRelation); + defaultValue = seed.majorityValue() == TruthValue.FALSE ? TruthValue.FALSE : TruthValue.UNKNOWN; + var cursor = seed.getCursor(defaultValue, problemTrace.getNodeTrace().size()); + // The symbol should be mutable if there is at least one non-default entry in the seed. + mutable = mutable || cursor.move(); + } + var parameterTypes = getParameterTypes(predicateDefinition, null); + var translator = new PredicateTranslator(partialRelation, query, parameterTypes, mutable, defaultValue); storeBuilder.with(translator); } @@ -628,6 +639,36 @@ private boolean isActionTarget(PredicateDefinition predicateDefinition) { return false; } + private List getParameterTypes(ParametricDefinition parametricDefinition, + PartialRelation defaultType) { + var parameters = parametricDefinition.getParameters(); + var parameterTypes = new ArrayList(parameters.size()); + for (var parameter : parameters) { + var relation = parameter.getParameterType(); + parameterTypes.add(relation == null ? defaultType : getPartialRelation(relation)); + } + return Collections.unmodifiableList(parameterTypes); + } + + private void collectBasePredicateDefinition(PredicateDefinition predicateDefinition, + ModelStoreBuilder storeBuilder) { + var partialRelation = getPartialRelation(predicateDefinition); + var parameterTypes = getParameterTypes(predicateDefinition, nodeRelation); + var seed = modelSeed.getSeed(partialRelation); + var defaultValue = seed.majorityValue() == TruthValue.FALSE ? TruthValue.FALSE : TruthValue.UNKNOWN; + boolean partial = predicateDefinition.getKind() == PredicateKind.PARTIAL; + var translator = new BasePredicateTranslator(partialRelation, parameterTypes, defaultValue, partial); + storeBuilder.with(translator); + } + + private void collectShadowPredicateDefinition(PredicateDefinition predicateDefinition, + ModelStoreBuilder storeBuilder) { + var partialRelation = getPartialRelation(predicateDefinition); + var query = queryCompiler.toQuery(partialRelation.name(), predicateDefinition); + var translator = new ShadowPredicateTranslator(partialRelation, query, keepShadowPredicates); + storeBuilder.with(translator); + } + private void collectScopes() { for (var importedProblem : importedProblems) { for (var statement : importedProblem.getStatements()) { @@ -676,6 +717,18 @@ private void collectTypeScope(TypeScope typeScope) { scopePropagator.scope(type, interval); } + public void setKeepNonExistingObjects(boolean keepNonExistingObjects) { + this.keepNonExistingObjects = keepNonExistingObjects; + } + + public boolean isKeepShadowPredicates() { + return keepShadowPredicates; + } + + public void setKeepShadowPredicates(boolean keepShadowPredicates) { + this.keepShadowPredicates = keepShadowPredicates; + } + private record RelationInfo(PartialRelation partialRelation, MutableSeed assertions, MutableSeed defaultAssertions) { 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 457f2362e..487ac9b9c 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 @@ void putRelation(Relation relation, PartialRelation partialRelation) { } } + void removeShadowRelations() { + var iterator = mutableRelationTrace.entrySet().iterator(); + while (iterator.hasNext()) { + var entry = iterator.next(); + var relation = entry.getKey(); + if (relation instanceof PredicateDefinition predicateDefinition && + predicateDefinition.getKind() == PredicateKind.SHADOW) { + iterator.remove(); + mutableInverseTrace.remove(entry.getValue()); + } + } + } + @Override public Map getInverseRelationTrace() { 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 ed4841c48..16a41824c 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.scoping.imports.ImportAdapterProvider; import tools.refinery.language.typesystem.SignatureProvider; import tools.refinery.language.utils.ProblemUtil; +import tools.refinery.logic.term.truthvalue.TruthValue; import tools.refinery.store.model.Model; import tools.refinery.store.reasoning.ReasoningAdapter; import tools.refinery.store.reasoning.interpretation.PartialInterpretation; @@ -31,13 +32,15 @@ import tools.refinery.store.reasoning.representation.PartialRelation; import tools.refinery.store.reasoning.translator.typehierarchy.InferredType; import tools.refinery.store.reasoning.translator.typehierarchy.TypeHierarchyTranslator; -import tools.refinery.logic.term.truthvalue.TruthValue; import tools.refinery.store.tuple.Tuple; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.*; +import java.util.Map; +import java.util.Objects; +import java.util.TreeMap; +import java.util.UUID; import java.util.function.Function; import java.util.stream.Collectors; @@ -107,6 +110,7 @@ public Problem serializeSolution(ProblemTrace trace, Model model, URI uri) { addExistsAssertions(); addClassAssertions(); addReferenceAssertions(); + addBasePredicateAssertions(); if (nodeDeclaration.getNodes().isEmpty()) { problem.getStatements().remove(nodeDeclaration); } @@ -249,8 +253,8 @@ private void addExistsAssertions() { } private void addClassAssertions() { - var types = - trace.getMetamodel().typeHierarchy().getPreservedTypes().keySet().stream().collect(Collectors.toMap(Function.identity(), this::findPartialRelation)); + var types = trace.getMetamodel().typeHierarchy().getPreservedTypes().keySet().stream() + .collect(Collectors.toMap(Function.identity(), this::findPartialRelation)); var cursor = model.getInterpretation(TypeHierarchyTranslator.TYPE_SYMBOL).getAll(); while (cursor.move()) { var key = cursor.getKey(); @@ -306,6 +310,17 @@ private void addReferenceAssertions() { } } + private void addBasePredicateAssertions() { + for (var entry : trace.getRelationTrace().entrySet()) { + if (entry.getKey() instanceof PredicateDefinition predicateDefinition && + ProblemUtil.isBasePredicate(predicateDefinition)) { + var partialRelation = entry.getValue(); + addDefaultAssertion(partialRelation); + addAssertions(partialRelation); + } + } + } + private void addAssertions(PartialRelation partialRelation) { var relation = findPartialRelation(partialRelation); var cursor = reasoningAdapter.getPartialInterpretation(Concreteness.CANDIDATE, partialRelation).getAll(); 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 69b5f1c2a..fded04bf8 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 @@ -234,6 +234,65 @@ class Foo. !exists(a). !exists(Foo::new). Foo(foo1). + """), Arguments.of(""" + class Foo { + partial Bar[] bar + } + + class Bar. + """, """ + bar(a, b). + scope Foo = 2, Bar = 2. + """, """ + declare a, b, foo1, bar1. + !exists(Foo::new). + !exists(Bar::new). + Foo(foo1). + Bar(bar1). + Foo(a). + Bar(b). + default !bar(*, *). + ?bar(foo1, bar1). + ?bar(foo1, b). + ?bar(a, bar1). + bar(a, b). + """), Arguments.of(""" + class Foo. + class Bar. + pred bar(Foo x, Bar y). + """, """ + bar(a, b). + scope Foo = 2, Bar = 2. + """, """ + declare a, b, foo1, bar1. + !exists(Foo::new). + !exists(Bar::new). + Foo(foo1). + Bar(bar1). + Foo(a). + Bar(b). + default !bar(*, *). + bar(a, b). + """), Arguments.of(""" + class Foo. + class Bar. + partial pred bar(Foo x, Bar y). + """, """ + bar(a, b). + scope Foo = 2, Bar = 2. + """, """ + declare a, b, foo1, bar1. + !exists(Foo::new). + !exists(Bar::new). + Foo(foo1). + Bar(bar1). + Foo(a). + Bar(b). + default !bar(*, *). + ?bar(foo1, bar1). + ?bar(foo1, b). + ?bar(a, bar1). + bar(a, b). """)); } } 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 000000000..6ffaf267a --- /dev/null +++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/BasePredicateDetail.java @@ -0,0 +1,10 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.language.web.semantics.metadata; + +public record BasePredicateDetail() implements RelationDetail { + public static final BasePredicateDetail INSTANCE = new BasePredicateDetail(); +} 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 29f8ab8ba..11f0a2287 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 @@ private RelationDetail getEnumDetail() { } private RelationDetail getPredicateDetail(PredicateDefinition predicate) { - return PredicateDetail.ofError(predicate.isError()); + if (ProblemUtil.isBasePredicate(predicate)) { + return BasePredicateDetail.INSTANCE; + } + return PredicateDetail.ofError(predicate.getKind() == PredicateKind.ERROR); } 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 bbe563cdd..00177858d 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 @@ package tools.refinery.language.web.semantics.metadata; public sealed interface RelationDetail permits ClassDetail, ReferenceDetail, PredicateDetail, OppositeReferenceDetail, - BuiltInDetail { + BuiltInDetail, BasePredicateDetail { } 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 818bd80e3..13ae12219 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 { .registerSubtype(ReferenceDetail.class, "reference") .registerSubtype(OppositeReferenceDetail.class, "opposite") .registerSubtype(PredicateDetail.class, "predicate") - .registerSubtype(BuiltInDetail.class, "builtin")) + .registerSubtype(BuiltInDetail.class, "builtin") + .registerSubtype(BasePredicateDetail.class, "base")) .create(); private final TransactionExecutor executor; 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 7e3b3c83b..7cd62dcd2 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: ReferenceMultiplicity returns Multiplicity: "[" Multiplicity "]"; +enum ErrorPredicateKind returns PredicateKind: + ERROR="error"; + +enum PredicateKind: + ERROR="error" | PARTIAL="partial" | SHADOW="shadow"; + PredicateDefinition: - shadow?="shadow"? - ("pred" | error?="error" "pred"?) + (kind=ErrorPredicateKind | kind=PredicateKind? "pred") name=Identifier "(" (parameters+=Parameter ("," parameters+=Parameter)*)? ")" ("<->" bodies+=Conjunction (";" bodies+=Conjunction)*)? @@ -294,7 +299,7 @@ Identifier: NonContainmentIdentifier: ID | "atom" | "multi" | "contained" | "problem" | "module" | - "datatype" | "aggregator" | "decision" | "propagation" | "computed"; + "datatype" | "aggregator" | "decision" | "propagation" | "shadow"; Real returns ecore::EDouble: 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 44f555638..97e93d462 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 @@ protected void installOrRemoveInvalidMultiplicityPredicate( if (declaration.getInvalidMultiplicity() == null) { var invalidMultiplicity = adapter.createInvalidMultiplicityPredicateIfAbsent(declaration, key -> { var predicate = ProblemFactory.eINSTANCE.createPredicateDefinition(); - predicate.setError(true); + predicate.setKind(PredicateKind.ERROR); predicate.setName("invalidMultiplicity"); var parameter = ProblemFactory.eINSTANCE.createParameter(); parameter.setParameterType(containingClassDeclaration); @@ -125,7 +125,7 @@ protected void installOrRemoveComputedValuePredicate(Adapter adapter, PredicateD if (ProblemUtil.hasComputedValue(predicateDefinition)) { var computedValue = adapter.createComputedValuePredicateIfAbsent(predicateDefinition, key -> { var predicate = ProblemFactory.eINSTANCE.createPredicateDefinition(); - predicate.setShadow(true); + predicate.setKind(PredicateKind.SHADOW); predicate.setName("computed"); return predicate; }); 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 f1e5a7acf..a8e3a783a 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 @@ private void checkTypes(Problem problem) { private void checkTypes(PredicateDefinition predicateDefinition) { for (var conjunction : predicateDefinition.getBodies()) { for (var literal : conjunction.getLiterals()) { - coerceIntoLiteral(literal, predicateDefinition.isShadow()); + coerceIntoLiteral(literal, predicateDefinition.getKind() == PredicateKind.SHADOW); } } } 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 067e684af..75e2ded01 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 static boolean isImplicit(EObject eObject) { } public static boolean isError(EObject eObject) { - return eObject instanceof PredicateDefinition predicateDefinition && predicateDefinition.isError(); + return eObject instanceof PredicateDefinition predicateDefinition && + predicateDefinition.getKind() == PredicateKind.ERROR; } public static boolean isShadow(EObject eObject) { - return eObject instanceof PredicateDefinition predicateDefinition && predicateDefinition.isShadow(); + return eObject instanceof PredicateDefinition predicateDefinition && + predicateDefinition.getKind() == PredicateKind.SHADOW; } public static boolean mayReferToShadow(EObject context) { var definitionContext = EcoreUtil2.getContainerOfType(context, ParametricDefinition.class); return switch (definitionContext) { - case PredicateDefinition predicateDefinition -> predicateDefinition.isShadow(); + case PredicateDefinition predicateDefinition -> predicateDefinition.getKind() == PredicateKind.SHADOW; case RuleDefinition ignored -> true; case null, default -> false; }; @@ -112,8 +114,26 @@ public static boolean hasMultiplicityConstraint(ReferenceDeclaration referenceDe return true; } + public static boolean isDerivedStatePredicate(PredicateDefinition predicateDefinition) { + var containingFeature = predicateDefinition.eContainingFeature(); + return containingFeature == ProblemPackage.Literals.REFERENCE_DECLARATION__INVALID_MULTIPLICITY || + containingFeature == ProblemPackage.Literals.PREDICATE_DEFINITION__COMPUTED_VALUE; + } + + public static boolean isBasePredicate(PredicateDefinition predicateDefinition) { + if (isBuiltIn(predicateDefinition) || predicateDefinition == null) { + // Built-in predicates have no clauses, but are not base. + return false; + } + return switch (predicateDefinition.getKind()) { + case DEFAULT -> predicateDefinition.getBodies().isEmpty(); + case PARTIAL -> true; + default -> false; + }; + } + public static boolean hasComputedValue(PredicateDefinition predicateDefinition) { - return !predicateDefinition.isShadow() && !predicateDefinition.getBodies().isEmpty(); + return predicateDefinition.getKind() != PredicateKind.SHADOW && !isBasePredicate(predicateDefinition); } 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 ace9f3ddb..74a6a0fc8 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 { public static final String INVALID_REFERENCE_TYPE_ISSUE = ISSUE_PREFIX + "INVALID_REFERENCE_TYPE"; public static final String INVALID_ARITY_ISSUE = ISSUE_PREFIX + "INVALID_ARITY"; public static final String INVALID_MODALITY_ISSUE = ISSUE_PREFIX + "INVALID_MODALITY"; + public static final String INVALID_PREDICATE_ISSUE = ISSUE_PREFIX + "INVALID_PREDICATE"; public static final String INVALID_RULE_ISSUE = ISSUE_PREFIX + "INVALID_RULE"; public static final String INVALID_TRANSITIVE_CLOSURE_ISSUE = ISSUE_PREFIX + "INVALID_TRANSITIVE_CLOSURE"; public static final String SHADOW_RELATION_ISSUE = ISSUE_PREFIX + "SHADOW_RELATION"; @@ -381,10 +382,27 @@ public void checkReferenceType(ReferenceDeclaration referenceDeclaration) { @Check public void checkPredicateDefinition(PredicateDefinition predicateDefinition) { - if (predicateDefinition.isError() && predicateDefinition.isShadow()) { - var message = "Shadow predicates cannot be marked as error predicates."; - acceptError(message, predicateDefinition, ProblemPackage.Literals.PREDICATE_DEFINITION__ERROR, 0, - SHADOW_RELATION_ISSUE); + if (ProblemUtil.isBuiltIn(predicateDefinition) || ProblemUtil.isDerivedStatePredicate(predicateDefinition)) { + return; + } + String message = null; + if (ProblemUtil.isBasePredicate(predicateDefinition)) { + if (!predicateDefinition.getBodies().isEmpty()) { + var predicateType = predicateDefinition.getKind() == PredicateKind.PARTIAL ? "Partial base predicate" : + "Base predicate"; + message = "%s '%s' must not have any clauses.".formatted(predicateType, predicateDefinition.getName()); + } + } else if (predicateDefinition.getBodies().isEmpty()) { + var predicateType = switch (predicateDefinition.getKind()) { + case ERROR -> "Error predicate"; + case SHADOW -> "Shadow predicate"; + default -> "Predicate"; + }; + message = "%s '%s' must have at least one clause.".formatted(predicateType, predicateDefinition.getName()); + } + if (message != null) { + acceptError(message, predicateDefinition, ProblemPackage.Literals.NAMED_ELEMENT__NAME, 0, + INVALID_PREDICATE_ISSUE); } } 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 c2e43e0d4..b38774b59 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 RuleBuilder action(ActionCallback4 callback) { } public Rule build() { + if (action == null) { + throw new IllegalStateException("Rule '%s' has no action".formatted(name)); + } var precondition = dnfBuilder.build().asRelation(); return new Rule(name, precondition, Action.ofPrecondition(precondition, action)); } 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 b83d162e0..8994ac6eb 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.StorageRefiner; import tools.refinery.store.reasoning.representation.AnyPartialSymbol; import tools.refinery.store.reasoning.representation.PartialSymbol; +import tools.refinery.store.reasoning.seed.ModelSeed; import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator; import tools.refinery.store.representation.Symbol; import tools.refinery.logic.term.cardinalityinterval.CardinalityInterval; @@ -106,6 +107,9 @@ private void createRefiners() { var refiner = createRefiner(factory, partialSymbol); refiners.put(partialSymbol, refiner); } + for (var refiner : refiners.values()) { + refiner.afterCreate(); + } } private , C> PartialInterpretationRefiner createRefiner( @@ -214,4 +218,10 @@ public int getNodeCount() { Integer nodeCount = nodeCountInterpretation.get(Tuple.of()); return nodeCount == null ? 0 : nodeCount; } + + void afterInitialize(ModelSeed modelSeed) { + for (var refiner : refiners.values()) { + refiner.afterInitialize(modelSeed); + } + } } 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 df4b64571..57cbb5d0c 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.model.Model; import tools.refinery.store.model.ModelStore; import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.reasoning.ReasoningAdapter; import tools.refinery.store.reasoning.ReasoningStoreAdapter; import tools.refinery.store.reasoning.interpretation.PartialInterpretation; import tools.refinery.store.reasoning.literal.Concreteness; @@ -107,6 +108,8 @@ public PropagatedModel tryCreateInitialModel(ModelSeed modelSeed) { for (var initializer : initializers) { initializer.initialize(model, modelSeed); } + var reasoningAdapter = ((ReasoningAdapterImpl) model.getAdapter(ReasoningAdapter.class)); + reasoningAdapter.afterInitialize(modelSeed); var propagationResult = model.tryGetAdapter(PropagationAdapter.class) .map(PropagationAdapter::propagate) .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 6c3815113..7fd17a3ae 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 @@ */ package tools.refinery.store.reasoning.refinement; +import tools.refinery.logic.AbstractValue; +import tools.refinery.store.model.Model; import tools.refinery.store.reasoning.ReasoningAdapter; import tools.refinery.store.reasoning.representation.AnyPartialSymbol; +import tools.refinery.store.reasoning.seed.ModelSeed; +import tools.refinery.store.tuple.Tuple; public sealed interface AnyPartialInterpretationRefiner permits PartialInterpretationRefiner { ReasoningAdapter getAdapter(); AnyPartialSymbol getPartialSymbol(); + + /** + * Called after all {@link PartialInterpretationRefiner} instances have been created for symbols registered to + * the {@link tools.refinery.store.reasoning.ReasoningStoreAdapter}. + *

+ * Override this method to access other {@link PartialInterpretationRefiner} instances associated to the + * {@link ReasoningAdapter} that are required for propagations executed by this + * {@link PartialInterpretationRefiner}. + */ + default void afterCreate() { + } + + /** + * Execute propagations based on the contents of the {@code modelSeed} that would by executed if the + * {@code modelSeed} were written to the model as a sequence of + * {@link PartialInterpretationRefiner#merge(Tuple, AbstractValue)} calls. + *

+ * This method is called only after {@link PartialModelInitializer#initialize(Model, ModelSeed)} was called on all + * {@link PartialModelInitializer} instances registered to the + * {@link tools.refinery.store.reasoning.ReasoningStoreAdapter}. + *

+ * The default implementation of this method performs no actions. Override it make the behavior consistent with + * your {@link PartialInterpretationRefiner#merge(Tuple, AbstractValue)} implementation. + * + * @param modelSeed The model seed which was written by a previous call of + * {@link PartialModelInitializer#initialize(Model, ModelSeed)}. + */ + default void afterInitialize(ModelSeed modelSeed) { + } } 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 d6ac0e9db..5474a4ff0 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 ConcreteSymbolRefiner(ReasoningAdapter adapter, PartialSymbol parti @Override public boolean merge(Tuple key, A value) { - var currentValue = interpretation.get(key); + var currentValue = get(key); var mergedValue = currentValue.meet(value); if (!Objects.equals(currentValue, mergedValue)) { - interpretation.put(key, mergedValue); + put(key, mergedValue); } return true; } + protected A get(Tuple key) { + return interpretation.get(key); + } + + protected A put(Tuple key, A value) { + return interpretation.put(key, value); + } + public static , C1> Factory of(Symbol concreteSymbol) { return (adapter, partialSymbol) -> new ConcreteSymbolRefiner<>(adapter, partialSymbol, concreteSymbol); } 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 3b78db02e..031115749 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 @@ public boolean isTerminated() { public boolean move() { return switch (state) { case INITIAL -> { + if (nodeCount == 0) { + state = State.TERMINATED; + yield false; + } state = State.STARTED; yield checkValue() || moveToNext(); } 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 9cd4862b2..31f6fa046 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 Set getSeededSymbols() { return getSeed(partialSymbol).getCursor(defaultValue, nodeCount); } + public > Cursor getCursor(PartialSymbol partialSymbol) { + return getCursor(partialSymbol, partialSymbol.defaultValue()); + } + public static Builder builder(int nodeCount) { return new Builder(nodeCount); } 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 138e3a640..adc6421fc 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 SeedInitializer(Symbol symbol, PartialSymbol partialSymbol) { this.partialSymbol = partialSymbol; } + protected Symbol getSymbol() { + return symbol; + } + + protected PartialSymbol getPartialSymbol() { + return partialSymbol; + } + @Override public void initialize(Model model, ModelSeed modelSeed) { 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 adbea26b1..14331dfc1 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 @@ class ContainmentLinkRefiner extends AbstractPartialInterpretationRefiner { private final Factory factory; private final Interpretation interpretation; - private final PartialInterpretationRefiner sourceRefiner; - private final PartialInterpretationRefiner targetRefiner; + private PartialInterpretationRefiner sourceRefiner; + private PartialInterpretationRefiner targetRefiner; private ContainmentLinkRefiner(ReasoningAdapter adapter, PartialSymbol partialSymbol, Factory factory) { super(adapter, partialSymbol); this.factory = factory; interpretation = adapter.getModel().getInterpretation(factory.symbol); + } + + @Override + public void afterCreate() { + var adapter = getAdapter(); sourceRefiner = adapter.getRefiner(factory.sourceType); targetRefiner = adapter.getRefiner(factory.targetType); } 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 024774bc3..4e5029bf6 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 interpretation; - private final PartialInterpretationRefiner containerRefiner; - private final PartialInterpretationRefiner containedRefiner; + private PartialInterpretationRefiner containerRefiner; + private PartialInterpretationRefiner containedRefiner; private ContainsRefiner(ReasoningAdapter adapter, PartialSymbol partialSymbol, Symbol containsStorage) { super(adapter, partialSymbol); interpretation = adapter.getModel().getInterpretation(containsStorage); + } + + @Override + public void afterCreate() { + var adapter = getAdapter(); containerRefiner = adapter.getRefiner(ContainmentHierarchyTranslator.CONTAINER_SYMBOL); containedRefiner = adapter.getRefiner(ContainmentHierarchyTranslator.CONTAINED_SYMBOL); } 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 7cb16a282..000000000 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceInitializer.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.reasoning.translator.crossreference; - -import tools.refinery.store.model.Model; -import tools.refinery.store.reasoning.ReasoningAdapter; -import tools.refinery.store.reasoning.refinement.PartialModelInitializer; -import tools.refinery.store.reasoning.representation.PartialRelation; -import tools.refinery.store.reasoning.seed.ModelSeed; -import tools.refinery.store.representation.Symbol; -import tools.refinery.logic.term.truthvalue.TruthValue; -import tools.refinery.store.tuple.Tuple; - -class DirectedCrossReferenceInitializer implements PartialModelInitializer { - private final PartialRelation linkType; - private final PartialRelation sourceType; - private final PartialRelation targetType; - private final Symbol symbol; - - public DirectedCrossReferenceInitializer(PartialRelation linkType, PartialRelation sourceType, - PartialRelation targetType, Symbol symbol) { - this.linkType = linkType; - this.sourceType = sourceType; - this.targetType = targetType; - this.symbol = symbol; - } - - @Override - public void initialize(Model model, ModelSeed modelSeed) { - var reasoningAdapter = model.getAdapter(ReasoningAdapter.class); - var sourceRefiner = reasoningAdapter.getRefiner(sourceType); - var targetRefiner = reasoningAdapter.getRefiner(targetType); - var interpretation = model.getInterpretation(symbol); - var cursor = modelSeed.getCursor(linkType, symbol.defaultValue()); - while (cursor.move()) { - var key = cursor.getKey(); - var value = cursor.getValue(); - interpretation.put(key, value); - if (value.must()) { - boolean merged = sourceRefiner.merge(Tuple.of(key.get(0)), TruthValue.TRUE) && - targetRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE); - if (!merged) { - throw new IllegalArgumentException("Failed to merge end types of reference %s for key %s" - .formatted(linkType, key)); - } - } - } - } -} 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 75dd5dad3..4471b1938 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 @@ */ package tools.refinery.store.reasoning.translator.crossreference; +import tools.refinery.logic.term.truthvalue.TruthValue; import tools.refinery.store.reasoning.ReasoningAdapter; import tools.refinery.store.reasoning.refinement.ConcreteSymbolRefiner; import tools.refinery.store.reasoning.refinement.PartialInterpretationRefiner; import tools.refinery.store.reasoning.representation.PartialRelation; import tools.refinery.store.reasoning.representation.PartialSymbol; +import tools.refinery.store.reasoning.seed.ModelSeed; import tools.refinery.store.representation.Symbol; -import tools.refinery.logic.term.truthvalue.TruthValue; import tools.refinery.store.tuple.Tuple; class DirectedCrossReferenceRefiner extends ConcreteSymbolRefiner { + private final PartialRelation sourceType; private final PartialRelation targetType; - private final PartialInterpretationRefiner sourceRefiner; + private PartialInterpretationRefiner sourceRefiner; private PartialInterpretationRefiner targetRefiner; - public DirectedCrossReferenceRefiner(ReasoningAdapter adapter, PartialSymbol partialSymbol, - Symbol concreteSymbol, PartialRelation sourceType, - PartialRelation targetType) { + protected DirectedCrossReferenceRefiner(ReasoningAdapter adapter, PartialSymbol partialSymbol, + Symbol concreteSymbol, PartialRelation sourceType, + PartialRelation targetType) { super(adapter, partialSymbol, concreteSymbol); + this.sourceType = sourceType; this.targetType = targetType; - // Source is always a class, so we can rely on the fact that it is always constructed before this refiner. + } + + @Override + public void afterCreate() { + var adapter = getAdapter(); sourceRefiner = adapter.getRefiner(sourceType); + targetRefiner = adapter.getRefiner(targetType); } @Override @@ -34,16 +42,30 @@ public boolean merge(Tuple key, TruthValue value) { return false; } if (value.must()) { - if (targetRefiner == null) { - // Access the target refinery lazily, since it may be constructed after this refiner. - targetRefiner = getAdapter().getRefiner(targetType); - } return sourceRefiner.merge(Tuple.of(key.get(0)), TruthValue.TRUE) && targetRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE); } return true; } + @Override + public void afterInitialize(ModelSeed modelSeed) { + var linkType = getPartialSymbol(); + var cursor = modelSeed.getCursor(linkType); + while (cursor.move()) { + var value = cursor.getValue(); + if (value.must()) { + var key = cursor.getKey(); + boolean merged = sourceRefiner.merge(Tuple.of(key.get(0)), TruthValue.TRUE) && + targetRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE); + if (!merged) { + throw new IllegalArgumentException("Failed to merge end types of reference %s for key %s" + .formatted(linkType, key)); + } + } + } + } + public static Factory of(Symbol concreteSymbol, PartialRelation sourceType, PartialRelation targetType) { 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 d4c2afd25..c98971d96 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 void apply(ModelStoreBuilder storeBuilder) { var targetType = info.targetType(); var defaultValue = info.defaultValue(); if (defaultValue.must()) { - throw new TranslationException(linkType, "Unsupported default value %s for directed cross references %s" + throw new TranslationException(linkType, "Unsupported default value %s for directed cross reference %s" .formatted(defaultValue, linkType)); } var translator = PartialRelationTranslator.of(linkType); @@ -58,7 +58,6 @@ public void apply(ModelStoreBuilder storeBuilder) { configureWithDefaultFalse(storeBuilder); } translator.refiner(DirectedCrossReferenceRefiner.of(symbol, sourceType, targetType)); - translator.initializer(new DirectedCrossReferenceInitializer(linkType, sourceType, targetType, symbol)); if (info.partial()) { translator.roundingMode(RoundingMode.NONE); } 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 84dcfdc56..d0784c272 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 @@ package tools.refinery.store.reasoning.translator.crossreference; import org.jetbrains.annotations.NotNull; +import tools.refinery.logic.term.truthvalue.TruthValue; import tools.refinery.store.model.Model; -import tools.refinery.store.reasoning.ReasoningAdapter; import tools.refinery.store.reasoning.refinement.PartialModelInitializer; import tools.refinery.store.reasoning.representation.PartialRelation; import tools.refinery.store.reasoning.seed.ModelSeed; import tools.refinery.store.reasoning.translator.TranslationException; import tools.refinery.store.representation.Symbol; -import tools.refinery.logic.term.truthvalue.TruthValue; import tools.refinery.store.tuple.Tuple; import java.util.LinkedHashMap; class UndirectedCrossReferenceInitializer implements PartialModelInitializer { private final PartialRelation linkType; - private final PartialRelation sourceType; private final Symbol symbol; - UndirectedCrossReferenceInitializer(PartialRelation linkType, PartialRelation sourceType, - Symbol symbol) { + UndirectedCrossReferenceInitializer(PartialRelation linkType, Symbol symbol) { this.linkType = linkType; - this.sourceType = sourceType; this.symbol = symbol; } @Override public void initialize(Model model, ModelSeed modelSeed) { - var reasoningAdapter = model.getAdapter(ReasoningAdapter.class); var mergedMap = getMergedMap(modelSeed); - var sourceRefiner = reasoningAdapter.getRefiner(sourceType); var interpretation = model.getInterpretation(symbol); for (var entry : mergedMap.entrySet()) { var key = entry.getKey(); var value = entry.getValue(); interpretation.put(key, value); - if (value.must()) { - boolean merged = sourceRefiner.merge(Tuple.of(key.get(0)), TruthValue.TRUE) && - sourceRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE); - if (!merged) { - throw new IllegalArgumentException("Failed to merge end types of reference %s for key %s" - .formatted(linkType, key)); - } - } } } 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 54aca80f6..116ac7ad6 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 @@ */ package tools.refinery.store.reasoning.translator.crossreference; +import tools.refinery.logic.term.truthvalue.TruthValue; import tools.refinery.store.reasoning.ReasoningAdapter; import tools.refinery.store.reasoning.refinement.ConcreteSymbolRefiner; import tools.refinery.store.reasoning.refinement.PartialInterpretationRefiner; import tools.refinery.store.reasoning.representation.PartialRelation; import tools.refinery.store.reasoning.representation.PartialSymbol; +import tools.refinery.store.reasoning.seed.ModelSeed; import tools.refinery.store.representation.Symbol; -import tools.refinery.logic.term.truthvalue.TruthValue; import tools.refinery.store.tuple.Tuple; +import java.util.Objects; + class UndirectedCrossReferenceRefiner extends ConcreteSymbolRefiner { - private final PartialInterpretationRefiner sourceRefiner; + private final PartialRelation sourceType; + private PartialInterpretationRefiner sourceRefiner; - public UndirectedCrossReferenceRefiner(ReasoningAdapter adapter, PartialSymbol partialSymbol, - Symbol concreteSymbol, PartialRelation sourceType) { + protected UndirectedCrossReferenceRefiner(ReasoningAdapter adapter, + PartialSymbol partialSymbol, + Symbol concreteSymbol, PartialRelation sourceType) { super(adapter, partialSymbol, concreteSymbol); - sourceRefiner = adapter.getRefiner(sourceType); + this.sourceType = sourceType; + } + + @Override + public void afterCreate() { + sourceRefiner = getAdapter().getRefiner(sourceType); } @Override public boolean merge(Tuple key, TruthValue value) { int source = key.get(0); int target = key.get(1); - if (!super.merge(key, value) || !super.merge(Tuple.of(target, source), value)) { - return false; + var currentValue = get(key); + var mergedValue = currentValue.meet(value); + if (!Objects.equals(currentValue, mergedValue)) { + var oldValue = put(key, mergedValue); + if (source != target) { + var inverseOldValue = put(Tuple.of(target, source), mergedValue); + if (!Objects.equals(oldValue, inverseOldValue)) { + return false; + } + } } if (value.must()) { return sourceRefiner.merge(Tuple.of(source), TruthValue.TRUE) && @@ -37,6 +55,24 @@ public boolean merge(Tuple key, TruthValue value) { return true; } + @Override + public void afterInitialize(ModelSeed modelSeed) { + var linkType = getPartialSymbol(); + var cursor = modelSeed.getCursor(linkType); + while (cursor.move()) { + var value = cursor.getValue(); + if (value.must()) { + var key = cursor.getKey(); + boolean merged = sourceRefiner.merge(Tuple.of(key.get(0)), TruthValue.TRUE) && + sourceRefiner.merge(Tuple.of(key.get(1)), TruthValue.TRUE); + if (!merged) { + throw new IllegalArgumentException("Failed to merge end types of reference %s for key %s" + .formatted(linkType, key)); + } + } + } + } + public static Factory of(Symbol concreteSymbol, PartialRelation sourceType) { return (adapter, partialSymbol) -> new UndirectedCrossReferenceRefiner(adapter, partialSymbol, concreteSymbol, 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 494211fed..0de1deac2 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 void apply(ModelStoreBuilder storeBuilder) { var type = info.type(); var defaultValue = info.defaultValue(); if (defaultValue.must()) { - throw new TranslationException(linkType, "Unsupported default value %s for directed cross references %s" + throw new TranslationException(linkType, "Unsupported default value %s for undirected cross reference %s" .formatted(defaultValue, linkType)); } var translator = PartialRelationTranslator.of(linkType); @@ -54,8 +54,8 @@ public void apply(ModelStoreBuilder storeBuilder) { } else { configureWithDefaultFalse(storeBuilder); } + translator.initializer(new UndirectedCrossReferenceInitializer(linkType, symbol)); translator.refiner(UndirectedCrossReferenceRefiner.of(symbol, type)); - translator.initializer(new UndirectedCrossReferenceInitializer(linkType, type, symbol)); if (info.partial()) { translator.roundingMode(RoundingMode.NONE); } else { 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 000000000..fb4521dda --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/BasePredicateTranslator.java @@ -0,0 +1,143 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.reasoning.translator.predicate; + +import tools.refinery.logic.dnf.AbstractQueryBuilder; +import tools.refinery.logic.dnf.Query; +import tools.refinery.logic.literal.Literal; +import tools.refinery.logic.term.NodeVariable; +import tools.refinery.logic.term.truthvalue.TruthValue; +import tools.refinery.store.dse.propagation.PropagationBuilder; +import tools.refinery.store.dse.transition.Rule; +import tools.refinery.store.model.ModelStoreBuilder; +import tools.refinery.store.model.ModelStoreConfiguration; +import tools.refinery.store.query.view.ForbiddenView; +import tools.refinery.store.reasoning.lifting.DnfLifter; +import tools.refinery.store.reasoning.literal.Concreteness; +import tools.refinery.store.reasoning.literal.Modality; +import tools.refinery.store.reasoning.representation.PartialRelation; +import tools.refinery.store.reasoning.translator.PartialRelationTranslator; +import tools.refinery.store.reasoning.translator.RoundingMode; +import tools.refinery.store.reasoning.translator.TranslationException; +import tools.refinery.store.representation.Symbol; + +import java.util.ArrayList; +import java.util.List; + +import static tools.refinery.logic.literal.Literals.not; +import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add; +import static tools.refinery.store.reasoning.actions.PartialActionLiterals.remove; +import static tools.refinery.store.reasoning.literal.PartialLiterals.*; +import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.MULTI_VIEW; + +public class BasePredicateTranslator implements ModelStoreConfiguration { + private final PartialRelation predicate; + private final List parameterTypes; + private final TruthValue defaultValue; + private final boolean partial; + private final Symbol symbol; + + public BasePredicateTranslator(PartialRelation predicate, List parameterTypes, + TruthValue defaultValue, boolean partial) { + this.predicate = predicate; + this.parameterTypes = parameterTypes; + this.defaultValue = defaultValue; + this.partial = partial; + symbol = Symbol.of(predicate.name(), predicate.arity(), TruthValue.class, defaultValue); + } + + @Override + public void apply(ModelStoreBuilder storeBuilder) { + int arity = predicate.arity(); + if (arity != parameterTypes.size()) { + throw new TranslationException(predicate, + "Expected %d parameter type for base predicate %s, got %d instead" + .formatted(arity, predicate, parameterTypes.size())); + } + if (defaultValue.must()) { + throw new TranslationException(predicate, "Unsupported default value %s for base predicate %s" + .formatted(defaultValue, predicate)); + } + var translator = PartialRelationTranslator.of(predicate); + translator.symbol(symbol); + if (defaultValue.may()) { + configureWithDefaultUnknown(translator); + } else { + configureWithDefaultFalse(storeBuilder); + } + translator.refiner(PredicateRefiner.of(symbol, parameterTypes)); + if (partial) { + translator.roundingMode(RoundingMode.NONE); + } else { + translator.decision(Rule.of(predicate.name(), builder -> { + var parameters = createParameters(builder); + var literals = new ArrayList(arity + 2); + literals.add(may(predicate.call(parameters))); + literals.add(not(candidateMust(predicate.call(parameters)))); + for (int i = 0; i < arity; i++) { + literals.add(not(MULTI_VIEW.call(parameters[i]))); + } + builder.clause(literals); + builder.action(add(predicate, parameters)); + })); + } + storeBuilder.with(translator); + } + + private NodeVariable[] createParameters(AbstractQueryBuilder builder) { + int arity = predicate.arity(); + var parameters = new NodeVariable[arity]; + for (int i = 0; i < arity; i++) { + parameters[i] = builder.parameter("p" + (i + 1)); + } + return parameters; + } + + private void configureWithDefaultUnknown(PartialRelationTranslator translator) { + var name = predicate.name(); + var mayName = DnfLifter.decorateName(name, Modality.MAY, Concreteness.PARTIAL); + int arity = predicate.arity(); + var forbiddenView = new ForbiddenView(symbol); + translator.may(Query.of(mayName, builder -> { + var parameters = createParameters(builder); + var literals = new ArrayList(arity + 1); + for (int i = 0; i < arity; i++) { + literals.add(may(parameterTypes.get(i).call(parameters[i]))); + } + literals.add(not(forbiddenView.call(parameters))); + builder.clause(literals); + })); + if (partial) { + var candidateMayName = DnfLifter.decorateName(name, Modality.MAY, Concreteness.CANDIDATE); + translator.candidateMay(Query.of(candidateMayName, builder -> { + var parameters = createParameters(builder); + var literals = new ArrayList(arity + 1); + for (int i = 0; i < arity; i++) { + literals.add(candidateMay(parameterTypes.get(i).call(parameters[i]))); + } + literals.add(not(forbiddenView.call(parameters))); + builder.clause(literals); + })); + } + } + + private void configureWithDefaultFalse(ModelStoreBuilder storeBuilder) { + var name = predicate.name(); + // Fail if there is no {@link PropagationBuilder}, since it is required for soundness. + var propagationBuilder = storeBuilder.getAdapter(PropagationBuilder.class); + propagationBuilder.rule(Rule.of(name + "#invalid", builder -> { + var parameters = createParameters(builder); + int arity = parameters.length; + for (int i = 0; i < arity; i++) { + builder.clause( + may(predicate.call(parameters)), + not(may(parameterTypes.get(i).call(parameters[i]))) + ); + } + builder.action(remove(predicate, parameters)); + })); + } +} 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 000000000..0fccced25 --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/PredicateRefiner.java @@ -0,0 +1,94 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.reasoning.translator.predicate; + +import org.jetbrains.annotations.Nullable; +import tools.refinery.logic.term.truthvalue.TruthValue; +import tools.refinery.store.reasoning.ReasoningAdapter; +import tools.refinery.store.reasoning.refinement.ConcreteSymbolRefiner; +import tools.refinery.store.reasoning.refinement.PartialInterpretationRefiner; +import tools.refinery.store.reasoning.representation.PartialRelation; +import tools.refinery.store.reasoning.representation.PartialSymbol; +import tools.refinery.store.reasoning.seed.ModelSeed; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; + +import java.util.List; +import java.util.Objects; + +class PredicateRefiner extends ConcreteSymbolRefiner { + private final List parameterTypes; + private @Nullable PartialInterpretationRefiner[] parameterTypeRefiners; + + protected PredicateRefiner(ReasoningAdapter adapter, PartialSymbol partialSymbol, + Symbol concreteSymbol, List parameterTypes) { + super(adapter, partialSymbol, concreteSymbol); + this.parameterTypes = parameterTypes; + } + + @Override + public void afterCreate() { + int arity = parameterTypes.size(); + // Generic array creation. + @SuppressWarnings("unchecked") + PartialInterpretationRefiner[] array = new PartialInterpretationRefiner[arity]; + parameterTypeRefiners = array; + var adapter = getAdapter(); + for (int i = 0; i < arity; i++) { + var parameterType = parameterTypes.get(i); + if (parameterType != null) { + array[i] = adapter.getRefiner(parameterType); + } + } + } + + @Override + public boolean merge(Tuple key, TruthValue value) { + var currentValue = get(key); + var mergedValue = currentValue.meet(value); + if (!Objects.equals(currentValue, mergedValue)) { + put(key, mergedValue); + } + // Avoid cyclic propagation between parameter types by avoiding propagation after reaching a fixed point. + if (mergedValue.must() && !currentValue.must()) { + return refineParameters(key); + } + return true; + } + + @Override + public void afterInitialize(ModelSeed modelSeed) { + var predicate = getPartialSymbol(); + var cursor = modelSeed.getCursor(predicate); + while (cursor.move()) { + var value = cursor.getValue(); + if (value.must()) { + var key = cursor.getKey(); + if (!refineParameters(key)) { + throw new IllegalArgumentException("Failed to merge parameter types of predicate %s for key %s" + .formatted(predicate, key)); + } + } + } + } + + private boolean refineParameters(Tuple key) { + int arity = parameterTypeRefiners.length; + for (int i = 0; i < arity; i++) { + var refiner = parameterTypeRefiners[i]; + if (refiner != null && !refiner.merge(Tuple.of(key.get(i)), TruthValue.TRUE)) { + return false; + } + } + return true; + } + + public static Factory of(Symbol concreteSymbol, + List parameterTypes) { + return (adapter, partialSymbol) -> new PredicateRefiner(adapter, partialSymbol, concreteSymbol, + parameterTypes); + } +} 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 010ce9771..8dd9cff63 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.TranslationException; import tools.refinery.store.representation.Symbol; +import java.util.List; +import java.util.Objects; + import static tools.refinery.logic.literal.Literals.not; import static tools.refinery.store.reasoning.literal.PartialLiterals.may; import static tools.refinery.store.reasoning.literal.PartialLiterals.must; @@ -30,9 +33,11 @@ public class PredicateTranslator implements ModelStoreConfiguration { private final RelationalQuery query; private final boolean mutable; private final TruthValue defaultValue; + private final List parameterTypes; - public PredicateTranslator(PartialRelation relation, RelationalQuery query, boolean mutable, - TruthValue defaultValue) { + public PredicateTranslator(PartialRelation relation, RelationalQuery query, List parameterTypes, + boolean mutable, TruthValue defaultValue) { + this.parameterTypes = parameterTypes; if (relation.arity() != query.arity()) { throw new TranslationException(relation, "Expected arity %d query for partial relation %s, got %d instead" .formatted(relation.arity(), relation, query.arity())); @@ -78,6 +83,10 @@ public void apply(ModelStoreBuilder storeBuilder) { .clause(mayLiterals) .build(); translator.may(may); + + if (parameterTypes != null && parameterTypes.stream().anyMatch(Objects::nonNull)) { + translator.refiner(PredicateRefiner.of(symbol, parameterTypes)); + } } else if (defaultValue.may()) { // If all values are permitted, we don't need to check for any forbidden values in the model. // 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 000000000..08cc92359 --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/ShadowPredicateTranslator.java @@ -0,0 +1,71 @@ +/* + * SPDX-FileCopyrightText: 2024 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.reasoning.translator.predicate; + +import tools.refinery.logic.dnf.RelationalQuery; +import tools.refinery.logic.term.truthvalue.TruthValue; +import tools.refinery.store.map.Cursor; +import tools.refinery.store.model.ModelStoreBuilder; +import tools.refinery.store.model.ModelStoreConfiguration; +import tools.refinery.store.reasoning.ReasoningAdapter; +import tools.refinery.store.reasoning.ReasoningBuilder; +import tools.refinery.store.reasoning.interpretation.AbstractPartialInterpretation; +import tools.refinery.store.reasoning.interpretation.QueryBasedComputedRewriter; +import tools.refinery.store.reasoning.literal.Concreteness; +import tools.refinery.store.reasoning.literal.Modality; +import tools.refinery.store.reasoning.representation.PartialRelation; +import tools.refinery.store.reasoning.representation.PartialSymbol; +import tools.refinery.store.reasoning.translator.PartialRelationTranslator; +import tools.refinery.store.tuple.Tuple; + +public class ShadowPredicateTranslator implements ModelStoreConfiguration { + private final PartialRelation relation; + private final RelationalQuery query; + private final boolean hasInterpretation; + + public ShadowPredicateTranslator(PartialRelation relation, RelationalQuery query, boolean hasInterpretation) { + this.relation = relation; + this.query = query; + this.hasInterpretation = hasInterpretation; + } + + @Override + public void apply(ModelStoreBuilder storeBuilder) { + var reasoningBuilder = storeBuilder.getAdapter(ReasoningBuilder.class); + var may = reasoningBuilder.lift(Modality.MAY, Concreteness.PARTIAL, query); + var must = reasoningBuilder.lift(Modality.MAY, Concreteness.PARTIAL, query); + // Do not let {@link PartialRelationTranslator} merge the partial queries into the candidate ones. + var candidateMay = reasoningBuilder.lift(Modality.MAY, Concreteness.PARTIAL, query); + var candidateMust = reasoningBuilder.lift(Modality.MAY, Concreteness.PARTIAL, query); + var translator = PartialRelationTranslator.of(relation) + .rewriter(new QueryBasedComputedRewriter(may, must, candidateMay, candidateMust, query)); + if (!hasInterpretation) { + translator.interpretation(MissingInterpretation::new); + } + storeBuilder.with(translator); + } + + private static class MissingInterpretation extends AbstractPartialInterpretation { + public MissingInterpretation(ReasoningAdapter adapter, Concreteness concreteness, + PartialSymbol partialSymbol) { + super(adapter, concreteness, partialSymbol); + } + + @Override + public TruthValue get(Tuple key) { + return fail(); + } + + @Override + public Cursor getAll() { + return fail(); + } + + private T fail() { + throw new UnsupportedOperationException("No interpretation for shadow predicate: " + getPartialSymbol()); + } + } +} diff --git a/yarn.lock b/yarn.lock index a1993b47c..d8841bb64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1710,12 +1710,12 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.22.6, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.24.8, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7": - version: 7.24.8 - resolution: "@babel/runtime@npm:7.24.8" +"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.22.6, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.25.0, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7": + version: 7.25.0 + resolution: "@babel/runtime@npm:7.25.0" dependencies: regenerator-runtime: "npm:^0.14.0" - checksum: 10c0/f24b30af6b3ecae19165b3b032f9bc37b2d1769677bd63b69a6f81061967cfc847aa822518402ea6616b1d301d7eb46986b99c9f69cdb5880834fca2e6b34881 + checksum: 10c0/bd3faf246170826cef2071a94d7b47b49d532351360ecd17722d03f6713fd93a3eb3dbd9518faa778d5e8ccad7392a7a604e56bd37aaad3f3aa68d619ccd983d languageName: node linkType: hard @@ -1831,14 +1831,14 @@ __metadata: languageName: node linkType: hard -"@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0, @codemirror/view@npm:^6.29.0": - version: 6.29.0 - resolution: "@codemirror/view@npm:6.29.0" +"@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.17.0, @codemirror/view@npm:^6.23.0, @codemirror/view@npm:^6.27.0, @codemirror/view@npm:^6.29.1": + version: 6.29.1 + resolution: "@codemirror/view@npm:6.29.1" dependencies: "@codemirror/state": "npm:^6.4.0" style-mod: "npm:^4.1.0" w3c-keyname: "npm:^2.2.4" - checksum: 10c0/155b58bfe7de5c91a4dd3877cc2b23e1e2f796de0bf59d01c46c0797126e70052f819465b2467e1558b2cfaac25c9569b53eef09fcc5a1ae1a432ab8019e364f + checksum: 10c0/f5cc5aed853ab5c0ca2fcb3337b7332650bcbc403faddd436fd7d57bc811901b28fd505bd9301e067b2fefd7f36382f0f67977c2866b2b5b905c01e4ef666476 languageName: node linkType: hard @@ -3071,12 +3071,12 @@ __metadata: languageName: node linkType: hard -"@lezer/lr@npm:^1.0.0, @lezer/lr@npm:^1.3.0, @lezer/lr@npm:^1.4.1": - version: 1.4.1 - resolution: "@lezer/lr@npm:1.4.1" +"@lezer/lr@npm:^1.0.0, @lezer/lr@npm:^1.3.0, @lezer/lr@npm:^1.4.2": + version: 1.4.2 + resolution: "@lezer/lr@npm:1.4.2" dependencies: "@lezer/common": "npm:^1.0.0" - checksum: 10c0/e24a383c52248321035d8157d3271890a5740e7a324f7026f1cb7556d3bd9883edeb53df194a8a3f7de50ca034112b234e31211a6b235d9d8d7791a0319b1724 + checksum: 10c0/22bb5d0d4b33d0de5eb0706b7e5b5f2d20f570e112d9110009bd35b62ff10f2eb4eff8da4cf373dd4ddf5e06a304120b8f039add7ed9997c981c13945d5329cd languageName: node linkType: hard @@ -3130,16 +3130,16 @@ __metadata: languageName: node linkType: hard -"@mui/core-downloads-tracker@npm:^5.16.5": - version: 5.16.5 - resolution: "@mui/core-downloads-tracker@npm:5.16.5" - checksum: 10c0/f8052e42e0694b4c95b0edf1893325417ac76fbe9b7714ddad56f607f251d5edbdecf3e7ae34b28ecd7e6d9eee4d3f958d3ff743db98cb35d4e69eef30dd0e23 +"@mui/core-downloads-tracker@npm:^5.16.6": + version: 5.16.6 + resolution: "@mui/core-downloads-tracker@npm:5.16.6" + checksum: 10c0/ee7655eda56e8eeb18ae600b24182c10caab4468d33179de3e76a783a827be9577afe114750835f7c9c7f555c0de0845c0500e91ed2e669b16399a1ffe41c33d languageName: node linkType: hard -"@mui/icons-material@npm:^5.16.5": - version: 5.16.5 - resolution: "@mui/icons-material@npm:5.16.5" +"@mui/icons-material@npm:^5.16.6": + version: 5.16.6 + resolution: "@mui/icons-material@npm:5.16.6" dependencies: "@babel/runtime": "npm:^7.23.9" peerDependencies: @@ -3149,19 +3149,19 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/6ba9cbb5bc7a5d3fbc297683973c7c15c4a95f8b12cf55cadd069d4ecbaf5639bb9044da82ddc029c04203ee81a8ac691ea5ada769dc86fef3f25a13fcec44fe + checksum: 10c0/9d24d95e8b4606b5fa2a2e40319255e2e6da52845db50d2d3ca6fd526102be3c498ec1aa9be8d33aad52cf531749b15d490abca5f23af92afc86cf45dc62ce24 languageName: node linkType: hard -"@mui/material@npm:^5.16.5": - version: 5.16.5 - resolution: "@mui/material@npm:5.16.5" +"@mui/material@npm:^5.16.6": + version: 5.16.6 + resolution: "@mui/material@npm:5.16.6" dependencies: "@babel/runtime": "npm:^7.23.9" - "@mui/core-downloads-tracker": "npm:^5.16.5" - "@mui/system": "npm:^5.16.5" + "@mui/core-downloads-tracker": "npm:^5.16.6" + "@mui/system": "npm:^5.16.6" "@mui/types": "npm:^7.2.15" - "@mui/utils": "npm:^5.16.5" + "@mui/utils": "npm:^5.16.6" "@popperjs/core": "npm:^2.11.8" "@types/react-transition-group": "npm:^4.4.10" clsx: "npm:^2.1.0" @@ -3182,16 +3182,16 @@ __metadata: optional: true "@types/react": optional: true - checksum: 10c0/d147f4c0b8b7cb640da2c4e2511bb8a8dd4152caaf49dc4f380dc37bac4960722b30e7fc310f3339e34a560a3c873f764cac6c37295407ca1f771d4e0854febb + checksum: 10c0/52cbffd87a36b9f8e16ba59030e89501e680ddea4d3dcf3db5d8fb7b86205444b00162e656c79571824a74769f879f39df2e7671d1e7ca8bc23602a7bf588dc5 languageName: node linkType: hard -"@mui/private-theming@npm:^5.16.5": - version: 5.16.5 - resolution: "@mui/private-theming@npm:5.16.5" +"@mui/private-theming@npm:^5.16.6": + version: 5.16.6 + resolution: "@mui/private-theming@npm:5.16.6" dependencies: "@babel/runtime": "npm:^7.23.9" - "@mui/utils": "npm:^5.16.5" + "@mui/utils": "npm:^5.16.6" prop-types: "npm:^15.8.1" peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 @@ -3199,13 +3199,13 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/4850ff47b5a4b1b19356fbd30ed675db6f688eda02bebf16d8b23bebc67bd55baaf4fdba1acae7d5b5e6bbdc2ac0f01c1c85005886b1ba098df65a9b26d4d4c7 + checksum: 10c0/0a09afd6c2be37197973a856049f97e2f17f3e5e6cf6387af036055342efbfcd7d7066dcad587886f25f491e5940e4e9bb7d732d5099eb85b53b84ef120e9555 languageName: node linkType: hard -"@mui/styled-engine@npm:^5.16.4": - version: 5.16.4 - resolution: "@mui/styled-engine@npm:5.16.4" +"@mui/styled-engine@npm:^5.16.6": + version: 5.16.6 + resolution: "@mui/styled-engine@npm:5.16.6" dependencies: "@babel/runtime": "npm:^7.23.9" "@emotion/cache": "npm:^11.11.0" @@ -3220,19 +3220,19 @@ __metadata: optional: true "@emotion/styled": optional: true - checksum: 10c0/5dbd656aedfbf308dbbbb651a589c12b85ba1af2b6b351a657ee5af1210eab9629cee0781b2dc33b14b0a9482f7a6fa6e8b695d94f7cc5f1f7df7efe88034372 + checksum: 10c0/b15e653c8756059c8ae2891ca54900573e22f6ed1aaf65a389ec838f2aca3252aeeb9a79aec4a43f080152b161a416e60b31a62595ba86ad5f72eda5642caaf2 languageName: node linkType: hard -"@mui/system@npm:^5.16.5": - version: 5.16.5 - resolution: "@mui/system@npm:5.16.5" +"@mui/system@npm:^5.16.5, @mui/system@npm:^5.16.6": + version: 5.16.6 + resolution: "@mui/system@npm:5.16.6" dependencies: "@babel/runtime": "npm:^7.23.9" - "@mui/private-theming": "npm:^5.16.5" - "@mui/styled-engine": "npm:^5.16.4" + "@mui/private-theming": "npm:^5.16.6" + "@mui/styled-engine": "npm:^5.16.6" "@mui/types": "npm:^7.2.15" - "@mui/utils": "npm:^5.16.5" + "@mui/utils": "npm:^5.16.6" clsx: "npm:^2.1.0" csstype: "npm:^3.1.3" prop-types: "npm:^15.8.1" @@ -3248,7 +3248,7 @@ __metadata: optional: true "@types/react": optional: true - checksum: 10c0/af3eccfa96e78e00a8b5a71c025b57baeb85b02adb44a7e1e96779ddcb3f0070d9880dcb6b8a7bdb78339fa1bbf892b63ef80b81d0497c9bbd45f5ea14958c91 + checksum: 10c0/493900594f51d1fc84994042e5cfa000b2d7664f86c8c0d62b87dbbb51cf7e789a700512f98e18c82e605beab38c20d0714ec25c46e2f6a5024f79f16db743f7 languageName: node linkType: hard @@ -3264,9 +3264,9 @@ __metadata: languageName: node linkType: hard -"@mui/utils@npm:^5.16.5": - version: 5.16.5 - resolution: "@mui/utils@npm:5.16.5" +"@mui/utils@npm:^5.16.5, @mui/utils@npm:^5.16.6": + version: 5.16.6 + resolution: "@mui/utils@npm:5.16.6" dependencies: "@babel/runtime": "npm:^7.23.9" "@mui/types": "npm:^7.2.15" @@ -3280,18 +3280,18 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/8b51190232c192db7dfd9fd33e054a789bf162d7ccfb40ee21d6b2636f07aa69d60e3f5bdc6ded1b3520fa4f93134101a5c4158772f589e56eff3a04f1a59a10 + checksum: 10c0/2db3d11a83d7216fb8ceb459d4b30c795922c04cd8fabc26c721dd7b4f5ed5c4f3f3ace6ea70227bf3b79361bd58f13b723562cfd40255424d979ab238ab2e91 languageName: node linkType: hard -"@mui/x-data-grid@npm:^7.11.1": - version: 7.11.1 - resolution: "@mui/x-data-grid@npm:7.11.1" +"@mui/x-data-grid@npm:^7.12.0": + version: 7.12.0 + resolution: "@mui/x-data-grid@npm:7.12.0" dependencies: - "@babel/runtime": "npm:^7.24.8" + "@babel/runtime": "npm:^7.25.0" "@mui/system": "npm:^5.16.5" "@mui/utils": "npm:^5.16.5" - "@mui/x-internals": "npm:7.11.1" + "@mui/x-internals": "npm:7.12.0" clsx: "npm:^2.1.1" prop-types: "npm:^15.8.1" reselect: "npm:^4.1.8" @@ -3299,19 +3299,19 @@ __metadata: "@mui/material": ^5.15.14 react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 - checksum: 10c0/c7bec9c6c9629a8f0d727b3be158eb0835efa6dcb966327ab56608c21147bf5ce4029688b55ce4dcf8c470926942ebc2b8deffed587c621c6dab5a07bb589234 + checksum: 10c0/4ff36033c5fdfa9bcfe70b62e4432e61d204033c999da89590f15afd61f9315a3c35e71628e5d5b7fb4bde7b6686e3230e5754846733ade8b100cda6873bc9fc languageName: node linkType: hard -"@mui/x-internals@npm:7.11.1": - version: 7.11.1 - resolution: "@mui/x-internals@npm:7.11.1" +"@mui/x-internals@npm:7.12.0": + version: 7.12.0 + resolution: "@mui/x-internals@npm:7.12.0" dependencies: - "@babel/runtime": "npm:^7.24.8" + "@babel/runtime": "npm:^7.25.0" "@mui/utils": "npm:^5.16.5" peerDependencies: react: ^17.0.0 || ^18.0.0 - checksum: 10c0/003c325accee117d0037273088d042a1122b4ec27f752847fede68d384d1b77024a6c5b1aa9d642a9757737c7ece79bba494a1325a37c13ce6c11b5a653c116a + checksum: 10c0/7fcb5a7785936c4cee7c8900a639523b0e04257b1ea54383886652801eeb09993a7ecae2fc6a06a699edc68108b82c1b968a56ec916f4530d6fdcfa7009b6d8a languageName: node linkType: hard @@ -3427,10 +3427,10 @@ __metadata: "@fontsource/open-sans": "npm:^5.0.28" "@material-icons/svg": "npm:^1.0.33" "@mdx-js/react": "npm:^3.0.1" - "@swc/core": "npm:^1.7.2" + "@swc/core": "npm:^1.7.5" "@types/babel__core": "npm:^7.20.5" "@types/mdast": "npm:^4.0.4" - "@types/node": "npm:^20.14.12" + "@types/node": "npm:^20.14.14" "@types/react": "npm:^18.3.3" "@types/react-dom": "npm:^18.3.0" "@types/unist": "npm:^3.0.2" @@ -3463,7 +3463,7 @@ __metadata: "@codemirror/lint": "npm:^6.8.1" "@codemirror/search": "npm:^6.5.6" "@codemirror/state": "npm:^6.4.1" - "@codemirror/view": "npm:^6.29.0" + "@codemirror/view": "npm:^6.29.1" "@emotion/cache": "npm:^11.13.1" "@emotion/react": "npm:^11.13.0" "@emotion/serialize": "npm:^1.3.0" @@ -3476,12 +3476,12 @@ __metadata: "@lezer/common": "npm:^1.2.1" "@lezer/generator": "npm:^1.7.1" "@lezer/highlight": "npm:^1.2.0" - "@lezer/lr": "npm:^1.4.1" + "@lezer/lr": "npm:^1.4.2" "@material-icons/svg": "npm:^1.0.33" - "@mui/icons-material": "npm:^5.16.5" - "@mui/material": "npm:^5.16.5" - "@mui/system": "npm:^5.16.5" - "@mui/x-data-grid": "npm:^7.11.1" + "@mui/icons-material": "npm:^5.16.6" + "@mui/material": "npm:^5.16.6" + "@mui/system": "npm:^5.16.6" + "@mui/x-data-grid": "npm:^7.12.0" "@types/d3": "npm:^7.4.3" "@types/d3-color": "npm:^3.1.3" "@types/d3-graphviz": "npm:^2.6.10" @@ -3492,7 +3492,7 @@ __metadata: "@types/lodash-es": "npm:^4.17.12" "@types/micromatch": "npm:^4.0.9" "@types/ms": "npm:^0.7.34" - "@types/node": "npm:^20.14.12" + "@types/node": "npm:^20.14.14" "@types/pnpapi": "npm:^0.0.5" "@types/react": "npm:^18.3.3" "@types/react-dom": "npm:^18.3.0" @@ -3536,10 +3536,10 @@ __metadata: resolution: "@refinery/root@workspace:." dependencies: "@types/eslint": "npm:^8.56.11" - "@types/node": "npm:^20.14.12" + "@types/node": "npm:^20.14.14" "@types/react": "npm:^18.3.3" - "@typescript-eslint/eslint-plugin": "npm:^7.17.0" - "@typescript-eslint/parser": "npm:^7.17.0" + "@typescript-eslint/eslint-plugin": "npm:^7.18.0" + "@typescript-eslint/parser": "npm:^7.18.0" corepack: "npm:^0.29.3" eslint: "npm:^8.57.0" eslint-config-airbnb: "npm:^19.0.4" @@ -3979,90 +3979,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.7.2": - version: 1.7.2 - resolution: "@swc/core-darwin-arm64@npm:1.7.2" +"@swc/core-darwin-arm64@npm:1.7.5": + version: 1.7.5 + resolution: "@swc/core-darwin-arm64@npm:1.7.5" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.7.2": - version: 1.7.2 - resolution: "@swc/core-darwin-x64@npm:1.7.2" +"@swc/core-darwin-x64@npm:1.7.5": + version: 1.7.5 + resolution: "@swc/core-darwin-x64@npm:1.7.5" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.7.2": - version: 1.7.2 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.7.2" +"@swc/core-linux-arm-gnueabihf@npm:1.7.5": + version: 1.7.5 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.7.5" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.7.2": - version: 1.7.2 - resolution: "@swc/core-linux-arm64-gnu@npm:1.7.2" +"@swc/core-linux-arm64-gnu@npm:1.7.5": + version: 1.7.5 + resolution: "@swc/core-linux-arm64-gnu@npm:1.7.5" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.7.2": - version: 1.7.2 - resolution: "@swc/core-linux-arm64-musl@npm:1.7.2" +"@swc/core-linux-arm64-musl@npm:1.7.5": + version: 1.7.5 + resolution: "@swc/core-linux-arm64-musl@npm:1.7.5" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.7.2": - version: 1.7.2 - resolution: "@swc/core-linux-x64-gnu@npm:1.7.2" +"@swc/core-linux-x64-gnu@npm:1.7.5": + version: 1.7.5 + resolution: "@swc/core-linux-x64-gnu@npm:1.7.5" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.7.2": - version: 1.7.2 - resolution: "@swc/core-linux-x64-musl@npm:1.7.2" +"@swc/core-linux-x64-musl@npm:1.7.5": + version: 1.7.5 + resolution: "@swc/core-linux-x64-musl@npm:1.7.5" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.7.2": - version: 1.7.2 - resolution: "@swc/core-win32-arm64-msvc@npm:1.7.2" +"@swc/core-win32-arm64-msvc@npm:1.7.5": + version: 1.7.5 + resolution: "@swc/core-win32-arm64-msvc@npm:1.7.5" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.7.2": - version: 1.7.2 - resolution: "@swc/core-win32-ia32-msvc@npm:1.7.2" +"@swc/core-win32-ia32-msvc@npm:1.7.5": + version: 1.7.5 + resolution: "@swc/core-win32-ia32-msvc@npm:1.7.5" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.7.2": - version: 1.7.2 - resolution: "@swc/core-win32-x64-msvc@npm:1.7.2" +"@swc/core-win32-x64-msvc@npm:1.7.5": + version: 1.7.5 + resolution: "@swc/core-win32-x64-msvc@npm:1.7.5" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@swc/core@npm:^1.5.7, @swc/core@npm:^1.7.2": - version: 1.7.2 - resolution: "@swc/core@npm:1.7.2" +"@swc/core@npm:^1.5.7, @swc/core@npm:^1.7.5": + version: 1.7.5 + resolution: "@swc/core@npm:1.7.5" dependencies: - "@swc/core-darwin-arm64": "npm:1.7.2" - "@swc/core-darwin-x64": "npm:1.7.2" - "@swc/core-linux-arm-gnueabihf": "npm:1.7.2" - "@swc/core-linux-arm64-gnu": "npm:1.7.2" - "@swc/core-linux-arm64-musl": "npm:1.7.2" - "@swc/core-linux-x64-gnu": "npm:1.7.2" - "@swc/core-linux-x64-musl": "npm:1.7.2" - "@swc/core-win32-arm64-msvc": "npm:1.7.2" - "@swc/core-win32-ia32-msvc": "npm:1.7.2" - "@swc/core-win32-x64-msvc": "npm:1.7.2" + "@swc/core-darwin-arm64": "npm:1.7.5" + "@swc/core-darwin-x64": "npm:1.7.5" + "@swc/core-linux-arm-gnueabihf": "npm:1.7.5" + "@swc/core-linux-arm64-gnu": "npm:1.7.5" + "@swc/core-linux-arm64-musl": "npm:1.7.5" + "@swc/core-linux-x64-gnu": "npm:1.7.5" + "@swc/core-linux-x64-musl": "npm:1.7.5" + "@swc/core-win32-arm64-msvc": "npm:1.7.5" + "@swc/core-win32-ia32-msvc": "npm:1.7.5" + "@swc/core-win32-x64-msvc": "npm:1.7.5" "@swc/counter": "npm:^0.1.3" "@swc/types": "npm:^0.1.12" peerDependencies: @@ -4091,7 +4091,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 10c0/fa07d7fce91a36554b468af9eceba599b94d2ae68a6a3756566bc03a33726f994ba6be419b8f50d543950442e8caa41738d547a9d2ee41d11f65332d6f6f6cb1 + checksum: 10c0/06fcd863348da77dc27dbd66e89bab5f37e391a41afdf044df7ba98639f4b49221fb40c8cd503508ac282ed002d90eb8203abaa02c3f1e4ba04b2f7509628484 languageName: node linkType: hard @@ -4811,12 +4811,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:^20.14.12": - version: 20.14.12 - resolution: "@types/node@npm:20.14.12" +"@types/node@npm:*, @types/node@npm:^20.14.14": + version: 20.14.14 + resolution: "@types/node@npm:20.14.14" dependencies: undici-types: "npm:~5.26.4" - checksum: 10c0/59bc5fa11fdd23fd517f859063118f54a1ab53d3399ef63c926f8902429d7453abc0db22ef4b0a6110026b6ab81b6472fee894e1d235c24b01a0b3e10cfae0bb + checksum: 10c0/4fc8d368df2b6f5497698327b30db68d7d20e32221ce7d057fb15cbd5834685b2fde0440609e4cb2204e5d305b928f008faf41b950a425f3fd55b60cb1b997cf languageName: node linkType: hard @@ -5053,15 +5053,15 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^7.17.0": - version: 7.17.0 - resolution: "@typescript-eslint/eslint-plugin@npm:7.17.0" +"@typescript-eslint/eslint-plugin@npm:^7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/eslint-plugin@npm:7.18.0" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:7.17.0" - "@typescript-eslint/type-utils": "npm:7.17.0" - "@typescript-eslint/utils": "npm:7.17.0" - "@typescript-eslint/visitor-keys": "npm:7.17.0" + "@typescript-eslint/scope-manager": "npm:7.18.0" + "@typescript-eslint/type-utils": "npm:7.18.0" + "@typescript-eslint/utils": "npm:7.18.0" + "@typescript-eslint/visitor-keys": "npm:7.18.0" graphemer: "npm:^1.4.0" ignore: "npm:^5.3.1" natural-compare: "npm:^1.4.0" @@ -5072,44 +5072,44 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/654d589531ae45b8ca8f3969e785926b2544100a985968d86c828e2a1ff50331250e19c8b4af83a4ba17847a0047479662eb317e4ad94f6279cac03acd5cda5a + checksum: 10c0/2b37948fa1b0dab77138909dabef242a4d49ab93e4019d4ef930626f0a7d96b03e696cd027fa0087881c20e73be7be77c942606b4a76fa599e6b37f6985304c3 languageName: node linkType: hard -"@typescript-eslint/parser@npm:^7.17.0": - version: 7.17.0 - resolution: "@typescript-eslint/parser@npm:7.17.0" +"@typescript-eslint/parser@npm:^7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/parser@npm:7.18.0" dependencies: - "@typescript-eslint/scope-manager": "npm:7.17.0" - "@typescript-eslint/types": "npm:7.17.0" - "@typescript-eslint/typescript-estree": "npm:7.17.0" - "@typescript-eslint/visitor-keys": "npm:7.17.0" + "@typescript-eslint/scope-manager": "npm:7.18.0" + "@typescript-eslint/types": "npm:7.18.0" + "@typescript-eslint/typescript-estree": "npm:7.18.0" + "@typescript-eslint/visitor-keys": "npm:7.18.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/0cf6922412517b4c005609b035119ddd2798e1b6e74e1bccd487aa53119d27067cfd89311f00b8e96b2b044a0fb7373418a16552be86079879158b260c397418 + checksum: 10c0/370e73fca4278091bc1b657f85e7d74cd52b24257ea20c927a8e17546107ce04fbf313fec99aed0cc2a145ddbae1d3b12e9cc2c1320117636dc1281bcfd08059 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:7.17.0": - version: 7.17.0 - resolution: "@typescript-eslint/scope-manager@npm:7.17.0" +"@typescript-eslint/scope-manager@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/scope-manager@npm:7.18.0" dependencies: - "@typescript-eslint/types": "npm:7.17.0" - "@typescript-eslint/visitor-keys": "npm:7.17.0" - checksum: 10c0/e1a693e19dc855fe6d04b46c6c205019bfc937eda5f8b255393f8267ebddd282165568336e37b04aab544b155a807784b9c4a92129dfc7c1eef5a9e9fe052685 + "@typescript-eslint/types": "npm:7.18.0" + "@typescript-eslint/visitor-keys": "npm:7.18.0" + checksum: 10c0/038cd58c2271de146b3a594afe2c99290034033326d57ff1f902976022c8b0138ffd3cb893ae439ae41003b5e4bcc00cabf6b244ce40e8668f9412cc96d97b8e languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:7.17.0": - version: 7.17.0 - resolution: "@typescript-eslint/type-utils@npm:7.17.0" +"@typescript-eslint/type-utils@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/type-utils@npm:7.18.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:7.17.0" - "@typescript-eslint/utils": "npm:7.17.0" + "@typescript-eslint/typescript-estree": "npm:7.18.0" + "@typescript-eslint/utils": "npm:7.18.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.3.0" peerDependencies: @@ -5117,23 +5117,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/b415cf37c0922cded78735c5049cb5a5b0065e1c0ce4a81ca2a26422763ccacca8945efa45480f40530f2ec414a14d35a88a6798258aa889f7a9cf4ca4a240cd + checksum: 10c0/ad92a38007be620f3f7036f10e234abdc2fdc518787b5a7227e55fd12896dacf56e8b34578723fbf9bea8128df2510ba8eb6739439a3879eda9519476d5783fd languageName: node linkType: hard -"@typescript-eslint/types@npm:7.17.0": - version: 7.17.0 - resolution: "@typescript-eslint/types@npm:7.17.0" - checksum: 10c0/8f734294d432b37c534f17eb2befdfe43b76874d09118d6adf7e308e5a586e9e11b7021abe4f6692a6e6226de58a15b3cfe1300939556ce1c908d9af627b7400 +"@typescript-eslint/types@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/types@npm:7.18.0" + checksum: 10c0/eb7371ac55ca77db8e59ba0310b41a74523f17e06f485a0ef819491bc3dd8909bb930120ff7d30aaf54e888167e0005aa1337011f3663dc90fb19203ce478054 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:7.17.0": - version: 7.17.0 - resolution: "@typescript-eslint/typescript-estree@npm:7.17.0" +"@typescript-eslint/typescript-estree@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/typescript-estree@npm:7.18.0" dependencies: - "@typescript-eslint/types": "npm:7.17.0" - "@typescript-eslint/visitor-keys": "npm:7.17.0" + "@typescript-eslint/types": "npm:7.18.0" + "@typescript-eslint/visitor-keys": "npm:7.18.0" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" @@ -5143,31 +5143,31 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/10967823ce00c9f8cd4a8b56bed3524c098e38cc0e27aaa49ffd8fad4e671c00226bf0330ba858948750b88dc55527ebeb62c74be8a30bac18a106d6c033ab59 + checksum: 10c0/0c7f109a2e460ec8a1524339479cf78ff17814d23c83aa5112c77fb345e87b3642616291908dcddea1e671da63686403dfb712e4a4435104f92abdfddf9aba81 languageName: node linkType: hard -"@typescript-eslint/utils@npm:7.17.0": - version: 7.17.0 - resolution: "@typescript-eslint/utils@npm:7.17.0" +"@typescript-eslint/utils@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/utils@npm:7.18.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" - "@typescript-eslint/scope-manager": "npm:7.17.0" - "@typescript-eslint/types": "npm:7.17.0" - "@typescript-eslint/typescript-estree": "npm:7.17.0" + "@typescript-eslint/scope-manager": "npm:7.18.0" + "@typescript-eslint/types": "npm:7.18.0" + "@typescript-eslint/typescript-estree": "npm:7.18.0" peerDependencies: eslint: ^8.56.0 - checksum: 10c0/1f3e22820b3ab3e47809c45e576614ad4a965f5c8634856eca5c70981386b9351a77fb172ba32345e7c5667479cf9526c673699dd38dccd0616ad6db21704e72 + checksum: 10c0/a25a6d50eb45c514469a01ff01f215115a4725fb18401055a847ddf20d1b681409c4027f349033a95c4ff7138d28c3b0a70253dfe8262eb732df4b87c547bd1e languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:7.17.0": - version: 7.17.0 - resolution: "@typescript-eslint/visitor-keys@npm:7.17.0" +"@typescript-eslint/visitor-keys@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/visitor-keys@npm:7.18.0" dependencies: - "@typescript-eslint/types": "npm:7.17.0" + "@typescript-eslint/types": "npm:7.18.0" eslint-visitor-keys: "npm:^3.4.3" - checksum: 10c0/fa6b339d51fc3710288bb2ffaa46d639551d77965cc42c36f96c4f43aed663ff12972e8a28652a280f6ce20b7a92dc2aea14b2b4049012799be2fc2d3cbb2c60 + checksum: 10c0/538b645f8ff1d9debf264865c69a317074eaff0255e63d7407046176b0f6a6beba34a6c51d511f12444bae12a98c69891eb6f403c9f54c6c2e2849d1c1cb73c0 languageName: node linkType: hard @@ -6280,9 +6280,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001587, caniuse-lite@npm:^1.0.30001599": - version: 1.0.30001643 - resolution: "caniuse-lite@npm:1.0.30001643" - checksum: 10c0/7fcd0fd180bbe6764311ad57b0d39c23afdcc3bb1d8f804e7a76752c62a85b1bb7cf74b672d9da2f0afe7ad75336ff811a6fe279eb2a54bc04c272b6b62e57f1 + version: 1.0.30001646 + resolution: "caniuse-lite@npm:1.0.30001646" + checksum: 10c0/ecdd87c08cd63fa32e11311dfa3543a52613b0b99498b6fe6f2c66af65cc27e2f7436fa5b2bc2bcf72174448a7670715b284d420de838bcf3e811864371a2465 languageName: node linkType: hard