diff options
author | Kristóf Marussy <marussy@mit.bme.hu> | 2023-09-14 19:29:36 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-14 19:29:36 +0200 |
commit | 98ed3b6db5f4e51961a161050cc31c66015116e8 (patch) | |
tree | 8bfd6d9bc8d6ed23b9eb0f889dd40b6c24fe8f92 /subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilder.java | |
parent | Merge pull request #38 from nagilooh/design-space-exploration (diff) | |
parent | Merge remote-tracking branch 'upstream/main' into partial-interpretation (diff) | |
download | refinery-98ed3b6db5f4e51961a161050cc31c66015116e8.tar.gz refinery-98ed3b6db5f4e51961a161050cc31c66015116e8.tar.zst refinery-98ed3b6db5f4e51961a161050cc31c66015116e8.zip |
Merge pull request #39 from kris7t/partial-interpretation
Implement partial interpretation based model generation
Diffstat (limited to 'subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilder.java')
-rw-r--r-- | subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilder.java | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilder.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilder.java new file mode 100644 index 00000000..ad0288ed --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilder.java | |||
@@ -0,0 +1,225 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.reasoning.translator.metamodel; | ||
7 | |||
8 | import tools.refinery.store.reasoning.representation.PartialRelation; | ||
9 | import tools.refinery.store.reasoning.translator.TranslationException; | ||
10 | import tools.refinery.store.reasoning.translator.containment.ContainmentHierarchyTranslator; | ||
11 | import tools.refinery.store.reasoning.translator.containment.ContainmentInfo; | ||
12 | import tools.refinery.store.reasoning.translator.crossreference.DirectedCrossReferenceInfo; | ||
13 | import tools.refinery.store.reasoning.translator.crossreference.UndirectedCrossReferenceInfo; | ||
14 | import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity; | ||
15 | import tools.refinery.store.reasoning.translator.multiplicity.UnconstrainedMultiplicity; | ||
16 | import tools.refinery.store.reasoning.translator.typehierarchy.TypeInfo; | ||
17 | |||
18 | import java.util.*; | ||
19 | |||
20 | public class MetamodelBuilder { | ||
21 | private final ContainedTypeHierarchyBuilder typeHierarchyBuilder = new ContainedTypeHierarchyBuilder(); | ||
22 | private final Map<PartialRelation, ReferenceInfo> referenceInfoMap = new LinkedHashMap<>(); | ||
23 | private final Set<PartialRelation> containedTypes = new HashSet<>(); | ||
24 | private final Map<PartialRelation, ContainmentInfo> containmentHierarchy = new LinkedHashMap<>(); | ||
25 | private final Map<PartialRelation, DirectedCrossReferenceInfo> directedCrossReferences = new LinkedHashMap<>(); | ||
26 | private final Map<PartialRelation, UndirectedCrossReferenceInfo> undirectedCrossReferences = new LinkedHashMap<>(); | ||
27 | private final Map<PartialRelation, PartialRelation> oppositeReferences = new LinkedHashMap<>(); | ||
28 | |||
29 | MetamodelBuilder() { | ||
30 | typeHierarchyBuilder.type(ContainmentHierarchyTranslator.CONTAINED_SYMBOL, true); | ||
31 | } | ||
32 | |||
33 | public MetamodelBuilder type(PartialRelation partialRelation, TypeInfo typeInfo) { | ||
34 | typeHierarchyBuilder.type(partialRelation, typeInfo); | ||
35 | return this; | ||
36 | |||
37 | } | ||
38 | |||
39 | public MetamodelBuilder type(PartialRelation partialRelation, boolean abstractType, | ||
40 | PartialRelation... supertypes) { | ||
41 | typeHierarchyBuilder.type(partialRelation, abstractType, supertypes); | ||
42 | return this; | ||
43 | } | ||
44 | |||
45 | public MetamodelBuilder type(PartialRelation partialRelation, boolean abstractType, | ||
46 | Collection<PartialRelation> supertypes) { | ||
47 | typeHierarchyBuilder.type(partialRelation, abstractType, supertypes); | ||
48 | return this; | ||
49 | } | ||
50 | |||
51 | public MetamodelBuilder type(PartialRelation partialRelation, PartialRelation... supertypes) { | ||
52 | typeHierarchyBuilder.type(partialRelation, supertypes); | ||
53 | return this; | ||
54 | } | ||
55 | |||
56 | public MetamodelBuilder type(PartialRelation partialRelation, Collection<PartialRelation> supertypes) { | ||
57 | typeHierarchyBuilder.type(partialRelation, supertypes); | ||
58 | return this; | ||
59 | } | ||
60 | |||
61 | public MetamodelBuilder types(Collection<Map.Entry<PartialRelation, TypeInfo>> entries) { | ||
62 | typeHierarchyBuilder.types(entries); | ||
63 | return this; | ||
64 | } | ||
65 | |||
66 | public MetamodelBuilder types(Map<PartialRelation, TypeInfo> map) { | ||
67 | typeHierarchyBuilder.types(map); | ||
68 | return this; | ||
69 | } | ||
70 | |||
71 | public MetamodelBuilder reference(PartialRelation linkType, ReferenceInfo info) { | ||
72 | if (linkType.arity() != 2) { | ||
73 | throw new TranslationException(linkType, | ||
74 | "Only references of arity 2 are supported, got %s with %d instead".formatted( | ||
75 | linkType, linkType.arity())); | ||
76 | } | ||
77 | var putResult = referenceInfoMap.put(linkType, info); | ||
78 | if (putResult != null && !putResult.equals(info)) { | ||
79 | throw new TranslationException(linkType, "Duplicate reference info for partial relation: " + linkType); | ||
80 | } | ||
81 | return this; | ||
82 | } | ||
83 | |||
84 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, boolean containment, | ||
85 | Multiplicity multiplicity, PartialRelation targetType, | ||
86 | PartialRelation opposite) { | ||
87 | return reference(linkType, new ReferenceInfo(containment, sourceType, multiplicity, targetType, opposite)); | ||
88 | } | ||
89 | |||
90 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, Multiplicity multiplicity, | ||
91 | PartialRelation targetType, PartialRelation opposite) { | ||
92 | return reference(linkType, sourceType, false, multiplicity, targetType, opposite); | ||
93 | } | ||
94 | |||
95 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, | ||
96 | boolean containment, PartialRelation targetType, PartialRelation opposite) { | ||
97 | return reference(linkType, sourceType, containment, UnconstrainedMultiplicity.INSTANCE, targetType, opposite); | ||
98 | } | ||
99 | |||
100 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, PartialRelation targetType, | ||
101 | PartialRelation opposite) { | ||
102 | return reference(linkType, sourceType, UnconstrainedMultiplicity.INSTANCE, targetType, opposite); | ||
103 | } | ||
104 | |||
105 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, boolean containment, | ||
106 | Multiplicity multiplicity, PartialRelation targetType) { | ||
107 | return reference(linkType, sourceType, containment, multiplicity, targetType, null); | ||
108 | } | ||
109 | |||
110 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, Multiplicity multiplicity, | ||
111 | PartialRelation targetType) { | ||
112 | return reference(linkType, sourceType, multiplicity, targetType, null); | ||
113 | } | ||
114 | |||
115 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, boolean containment, | ||
116 | PartialRelation targetType) { | ||
117 | return reference(linkType, sourceType, containment, targetType, null); | ||
118 | } | ||
119 | |||
120 | public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, | ||
121 | PartialRelation targetType) { | ||
122 | return reference(linkType, sourceType, targetType, null); | ||
123 | } | ||
124 | |||
125 | public MetamodelBuilder references(Collection<Map.Entry<PartialRelation, ReferenceInfo>> entries) { | ||
126 | for (var entry : entries) { | ||
127 | reference(entry.getKey(), entry.getValue()); | ||
128 | } | ||
129 | return this; | ||
130 | } | ||
131 | |||
132 | public MetamodelBuilder references(Map<PartialRelation, ReferenceInfo> map) { | ||
133 | return references(map.entrySet()); | ||
134 | } | ||
135 | |||
136 | public Metamodel build() { | ||
137 | for (var entry : referenceInfoMap.entrySet()) { | ||
138 | var linkType = entry.getKey(); | ||
139 | var info = entry.getValue(); | ||
140 | processReferenceInfo(linkType, info); | ||
141 | } | ||
142 | typeHierarchyBuilder.setContainedTypes(containedTypes); | ||
143 | var typeHierarchy = typeHierarchyBuilder.build(); | ||
144 | return new Metamodel(typeHierarchy, Collections.unmodifiableMap(containmentHierarchy), | ||
145 | Collections.unmodifiableMap(directedCrossReferences), | ||
146 | Collections.unmodifiableMap(undirectedCrossReferences), | ||
147 | Collections.unmodifiableMap(oppositeReferences)); | ||
148 | } | ||
149 | |||
150 | private void processReferenceInfo(PartialRelation linkType, ReferenceInfo info) { | ||
151 | if (oppositeReferences.containsKey(linkType) || containmentHierarchy.containsKey(linkType)) { | ||
152 | // We already processed this reference while processing its opposite. | ||
153 | return; | ||
154 | } | ||
155 | var sourceType = info.sourceType(); | ||
156 | var targetType = info.targetType(); | ||
157 | if (typeHierarchyBuilder.isInvalidType(sourceType)) { | ||
158 | throw new TranslationException(linkType, "Source type %s of %s is not in type hierarchy" | ||
159 | .formatted(sourceType, linkType)); | ||
160 | } | ||
161 | if (typeHierarchyBuilder.isInvalidType(targetType)) { | ||
162 | throw new TranslationException(linkType, "Target type %s of %s is not in type hierarchy" | ||
163 | .formatted(targetType, linkType)); | ||
164 | } | ||
165 | var opposite = info.opposite(); | ||
166 | Multiplicity targetMultiplicity = UnconstrainedMultiplicity.INSTANCE; | ||
167 | if (opposite != null) { | ||
168 | var oppositeInfo = referenceInfoMap.get(opposite); | ||
169 | validateOpposite(linkType, info, opposite, oppositeInfo); | ||
170 | targetMultiplicity = oppositeInfo.multiplicity(); | ||
171 | if (oppositeInfo.containment()) { | ||
172 | // Skip processing this reference and process it once we encounter its containment opposite. | ||
173 | return; | ||
174 | } | ||
175 | if (opposite.equals(linkType)) { | ||
176 | if (!sourceType.equals(targetType)) { | ||
177 | throw new TranslationException(linkType, | ||
178 | "Target %s of undirected reference %s differs from source %s".formatted( | ||
179 | targetType, linkType, sourceType)); | ||
180 | } | ||
181 | undirectedCrossReferences.put(linkType, new UndirectedCrossReferenceInfo(sourceType, | ||
182 | info.multiplicity())); | ||
183 | return; | ||
184 | } | ||
185 | oppositeReferences.put(opposite, linkType); | ||
186 | } | ||
187 | if (info.containment()) { | ||
188 | if (!UnconstrainedMultiplicity.INSTANCE.equals(targetMultiplicity)) { | ||
189 | throw new TranslationException(opposite, "Invalid opposite %s with multiplicity %s of containment %s" | ||
190 | .formatted(opposite, targetMultiplicity, linkType)); | ||
191 | } | ||
192 | containedTypes.add(targetType); | ||
193 | containmentHierarchy.put(linkType, new ContainmentInfo(sourceType, info.multiplicity(), targetType)); | ||
194 | return; | ||
195 | } | ||
196 | directedCrossReferences.put(linkType, new DirectedCrossReferenceInfo(sourceType, info.multiplicity(), | ||
197 | targetType, targetMultiplicity)); | ||
198 | } | ||
199 | |||
200 | private static void validateOpposite(PartialRelation linkType, ReferenceInfo info, PartialRelation opposite, | ||
201 | ReferenceInfo oppositeInfo) { | ||
202 | var sourceType = info.sourceType(); | ||
203 | var targetType = info.targetType(); | ||
204 | if (oppositeInfo == null) { | ||
205 | throw new TranslationException(linkType, "Opposite %s of %s is not defined" | ||
206 | .formatted(opposite, linkType)); | ||
207 | } | ||
208 | if (!linkType.equals(oppositeInfo.opposite())) { | ||
209 | throw new TranslationException(opposite, "Expected %s to have opposite %s, got %s instead" | ||
210 | .formatted(opposite, linkType, oppositeInfo.opposite())); | ||
211 | } | ||
212 | if (!targetType.equals(oppositeInfo.sourceType())) { | ||
213 | throw new TranslationException(linkType, "Expected %s to have source type %s, got %s instead" | ||
214 | .formatted(opposite, targetType, oppositeInfo.sourceType())); | ||
215 | } | ||
216 | if (!sourceType.equals(oppositeInfo.targetType())) { | ||
217 | throw new TranslationException(linkType, "Expected %s to have target type %s, got %s instead" | ||
218 | .formatted(opposite, sourceType, oppositeInfo.targetType())); | ||
219 | } | ||
220 | if (oppositeInfo.containment() && info.containment()) { | ||
221 | throw new TranslationException(opposite, "Opposite %s of containment %s cannot be containment" | ||
222 | .formatted(opposite, linkType)); | ||
223 | } | ||
224 | } | ||
225 | } | ||