aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-reasoning/src/main
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-07-20 20:41:23 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-07-20 20:41:23 +0200
commitd1ba7d2e4ed0803832c23f2919b2fd7c14c02d8f (patch)
treed74f5c3d33207347e9563e87ac534f2b82c50d6a /subprojects/store-reasoning/src/main
parentfeat: multi-object based EQUALS and EXISTS (diff)
downloadrefinery-d1ba7d2e4ed0803832c23f2919b2fd7c14c02d8f.tar.gz
refinery-d1ba7d2e4ed0803832c23f2919b2fd7c14c02d8f.tar.zst
refinery-d1ba7d2e4ed0803832c23f2919b2fd7c14c02d8f.zip
feat: partial interpretation for type hierarchy
Diffstat (limited to 'subprojects/store-reasoning/src/main')
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/proxy/PartialRelationTranslatorProxy.java52
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/CandidateTypeView.java21
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/EliminatedType.java11
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredType.java8
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeRefiner.java38
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeView.java35
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/MayTypeView.java21
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/MustTypeView.java21
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/PreservedType.java141
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisResult.java134
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchy.java (renamed from subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzer.java)54
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyBuilder.java62
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyInitializer.java57
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslator.java81
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeInfo.java38
15 files changed, 565 insertions, 209 deletions
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/proxy/PartialRelationTranslatorProxy.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/proxy/PartialRelationTranslatorProxy.java
new file mode 100644
index 00000000..45dc5bd2
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/proxy/PartialRelationTranslatorProxy.java
@@ -0,0 +1,52 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.proxy;
7
8import tools.refinery.store.model.ModelStoreBuilder;
9import tools.refinery.store.model.ModelStoreConfiguration;
10import tools.refinery.store.query.literal.AbstractCallLiteral;
11import tools.refinery.store.query.literal.Literal;
12import tools.refinery.store.query.term.Variable;
13import tools.refinery.store.reasoning.interpretation.PartialRelationRewriter;
14import tools.refinery.store.reasoning.literal.Concreteness;
15import tools.refinery.store.reasoning.literal.ModalConstraint;
16import tools.refinery.store.reasoning.literal.Modality;
17import tools.refinery.store.reasoning.representation.PartialRelation;
18import tools.refinery.store.reasoning.translator.PartialRelationTranslator;
19
20import java.util.List;
21import java.util.Set;
22
23public class PartialRelationTranslatorProxy implements ModelStoreConfiguration, PartialRelationRewriter {
24 private final PartialRelation partialRelation;
25 private final PartialRelation targetRelation;
26 private final boolean mutable;
27
28 public PartialRelationTranslatorProxy(PartialRelation partialRelation, PartialRelation targetRelation,
29 boolean mutable) {
30 this.partialRelation = partialRelation;
31 this.targetRelation = targetRelation;
32 this.mutable = mutable;
33 }
34
35 @Override
36 public void apply(ModelStoreBuilder storeBuilder) {
37 var translator = PartialRelationTranslator.of(partialRelation)
38 .interpretation(((adapter, concreteness, partialSymbol) ->
39 adapter.getPartialInterpretation(concreteness, targetRelation)))
40 .rewriter(this);
41 if (mutable) {
42 translator.refiner((adapter, partialSymbol) -> adapter.getRefiner(targetRelation));
43 }
44 storeBuilder.with(translator);
45 }
46
47 @Override
48 public List<Literal> rewriteLiteral(Set<Variable> positiveVariables, AbstractCallLiteral literal,
49 Modality modality, Concreteness concreteness) {
50 return List.of(literal.withTarget(ModalConstraint.of(modality, concreteness, targetRelation)));
51 }
52}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/CandidateTypeView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/CandidateTypeView.java
new file mode 100644
index 00000000..faf1b958
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/CandidateTypeView.java
@@ -0,0 +1,21 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.typehierarchy;
7
8import tools.refinery.store.reasoning.representation.PartialRelation;
9import tools.refinery.store.representation.Symbol;
10import tools.refinery.store.tuple.Tuple;
11
12class CandidateTypeView extends InferredTypeView {
13 public CandidateTypeView(Symbol<InferredType> symbol, PartialRelation type) {
14 super(symbol, "candidate", type);
15 }
16
17 @Override
18 protected boolean doFilter(Tuple key, InferredType value) {
19 return type.equals(value.candidateType());
20 }
21}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/EliminatedType.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/EliminatedType.java
deleted file mode 100644
index 6e4728db..00000000
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/EliminatedType.java
+++ /dev/null
@@ -1,11 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.typehierarchy;
7
8import tools.refinery.store.reasoning.representation.PartialRelation;
9
10record EliminatedType(PartialRelation replacement) implements TypeAnalysisResult {
11}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredType.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredType.java
index fd05158b..1ae94ae1 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredType.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredType.java
@@ -11,18 +11,18 @@ import java.util.Collections;
11import java.util.Set; 11import java.util.Set;
12 12
13record InferredType(Set<PartialRelation> mustTypes, Set<PartialRelation> mayConcreteTypes, 13record InferredType(Set<PartialRelation> mustTypes, Set<PartialRelation> mayConcreteTypes,
14 PartialRelation currentType) { 14 PartialRelation candidateType) {
15 public static final InferredType UNTYPED = new InferredType(Set.of(), Set.of(), null); 15 public static final InferredType UNTYPED = new InferredType(Set.of(), Set.of(), null);
16 16
17 public InferredType(Set<PartialRelation> mustTypes, Set<PartialRelation> mayConcreteTypes, 17 public InferredType(Set<PartialRelation> mustTypes, Set<PartialRelation> mayConcreteTypes,
18 PartialRelation currentType) { 18 PartialRelation candidateType) {
19 this.mustTypes = Collections.unmodifiableSet(mustTypes); 19 this.mustTypes = Collections.unmodifiableSet(mustTypes);
20 this.mayConcreteTypes = Collections.unmodifiableSet(mayConcreteTypes); 20 this.mayConcreteTypes = Collections.unmodifiableSet(mayConcreteTypes);
21 this.currentType = currentType; 21 this.candidateType = candidateType;
22 } 22 }
23 23
24 public boolean isConsistent() { 24 public boolean isConsistent() {
25 return currentType != null || mustTypes.isEmpty(); 25 return candidateType != null || mustTypes.isEmpty();
26 } 26 }
27 27
28 public boolean isMust(PartialRelation partialRelation) { 28 public boolean isMust(PartialRelation partialRelation) {
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeRefiner.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeRefiner.java
new file mode 100644
index 00000000..40a7b3fa
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeRefiner.java
@@ -0,0 +1,38 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.typehierarchy;
7
8import tools.refinery.store.model.Interpretation;
9import tools.refinery.store.reasoning.ReasoningAdapter;
10import tools.refinery.store.reasoning.refinement.AbstractPartialInterpretationRefiner;
11import tools.refinery.store.reasoning.representation.PartialSymbol;
12import tools.refinery.store.representation.Symbol;
13import tools.refinery.store.representation.TruthValue;
14import tools.refinery.store.tuple.Tuple;
15
16class InferredTypeRefiner extends AbstractPartialInterpretationRefiner<TruthValue, Boolean> {
17 private final Interpretation<InferredType> interpretation;
18 private final TypeAnalysisResult result;
19
20 private InferredTypeRefiner(ReasoningAdapter adapter, PartialSymbol<TruthValue, Boolean> partialSymbol,
21 Symbol<InferredType> symbol, TypeAnalysisResult result) {
22 super(adapter, partialSymbol);
23 interpretation = adapter.getModel().getInterpretation(symbol);
24 this.result = result;
25 }
26
27 @Override
28 public boolean merge(Tuple key, TruthValue value) {
29 var currentType = interpretation.get(key);
30 var newType = result.merge(currentType, value);
31 interpretation.put(key, newType);
32 return true;
33 }
34
35 public static Factory<TruthValue, Boolean> of(Symbol<InferredType> symbol, TypeAnalysisResult result) {
36 return (adapter, partialSymbol) -> new InferredTypeRefiner(adapter, partialSymbol, symbol, result);
37 }
38}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeView.java
new file mode 100644
index 00000000..3c074df5
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeView.java
@@ -0,0 +1,35 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.typehierarchy;
7
8import tools.refinery.store.query.view.TuplePreservingView;
9import tools.refinery.store.reasoning.representation.PartialRelation;
10import tools.refinery.store.representation.Symbol;
11
12import java.util.Objects;
13
14abstract class InferredTypeView extends TuplePreservingView<InferredType> {
15 protected final PartialRelation type;
16
17 protected InferredTypeView(Symbol<InferredType> symbol, String name, PartialRelation type) {
18 super(symbol, type.name() + "#" + name);
19 this.type = type;
20 }
21
22 @Override
23 public boolean equals(Object o) {
24 if (this == o) return true;
25 if (o == null || getClass() != o.getClass()) return false;
26 if (!super.equals(o)) return false;
27 InferredTypeView that = (InferredTypeView) o;
28 return Objects.equals(type, that.type);
29 }
30
31 @Override
32 public int hashCode() {
33 return Objects.hash(super.hashCode(), type);
34 }
35}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/MayTypeView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/MayTypeView.java
new file mode 100644
index 00000000..dcaf61c5
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/MayTypeView.java
@@ -0,0 +1,21 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.typehierarchy;
7
8import tools.refinery.store.reasoning.representation.PartialRelation;
9import tools.refinery.store.representation.Symbol;
10import tools.refinery.store.tuple.Tuple;
11
12class MayTypeView extends InferredTypeView {
13 public MayTypeView(Symbol<InferredType> symbol, PartialRelation type) {
14 super(symbol, "may", type);
15 }
16
17 @Override
18 protected boolean doFilter(Tuple key, InferredType value) {
19 return value.mayConcreteTypes().contains(type);
20 }
21}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/MustTypeView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/MustTypeView.java
new file mode 100644
index 00000000..833e1594
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/MustTypeView.java
@@ -0,0 +1,21 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.typehierarchy;
7
8import tools.refinery.store.reasoning.representation.PartialRelation;
9import tools.refinery.store.representation.Symbol;
10import tools.refinery.store.tuple.Tuple;
11
12class MustTypeView extends InferredTypeView {
13 public MustTypeView(Symbol<InferredType> symbol, PartialRelation type) {
14 super(symbol, "must", type);
15 }
16
17 @Override
18 protected boolean doFilter(Tuple key, InferredType value) {
19 return value.mustTypes().contains(type);
20 }
21}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/PreservedType.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/PreservedType.java
deleted file mode 100644
index 0696f4c3..00000000
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/PreservedType.java
+++ /dev/null
@@ -1,141 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.typehierarchy;
7
8import tools.refinery.store.reasoning.representation.PartialRelation;
9import tools.refinery.store.representation.TruthValue;
10
11import java.util.*;
12
13final class PreservedType implements TypeAnalysisResult {
14 private final ExtendedTypeInfo extendedTypeInfo;
15 private final List<PartialRelation> directSubtypes;
16 private final List<ExtendedTypeInfo> allExternalTypeInfoList;
17 private final InferredType inferredType;
18
19 public PreservedType(ExtendedTypeInfo extendedTypeInfo, List<ExtendedTypeInfo> allExternalTypeInfoList) {
20 this.extendedTypeInfo = extendedTypeInfo;
21 directSubtypes = List.copyOf(extendedTypeInfo.getDirectSubtypes());
22 this.allExternalTypeInfoList = allExternalTypeInfoList;
23 inferredType = propagateMust(extendedTypeInfo.getAllSupertypesAndSelf(),
24 extendedTypeInfo.getConcreteSubtypesAndSelf());
25 }
26
27 public PartialRelation type() {
28 return extendedTypeInfo.getType();
29 }
30
31 public List<PartialRelation> getDirectSubtypes() {
32 return directSubtypes;
33 }
34
35 public boolean isAbstractType() {
36 return extendedTypeInfo.isAbstractType();
37 }
38
39 public boolean isVacuous() {
40 return isAbstractType() && directSubtypes.isEmpty();
41 }
42
43 public InferredType asInferredType() {
44 return inferredType;
45 }
46
47 public InferredType merge(InferredType inferredType, TruthValue value) {
48 return switch (value) {
49 case UNKNOWN -> inferredType;
50 case TRUE -> addMust(inferredType);
51 case FALSE -> removeMay(inferredType);
52 case ERROR -> addError(inferredType);
53 };
54 }
55
56 private InferredType addMust(InferredType inferredType) {
57 var originalMustTypes = inferredType.mustTypes();
58 if (originalMustTypes.contains(type())) {
59 return inferredType;
60 }
61 var mustTypes = new HashSet<>(originalMustTypes);
62 extendedTypeInfo.addMust(mustTypes);
63 var originalMayConcreteTypes = inferredType.mayConcreteTypes();
64 var mayConcreteTypes = new LinkedHashSet<>(originalMayConcreteTypes);
65 Set<PartialRelation> mayConcreteTypesResult;
66 if (mayConcreteTypes.retainAll(extendedTypeInfo.getConcreteSubtypesAndSelf())) {
67 mayConcreteTypesResult = mayConcreteTypes;
68 } else {
69 mayConcreteTypesResult = originalMayConcreteTypes;
70 }
71 return propagateMust(mustTypes, mayConcreteTypesResult);
72 }
73
74 private InferredType removeMay(InferredType inferredType) {
75 var originalMayConcreteTypes = inferredType.mayConcreteTypes();
76 var mayConcreteTypes = new LinkedHashSet<>(originalMayConcreteTypes);
77 if (!mayConcreteTypes.removeAll(extendedTypeInfo.getConcreteSubtypesAndSelf())) {
78 return inferredType;
79 }
80 return propagateMust(inferredType.mustTypes(), mayConcreteTypes);
81 }
82
83 private InferredType addError(InferredType inferredType) {
84 var originalMustTypes = inferredType.mustTypes();
85 if (originalMustTypes.contains(type())) {
86 if (inferredType.mayConcreteTypes().isEmpty()) {
87 return inferredType;
88 }
89 return new InferredType(originalMustTypes, Set.of(), null);
90 }
91 var mustTypes = new HashSet<>(originalMustTypes);
92 extendedTypeInfo.addMust(mustTypes);
93 return new InferredType(mustTypes, Set.of(), null);
94 }
95
96 private InferredType propagateMust(Set<PartialRelation> originalMustTypes,
97 Set<PartialRelation> mayConcreteTypes) {
98 // It is possible that there is not type at all, do not force one by propagation.
99 var maybeUntyped = originalMustTypes.isEmpty();
100 // Para-consistent case, do not propagate must types to avoid logical explosion.
101 var paraConsistentOrSurelyUntyped = mayConcreteTypes.isEmpty();
102 if (maybeUntyped || paraConsistentOrSurelyUntyped) {
103 return new InferredType(originalMustTypes, mayConcreteTypes, null);
104 }
105 var currentType = computeCurrentType(mayConcreteTypes);
106 var mustTypes = new HashSet<>(originalMustTypes);
107 boolean changed = false;
108 for (var newMustExtendedTypeInfo : allExternalTypeInfoList) {
109 var newMustType = newMustExtendedTypeInfo.getType();
110 if (mustTypes.contains(newMustType)) {
111 continue;
112 }
113 if (newMustExtendedTypeInfo.allowsAllConcreteTypes(mayConcreteTypes)) {
114 newMustExtendedTypeInfo.addMust(mustTypes);
115 changed = true;
116 }
117 }
118 if (!changed) {
119 return new InferredType(originalMustTypes, mayConcreteTypes, currentType);
120 }
121 return new InferredType(mustTypes, mayConcreteTypes, currentType);
122 }
123
124 /**
125 * Returns a concrete type that is allowed by a (consistent, i.e., nonempty) set of <b>may</b> concrete types.
126 *
127 * @param mayConcreteTypes The set of allowed concrete types. Must not be empty.
128 * @return The first concrete type that is allowed by {@code matConcreteTypes}.
129 */
130 private PartialRelation computeCurrentType(Set<PartialRelation> mayConcreteTypes) {
131 for (var concreteExtendedTypeInfo : allExternalTypeInfoList) {
132 var concreteType = concreteExtendedTypeInfo.getType();
133 if (!concreteExtendedTypeInfo.isAbstractType() && mayConcreteTypes.contains(concreteType)) {
134 return concreteType;
135 }
136 }
137 // We have already filtered out the para-consistent case in {@link #propagateMust(Set<PartialRelation>,
138 // Set<PartialRelation>}.
139 throw new AssertionError("No concrete type in %s".formatted(mayConcreteTypes));
140 }
141}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisResult.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisResult.java
index fbf8a7c9..39a76745 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisResult.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisResult.java
@@ -5,5 +5,137 @@
5 */ 5 */
6package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
7 7
8sealed interface TypeAnalysisResult permits EliminatedType, PreservedType { 8import tools.refinery.store.reasoning.representation.PartialRelation;
9import tools.refinery.store.representation.TruthValue;
10
11import java.util.*;
12
13final class TypeAnalysisResult {
14 private final ExtendedTypeInfo extendedTypeInfo;
15 private final List<PartialRelation> directSubtypes;
16 private final List<ExtendedTypeInfo> allExternalTypeInfoList;
17 private final InferredType inferredType;
18
19 public TypeAnalysisResult(ExtendedTypeInfo extendedTypeInfo, List<ExtendedTypeInfo> allExternalTypeInfoList) {
20 this.extendedTypeInfo = extendedTypeInfo;
21 directSubtypes = List.copyOf(extendedTypeInfo.getDirectSubtypes());
22 this.allExternalTypeInfoList = allExternalTypeInfoList;
23 inferredType = propagateMust(extendedTypeInfo.getAllSupertypesAndSelf(),
24 extendedTypeInfo.getConcreteSubtypesAndSelf());
25 }
26
27 public PartialRelation type() {
28 return extendedTypeInfo.getType();
29 }
30
31 public List<PartialRelation> getDirectSubtypes() {
32 return directSubtypes;
33 }
34
35 public boolean isAbstractType() {
36 return extendedTypeInfo.isAbstractType();
37 }
38
39 public boolean isVacuous() {
40 return isAbstractType() && directSubtypes.isEmpty();
41 }
42
43 public InferredType asInferredType() {
44 return inferredType;
45 }
46
47 public InferredType merge(InferredType inferredType, TruthValue value) {
48 return switch (value) {
49 case UNKNOWN -> inferredType;
50 case TRUE -> addMust(inferredType);
51 case FALSE -> removeMay(inferredType);
52 case ERROR -> addError(inferredType);
53 };
54 }
55
56 private InferredType addMust(InferredType inferredType) {
57 var originalMustTypes = inferredType.mustTypes();
58 if (originalMustTypes.contains(type())) {
59 return inferredType;
60 }
61 var mustTypes = new HashSet<>(originalMustTypes);
62 extendedTypeInfo.addMust(mustTypes);
63 var originalMayConcreteTypes = inferredType.mayConcreteTypes();
64 var mayConcreteTypes = new LinkedHashSet<>(originalMayConcreteTypes);
65 Set<PartialRelation> mayConcreteTypesResult;
66 if (mayConcreteTypes.retainAll(extendedTypeInfo.getConcreteSubtypesAndSelf())) {
67 mayConcreteTypesResult = mayConcreteTypes;
68 } else {
69 mayConcreteTypesResult = originalMayConcreteTypes;
70 }
71 return propagateMust(mustTypes, mayConcreteTypesResult);
72 }
73
74 private InferredType removeMay(InferredType inferredType) {
75 var originalMayConcreteTypes = inferredType.mayConcreteTypes();
76 var mayConcreteTypes = new LinkedHashSet<>(originalMayConcreteTypes);
77 if (!mayConcreteTypes.removeAll(extendedTypeInfo.getConcreteSubtypesAndSelf())) {
78 return inferredType;
79 }
80 return propagateMust(inferredType.mustTypes(), mayConcreteTypes);
81 }
82
83 private InferredType addError(InferredType inferredType) {
84 var originalMustTypes = inferredType.mustTypes();
85 if (originalMustTypes.contains(type())) {
86 if (inferredType.mayConcreteTypes().isEmpty()) {
87 return inferredType;
88 }
89 return new InferredType(originalMustTypes, Set.of(), null);
90 }
91 var mustTypes = new HashSet<>(originalMustTypes);
92 extendedTypeInfo.addMust(mustTypes);
93 return new InferredType(mustTypes, Set.of(), null);
94 }
95
96 private InferredType propagateMust(Set<PartialRelation> originalMustTypes,
97 Set<PartialRelation> mayConcreteTypes) {
98 // It is possible that there is not type at all, do not force one by propagation.
99 var maybeUntyped = originalMustTypes.isEmpty();
100 // Para-consistent case, do not propagate must types to avoid logical explosion.
101 var paraConsistentOrSurelyUntyped = mayConcreteTypes.isEmpty();
102 if (maybeUntyped || paraConsistentOrSurelyUntyped) {
103 return new InferredType(originalMustTypes, mayConcreteTypes, null);
104 }
105 var currentType = computeCurrentType(mayConcreteTypes);
106 var mustTypes = new HashSet<>(originalMustTypes);
107 boolean changed = false;
108 for (var newMustExtendedTypeInfo : allExternalTypeInfoList) {
109 var newMustType = newMustExtendedTypeInfo.getType();
110 if (mustTypes.contains(newMustType)) {
111 continue;
112 }
113 if (newMustExtendedTypeInfo.allowsAllConcreteTypes(mayConcreteTypes)) {
114 newMustExtendedTypeInfo.addMust(mustTypes);
115 changed = true;
116 }
117 }
118 if (!changed) {
119 return new InferredType(originalMustTypes, mayConcreteTypes, currentType);
120 }
121 return new InferredType(mustTypes, mayConcreteTypes, currentType);
122 }
123
124 /**
125 * Returns a concrete type that is allowed by a (consistent, i.e., nonempty) set of <b>may</b> concrete types.
126 *
127 * @param mayConcreteTypes The set of allowed concrete types. Must not be empty.
128 * @return The first concrete type that is allowed by {@code matConcreteTypes}.
129 */
130 private PartialRelation computeCurrentType(Set<PartialRelation> mayConcreteTypes) {
131 for (var concreteExtendedTypeInfo : allExternalTypeInfoList) {
132 var concreteType = concreteExtendedTypeInfo.getType();
133 if (!concreteExtendedTypeInfo.isAbstractType() && mayConcreteTypes.contains(concreteType)) {
134 return concreteType;
135 }
136 }
137 // We have already filtered out the para-consistent case in {@link #propagateMust(Set<PartialRelation>,
138 // Set<PartialRelation>}.
139 throw new AssertionError("No concrete type in %s".formatted(mayConcreteTypes));
140 }
9} 141}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzer.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchy.java
index e97ce954..99069ab9 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzer.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchy.java
@@ -9,14 +9,16 @@ import tools.refinery.store.reasoning.representation.PartialRelation;
9 9
10import java.util.*; 10import java.util.*;
11 11
12class TypeAnalyzer { 12public class TypeHierarchy {
13 private final Set<PartialRelation> allTypes;
13 private final Map<PartialRelation, ExtendedTypeInfo> extendedTypeInfoMap; 14 private final Map<PartialRelation, ExtendedTypeInfo> extendedTypeInfoMap;
14 private final Map<PartialRelation, PartialRelation> replacements = new LinkedHashMap<>(); 15 private final Map<PartialRelation, PartialRelation> replacements = new LinkedHashMap<>();
15 private final InferredType unknownType; 16 private final InferredType unknownType;
16 private final Map<PartialRelation, TypeAnalysisResult> analysisResults; 17 private final Map<PartialRelation, TypeAnalysisResult> preservedTypes;
17 18
18 public TypeAnalyzer(Map<PartialRelation, TypeInfo> typeInfoMap) { 19 TypeHierarchy(Map<PartialRelation, TypeInfo> typeInfoMap) {
19 int size = typeInfoMap.size(); 20 int size = typeInfoMap.size();
21 allTypes = Collections.unmodifiableSet(new LinkedHashSet<>(typeInfoMap.keySet()));
20 extendedTypeInfoMap = new LinkedHashMap<>(size); 22 extendedTypeInfoMap = new LinkedHashMap<>(size);
21 var concreteTypes = new LinkedHashSet<PartialRelation>(); 23 var concreteTypes = new LinkedHashSet<PartialRelation>();
22 int index = 0; 24 int index = 0;
@@ -34,15 +36,39 @@ class TypeAnalyzer {
34 computeAllAndConcreteSubtypes(); 36 computeAllAndConcreteSubtypes();
35 computeDirectSubtypes(); 37 computeDirectSubtypes();
36 eliminateTrivialSupertypes(); 38 eliminateTrivialSupertypes();
37 analysisResults = computeAnalysisResults(); 39 preservedTypes = computeAnalysisResults();
40 }
41
42 public boolean isEmpty() {
43 return extendedTypeInfoMap.isEmpty();
38 } 44 }
39 45
40 public InferredType getUnknownType() { 46 public InferredType getUnknownType() {
41 return unknownType; 47 return unknownType;
42 } 48 }
43 49
44 public Map<PartialRelation, TypeAnalysisResult> getAnalysisResults() { 50 public Set<PartialRelation> getAllTypes() {
45 return analysisResults; 51 return allTypes;
52 }
53
54 public Map<PartialRelation, TypeAnalysisResult> getPreservedTypes() {
55 return preservedTypes;
56 }
57
58 public Map<PartialRelation, PartialRelation> getEliminatedTypes() {
59 return Collections.unmodifiableMap(replacements);
60 }
61
62 public TypeAnalysisResult getAnalysisResult(PartialRelation type) {
63 var preservedResult = preservedTypes.get(type);
64 if (preservedResult != null) {
65 return preservedResult;
66 }
67 var eliminatedResult = replacements.get(type);
68 if (eliminatedResult != null) {
69 return preservedTypes.get(eliminatedResult);
70 }
71 throw new IllegalArgumentException("Unknown type: " + type);
46 } 72 }
47 73
48 private void computeAllSupertypes() { 74 private void computeAllSupertypes() {
@@ -156,17 +182,13 @@ class TypeAnalyzer {
156 182
157 private Map<PartialRelation, TypeAnalysisResult> computeAnalysisResults() { 183 private Map<PartialRelation, TypeAnalysisResult> computeAnalysisResults() {
158 var allExtendedTypeInfoList = sortTypes(); 184 var allExtendedTypeInfoList = sortTypes();
159 var results = new LinkedHashMap<PartialRelation, TypeAnalysisResult>( 185 var preservedResults = new LinkedHashMap<PartialRelation, TypeAnalysisResult>(
160 allExtendedTypeInfoList.size() + replacements.size()); 186 allExtendedTypeInfoList.size());
161 for (var extendedTypeInfo : allExtendedTypeInfoList) { 187 for (var extendedTypeInfo : allExtendedTypeInfoList) {
162 var type = extendedTypeInfo.getType(); 188 var type = extendedTypeInfo.getType();
163 results.put(type, new PreservedType(extendedTypeInfo, allExtendedTypeInfoList)); 189 preservedResults.put(type, new TypeAnalysisResult(extendedTypeInfo, allExtendedTypeInfoList));
164 } 190 }
165 for (var entry : replacements.entrySet()) { 191 return Collections.unmodifiableMap(preservedResults);
166 var type = entry.getKey();
167 results.put(type, new EliminatedType(entry.getValue()));
168 }
169 return Collections.unmodifiableMap(results);
170 } 192 }
171 193
172 private List<ExtendedTypeInfo> sortTypes() { 194 private List<ExtendedTypeInfo> sortTypes() {
@@ -204,4 +226,8 @@ class TypeAnalyzer {
204 } 226 }
205 return Collections.unmodifiableList(sorted); 227 return Collections.unmodifiableList(sorted);
206 } 228 }
229
230 public static TypeHierarchyBuilder builder() {
231 return new TypeHierarchyBuilder();
232 }
207} 233}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyBuilder.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyBuilder.java
new file mode 100644
index 00000000..0fca4810
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyBuilder.java
@@ -0,0 +1,62 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.typehierarchy;
7
8import tools.refinery.store.reasoning.representation.PartialRelation;
9
10import java.util.Collection;
11import java.util.LinkedHashMap;
12import java.util.List;
13import java.util.Map;
14
15public class TypeHierarchyBuilder {
16 private final Map<PartialRelation, TypeInfo> typeInfoMap = new LinkedHashMap<>();
17
18 public TypeHierarchyBuilder type(PartialRelation partialRelation, TypeInfo typeInfo) {
19 if (partialRelation.arity() != 1) {
20 throw new IllegalArgumentException("Only types of arity 1 are supported, hot %d instead"
21 .formatted(partialRelation.arity()));
22 }
23 var putResult = typeInfoMap.put(partialRelation, typeInfo);
24 if (putResult != null && !putResult.equals(typeInfo)) {
25 throw new IllegalArgumentException("Duplicate type info for partial relation: " + partialRelation);
26 }
27 return this;
28 }
29
30 public TypeHierarchyBuilder type(PartialRelation partialRelation, boolean abstractType,
31 PartialRelation... supertypes) {
32 return type(partialRelation, abstractType, List.of(supertypes));
33 }
34
35 public TypeHierarchyBuilder type(PartialRelation partialRelation, boolean abstractType,
36 Collection<PartialRelation> supertypes) {
37 return type(partialRelation, new TypeInfo(supertypes, abstractType));
38 }
39
40 public TypeHierarchyBuilder type(PartialRelation partialRelation, PartialRelation... supertypes) {
41 return type(partialRelation, List.of(supertypes));
42 }
43
44 public TypeHierarchyBuilder type(PartialRelation partialRelation, Collection<PartialRelation> supertypes) {
45 return type(partialRelation, false, supertypes);
46 }
47
48 public TypeHierarchyBuilder types(Collection<Map.Entry<PartialRelation, TypeInfo>> entries) {
49 for (var entry : entries) {
50 type(entry.getKey(), entry.getValue());
51 }
52 return this;
53 }
54
55 public TypeHierarchyBuilder types(Map<PartialRelation, TypeInfo> map) {
56 return types(map.entrySet());
57 }
58
59 public TypeHierarchy build() {
60 return new TypeHierarchy(typeInfoMap);
61 }
62}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyInitializer.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyInitializer.java
new file mode 100644
index 00000000..6648a454
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyInitializer.java
@@ -0,0 +1,57 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.typehierarchy;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.reasoning.refinement.PartialModelInitializer;
10import tools.refinery.store.reasoning.representation.PartialRelation;
11import tools.refinery.store.reasoning.seed.ModelSeed;
12import tools.refinery.store.representation.Symbol;
13import tools.refinery.store.representation.TruthValue;
14import tools.refinery.store.tuple.Tuple;
15
16import java.util.Arrays;
17
18public class TypeHierarchyInitializer implements PartialModelInitializer {
19 private final TypeHierarchy typeHierarchy;
20 private final Symbol<InferredType> typeSymbol;
21
22 public TypeHierarchyInitializer(TypeHierarchy typeHierarchy, Symbol<InferredType> typeSymbol) {
23 this.typeHierarchy = typeHierarchy;
24 this.typeSymbol = typeSymbol;
25 }
26
27 @Override
28 public void initialize(Model model, ModelSeed modelSeed) {
29 var inferredTypes = new InferredType[modelSeed.getNodeCount()];
30 Arrays.fill(inferredTypes, typeHierarchy.getUnknownType());
31 for (var type : typeHierarchy.getAllTypes()) {
32 initializeType(type, inferredTypes, modelSeed);
33 }
34 var typeInterpretation = model.getInterpretation(typeSymbol);
35 for (int i = 0; i < inferredTypes.length; i++) {
36 typeInterpretation.put(Tuple.of(i), inferredTypes[i]);
37 }
38 }
39
40 private void initializeType(PartialRelation type, InferredType[] inferredTypes, ModelSeed modelSeed) {
41 var cursor = modelSeed.getCursor(type, TruthValue.UNKNOWN);
42 var analysisResult = typeHierarchy.getAnalysisResult(type);
43 while (cursor.move()) {
44 var i = cursor.getKey().get(0);
45 checkNodeId(inferredTypes, i);
46 var value = cursor.getValue();
47 inferredTypes[i] = analysisResult.merge(inferredTypes[i], value);
48 }
49 }
50
51 private void checkNodeId(InferredType[] inferredTypes, int nodeId) {
52 if (nodeId < 0 || nodeId >= inferredTypes.length) {
53 throw new IllegalArgumentException("Expected node id %d to be lower than model size %d"
54 .formatted(nodeId, inferredTypes.length));
55 }
56 }
57}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslator.java
new file mode 100644
index 00000000..6a45acd3
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslator.java
@@ -0,0 +1,81 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.typehierarchy;
7
8import tools.refinery.store.model.ModelStoreBuilder;
9import tools.refinery.store.model.ModelStoreConfiguration;
10import tools.refinery.store.query.dnf.Query;
11import tools.refinery.store.reasoning.ReasoningBuilder;
12import tools.refinery.store.reasoning.literal.PartialLiterals;
13import tools.refinery.store.reasoning.representation.PartialRelation;
14import tools.refinery.store.reasoning.translator.PartialRelationTranslator;
15import tools.refinery.store.reasoning.translator.proxy.PartialRelationTranslatorProxy;
16import tools.refinery.store.representation.Symbol;
17
18public class TypeHierarchyTranslator implements ModelStoreConfiguration {
19 private final Symbol<InferredType> typeSymbol = Symbol.of("TYPE", 1, InferredType.class, InferredType.UNTYPED);
20 private final TypeHierarchy typeHierarchy;
21
22 public TypeHierarchyTranslator(TypeHierarchy typeHierarchy) {
23 this.typeHierarchy = typeHierarchy;
24 }
25
26 @Override
27 public void apply(ModelStoreBuilder storeBuilder) {
28 if (typeHierarchy.isEmpty()) {
29 return;
30 }
31
32 storeBuilder.symbol(typeSymbol);
33
34 for (var entry : typeHierarchy.getPreservedTypes().entrySet()) {
35 storeBuilder.with(createPreservedTypeTranslator(entry.getKey(), entry.getValue()));
36 }
37
38 for (var entry : typeHierarchy.getEliminatedTypes().entrySet()) {
39 storeBuilder.with(createEliminatedTypeTranslator(entry.getKey(), entry.getValue()));
40 }
41
42 var reasoningBuilder = storeBuilder.getAdapter(ReasoningBuilder.class);
43 reasoningBuilder.initializer(new TypeHierarchyInitializer(typeHierarchy, typeSymbol));
44 }
45
46 private ModelStoreConfiguration createPreservedTypeTranslator(PartialRelation type, TypeAnalysisResult result) {
47 var may = Query.of(type.name() + "#may", (builder, p1) -> {
48 if (result.isAbstractType()) {
49 for (var subtype : result.getDirectSubtypes()) {
50 builder.clause(PartialLiterals.may(subtype.call(p1)));
51 }
52 } else {
53 builder.clause(new MayTypeView(typeSymbol, type).call(p1));
54 }
55 });
56
57 var must = Query.of(type.name() + "#must", (builder, p1) -> builder.clause(
58 new MustTypeView(typeSymbol, type).call(p1)
59 ));
60
61 var candidate = Query.of(type.name() + "#candidate", (builder, p1) -> {
62 if (!result.isAbstractType()) {
63 builder.clause(new CandidateTypeView(typeSymbol, type).call(p1));
64 }
65 for (var subtype : result.getDirectSubtypes()) {
66 builder.clause(PartialLiterals.candidateMust(subtype.call(p1)));
67 }
68 });
69
70 return PartialRelationTranslator.of(type)
71 .may(may)
72 .must(must)
73 .candidate(candidate)
74 .refiner(InferredTypeRefiner.of(typeSymbol, result));
75 }
76
77 private ModelStoreConfiguration createEliminatedTypeTranslator(
78 PartialRelation type, PartialRelation replacement) {
79 return new PartialRelationTranslatorProxy(type, replacement, true);
80 }
81}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeInfo.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeInfo.java
index 9f897e46..68ed4089 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeInfo.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeInfo.java
@@ -10,42 +10,4 @@ import tools.refinery.store.reasoning.representation.PartialRelation;
10import java.util.*; 10import java.util.*;
11 11
12public record TypeInfo(Collection<PartialRelation> supertypes, boolean abstractType) { 12public record TypeInfo(Collection<PartialRelation> supertypes, boolean abstractType) {
13 public static Builder builder() {
14 return new Builder();
15 }
16
17 public static class Builder {
18 private final Set<PartialRelation> supertypes = new LinkedHashSet<>();
19 private boolean abstractType;
20
21 private Builder() {
22 }
23
24 public Builder supertypes(Collection<PartialRelation> supertypes) {
25 this.supertypes.addAll(supertypes);
26 return this;
27 }
28
29 public Builder supertypes(PartialRelation... supertypes) {
30 return supertypes(List.of(supertypes));
31 }
32
33 public Builder supertype(PartialRelation supertype) {
34 supertypes.add(supertype);
35 return this;
36 }
37
38 public Builder abstractType(boolean abstractType) {
39 this.abstractType = abstractType;
40 return this;
41 }
42
43 public Builder abstractType() {
44 return abstractType(true);
45 }
46
47 public TypeInfo build() {
48 return new TypeInfo(Collections.unmodifiableSet(supertypes), abstractType);
49 }
50 }
51} 13}