aboutsummaryrefslogtreecommitdiffstats
path: root/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality
diff options
context:
space:
mode:
Diffstat (limited to 'Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality')
-rw-r--r--Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/MultiplicityGoalConstraintCalculator.xtend46
-rw-r--r--Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronScopePropagator.xtend355
-rw-r--r--Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronSolver.xtend32
-rw-r--r--Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/RelationConstraintCalculator.xtend133
-rw-r--r--Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/ScopePropagator.xtend5
-rw-r--r--Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/ScopePropagatorStrategy.java18
6 files changed, 506 insertions, 83 deletions
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/MultiplicityGoalConstraintCalculator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/MultiplicityGoalConstraintCalculator.xtend
new file mode 100644
index 00000000..86a59aa1
--- /dev/null
+++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/MultiplicityGoalConstraintCalculator.xtend
@@ -0,0 +1,46 @@
1package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality
2
3import org.eclipse.emf.common.notify.Notifier
4import org.eclipse.viatra.query.runtime.api.IQuerySpecification
5import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine
6import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher
7import org.eclipse.viatra.query.runtime.emf.EMFScope
8
9class MultiplicityGoalConstraintCalculator {
10 val String targetRelationName;
11 val IQuerySpecification<?> querySpecification;
12 var ViatraQueryMatcher<?> matcher;
13
14 new(String targetRelationName, IQuerySpecification<?> querySpecification) {
15 this.targetRelationName = targetRelationName
16 this.querySpecification = querySpecification
17 this.matcher = null
18 }
19
20 new(MultiplicityGoalConstraintCalculator other) {
21 this.targetRelationName = other.targetRelationName
22 this.querySpecification = other.querySpecification
23 this.matcher = null
24 }
25
26 def getName() {
27 targetRelationName
28 }
29
30 def init(Notifier notifier) {
31 val engine = ViatraQueryEngine.on(new EMFScope(notifier))
32 matcher = querySpecification.getMatcher(engine)
33 }
34
35 def calculateValue() {
36 var res = 0
37 val allMatches = this.matcher.allMatches
38 for(match : allMatches) {
39 //println(targetRelationName+ " missing multiplicity: "+match.get(3))
40 val missingMultiplicity = match.get(2) as Integer
41 res += missingMultiplicity
42 }
43 //println(targetRelationName+ " all missing multiplicities: "+res)
44 return res
45 }
46}
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronScopePropagator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronScopePropagator.xtend
index cebd89da..4f0c8f20 100644
--- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronScopePropagator.xtend
+++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronScopePropagator.xtend
@@ -2,90 +2,60 @@ package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality
2 2
3import com.google.common.collect.ImmutableList 3import com.google.common.collect.ImmutableList
4import com.google.common.collect.ImmutableMap 4import com.google.common.collect.ImmutableMap
5import com.google.common.collect.Maps
5import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Type 6import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Type
7import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.UnifinishedMultiplicityQueries
6import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialComplexTypeInterpretation 8import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialComplexTypeInterpretation
7import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation 9import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation
8import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialPrimitiveInterpretation 10import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialPrimitiveInterpretation
9import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.Scope 11import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.Scope
10import java.util.ArrayDeque 12import java.util.ArrayDeque
13import java.util.ArrayList
11import java.util.HashMap 14import java.util.HashMap
12import java.util.HashSet 15import java.util.HashSet
16import java.util.List
13import java.util.Map 17import java.util.Map
14import java.util.Set 18import java.util.Set
19import javax.naming.OperationNotSupportedException
20import org.eclipse.viatra.query.runtime.api.IPatternMatch
21import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine
22import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher
23import org.eclipse.viatra.query.runtime.emf.EMFScope
24import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
15 25
16class PolyhedronScopePropagator extends ScopePropagator { 26class PolyhedronScopePropagator extends ScopePropagator {
17 val Map<Scope, LinearBoundedExpression> scopeBounds 27 val Map<Scope, LinearBoundedExpression> scopeBounds
18 val LinearConstraint topLevelBounds 28 val LinearBoundedExpression topLevelBounds
29 val Polyhedron polyhedron
19 val PolyhedronSaturationOperator operator 30 val PolyhedronSaturationOperator operator
31 List<RelationConstraintUpdater> updaters = emptyList
20 32
21 new(PartialInterpretation p, Set<? extends Type> possibleNewDynamicTypes, PolyhedronSolver solver) { 33 new(PartialInterpretation p, Set<? extends Type> possibleNewDynamicTypes,
34 Map<RelationMultiplicityConstraint, UnifinishedMultiplicityQueries> unfinishedMultiplicityQueries,
35 PolyhedronSolver solver, boolean propagateRelations) {
22 super(p) 36 super(p)
23 val instanceCounts = possibleNewDynamicTypes.toInvertedMap[new Dimension(name, 0, null)] 37 val builder = new PolyhedronBuilder(p)
24 val primitiveDimensions = new HashMap 38 builder.buildPolyhedron(possibleNewDynamicTypes)
25 val constraintsBuilder = ImmutableList.builder 39 scopeBounds = builder.scopeBounds
26 val scopeBoundsBuilder = ImmutableMap.builder 40 topLevelBounds = builder.topLevelBounds
27 // Dimensions for instantiable types were created according to the type analysis, 41 polyhedron = builder.polyhedron
28 // but for any possible primitive types, we create them on demand,
29 // as there is no Type directly associated with a PartialPrimitiveInterpretation.
30 // Below we will assume that each PartialTypeInterpretation has at most one Scope.
31 for (scope : p.scopes) {
32 switch (targetTypeInterpretation : scope.targetTypeInterpretation) {
33 PartialPrimitiveInterpretation: {
34 val dimension = primitiveDimensions.computeIfAbsent(targetTypeInterpretation) [ interpretation |
35 new Dimension(interpretation.eClass.name, 0, null)
36 ]
37 scopeBoundsBuilder.put(scope, dimension)
38 }
39 PartialComplexTypeInterpretation: {
40 val complexType = targetTypeInterpretation.interpretationOf
41 val dimensions = findSubtypeDimensions(complexType, instanceCounts)
42 switch (dimensions.size) {
43 case 0:
44 if (scope.minNewElements > 0) {
45 throw new IllegalArgumentException("Found scope for " + complexType.name +
46 ", but the type cannot be instantiated")
47 }
48 case 1:
49 scopeBoundsBuilder.put(scope, dimensions.head)
50 default: {
51 val constraint = new LinearConstraint(dimensions.toInvertedMap[1], null, null)
52 constraintsBuilder.add(constraint)
53 scopeBoundsBuilder.put(scope, constraint)
54 }
55 }
56 }
57 default:
58 throw new IllegalArgumentException("Unknown PartialTypeInterpretation: " + targetTypeInterpretation)
59 }
60 }
61 val allDimensions = ImmutableList.builder.addAll(instanceCounts.values).addAll(primitiveDimensions.values).build
62 scopeBounds = scopeBoundsBuilder.build
63 topLevelBounds = new LinearConstraint(allDimensions.toInvertedMap[1], null, null)
64 constraintsBuilder.add(topLevelBounds)
65 val expressionsToSaturate = ImmutableList.builder.addAll(scopeBounds.values).add(topLevelBounds).build
66 val polyhedron = new Polyhedron(allDimensions, constraintsBuilder.build, expressionsToSaturate)
67 operator = solver.createSaturationOperator(polyhedron) 42 operator = solver.createSaturationOperator(polyhedron)
68 } 43 if (propagateRelations) {
69 44 propagateAllScopeConstraints()
70 private def findSubtypeDimensions(Type type, Map<Type, Dimension> instanceCounts) { 45 val maximumNumberOfNewNodes = topLevelBounds.upperBound
71 val subtypes = new HashSet 46 if (maximumNumberOfNewNodes === null) {
72 val dimensions = new HashSet 47 throw new IllegalStateException("Could not determine maximum number of new nodes, it may be unbounded")
73 val stack = new ArrayDeque 48 }
74 stack.addLast(type) 49 if (maximumNumberOfNewNodes <= 0) {
75 while (!stack.empty) { 50 throw new IllegalStateException("Maximum number of new nodes is negative")
76 val subtype = stack.removeLast
77 if (subtypes.add(subtype)) {
78 val dimension = instanceCounts.get(subtype)
79 if (dimension !== null) {
80 dimensions.add(dimension)
81 }
82 stack.addAll(subtype.subtypes)
83 } 51 }
52 builder.buildMultiplicityConstraints(unfinishedMultiplicityQueries, maximumNumberOfNewNodes)
53 updaters = builder.updaters
84 } 54 }
85 dimensions
86 } 55 }
87 56
88 override void propagateAllScopeConstraints() { 57 override void propagateAllScopeConstraints() {
58 resetBounds()
89 populatePolyhedronFromScope() 59 populatePolyhedronFromScope()
90 val result = operator.saturate() 60 val result = operator.saturate()
91 if (result == PolyhedronSaturationResult.EMPTY) { 61 if (result == PolyhedronSaturationResult.EMPTY) {
@@ -96,21 +66,36 @@ class PolyhedronScopePropagator extends ScopePropagator {
96 super.propagateAllScopeConstraints() 66 super.propagateAllScopeConstraints()
97 } 67 }
98 } 68 }
69 // println(polyhedron)
70 }
71
72 def resetBounds() {
73 for (dimension : polyhedron.dimensions) {
74 dimension.lowerBound = 0
75 dimension.upperBound = null
76 }
77 for (constraint : polyhedron.constraints) {
78 constraint.lowerBound = null
79 constraint.upperBound = null
80 }
99 } 81 }
100 82
101 private def populatePolyhedronFromScope() { 83 private def populatePolyhedronFromScope() {
102 topLevelBounds.lowerBound = partialInterpretation.minNewElements 84 topLevelBounds.tightenLowerBound(partialInterpretation.minNewElements)
103 if (partialInterpretation.maxNewElements >= 0) { 85 if (partialInterpretation.maxNewElements >= 0) {
104 topLevelBounds.upperBound = partialInterpretation.maxNewElements 86 topLevelBounds.tightenUpperBound(partialInterpretation.maxNewElements)
105 } 87 }
106 for (pair : scopeBounds.entrySet) { 88 for (pair : scopeBounds.entrySet) {
107 val scope = pair.key 89 val scope = pair.key
108 val bounds = pair.value 90 val bounds = pair.value
109 bounds.lowerBound = scope.minNewElements 91 bounds.tightenLowerBound(scope.minNewElements)
110 if (scope.maxNewElements >= 0) { 92 if (scope.maxNewElements >= 0) {
111 bounds.upperBound = scope.maxNewElements 93 bounds.tightenUpperBound(scope.maxNewElements)
112 } 94 }
113 } 95 }
96 for (updater : updaters) {
97 updater.update(partialInterpretation)
98 }
114 } 99 }
115 100
116 private def populateScopesFromPolyhedron() { 101 private def populateScopesFromPolyhedron() {
@@ -151,4 +136,242 @@ class PolyhedronScopePropagator extends ScopePropagator {
151 throw new IllegalArgumentException("Infinite upper bound: " + bounds) 136 throw new IllegalArgumentException("Infinite upper bound: " + bounds)
152 } 137 }
153 } 138 }
139
140 private static def <T extends IPatternMatch> getCalculatedMultiplicity(ViatraQueryMatcher<T> matcher,
141 PartialInterpretation p) {
142 val match = matcher.newEmptyMatch
143 match.set(0, p.problem)
144 match.set(1, p)
145 val iterator = matcher.streamAllMatches(match).iterator
146 if (!iterator.hasNext) {
147 return null
148 }
149 val value = iterator.next.get(2) as Integer
150 if (iterator.hasNext) {
151 throw new IllegalArgumentException("Multiplicity calculation query has more than one match")
152 }
153 value
154 }
155
156 @FinalFieldsConstructor
157 private static class PolyhedronBuilder {
158 static val INFINITY_SCALE = 10
159
160 val PartialInterpretation p
161
162 Map<Type, Dimension> instanceCounts
163 Map<Type, Map<Dimension, Integer>> subtypeDimensions
164 Map<Map<Dimension, Integer>, LinearBoundedExpression> expressionsCache
165 Map<Type, LinearBoundedExpression> typeBounds
166 int infinity
167 ViatraQueryEngine queryEngine
168 ImmutableList.Builder<RelationConstraintUpdater> updatersBuilder
169
170 Map<Scope, LinearBoundedExpression> scopeBounds
171 LinearBoundedExpression topLevelBounds
172 Polyhedron polyhedron
173 List<RelationConstraintUpdater> updaters
174
175 def buildPolyhedron(Set<? extends Type> possibleNewDynamicTypes) {
176 instanceCounts = possibleNewDynamicTypes.toInvertedMap[new Dimension(name, 0, null)]
177 val types = p.problem.types
178 expressionsCache = Maps.newHashMapWithExpectedSize(types.size)
179 subtypeDimensions = types.toInvertedMap[findSubtypeDimensions.toInvertedMap[1]]
180 typeBounds = ImmutableMap.copyOf(subtypeDimensions.mapValues[toExpression])
181 scopeBounds = buildScopeBounds
182 topLevelBounds = instanceCounts.values.toInvertedMap[1].toExpression
183 val dimensions = ImmutableList.copyOf(instanceCounts.values)
184 val expressionsToSaturate = ImmutableList.copyOf(scopeBounds.values)
185 polyhedron = new Polyhedron(dimensions, new ArrayList, expressionsToSaturate)
186 addCachedConstraintsToPolyhedron()
187 }
188
189 def buildMultiplicityConstraints(
190 Map<RelationMultiplicityConstraint, UnifinishedMultiplicityQueries> constraints,
191 int maximumNuberOfNewNodes) {
192 infinity = maximumNuberOfNewNodes * INFINITY_SCALE
193 queryEngine = ViatraQueryEngine.on(new EMFScope(p))
194 updatersBuilder = ImmutableList.builder
195 for (pair : constraints.entrySet.filter[key.containment].groupBy[key.targetType].entrySet) {
196 buildContainmentConstraints(pair.key, pair.value)
197 }
198 for (pair : constraints.entrySet) {
199 val constraint = pair.key
200 if (!constraint.containment) {
201 buildNonContainmentConstraints(constraint, pair.value)
202 }
203 }
204 updaters = updatersBuilder.build
205 addCachedConstraintsToPolyhedron()
206 }
207
208 private def addCachedConstraintsToPolyhedron() {
209 val constraints = new HashSet
210 constraints.addAll(expressionsCache.values.filter(LinearConstraint))
211 constraints.removeAll(polyhedron.constraints)
212 polyhedron.constraints.addAll(constraints)
213 }
214
215 private def buildContainmentConstraints(Type containedType,
216 List<Map.Entry<RelationMultiplicityConstraint, UnifinishedMultiplicityQueries>> constraints) {
217 val typeCoefficients = subtypeDimensions.get(containedType)
218 val orphansLowerBoundCoefficients = new HashMap(typeCoefficients)
219 val orphansUpperBoundCoefficients = new HashMap(typeCoefficients)
220 val unfinishedMultiplicitiesMatchersBuilder = ImmutableList.builder
221 val remainingContentsQueriesBuilder = ImmutableList.builder
222 for (pair : constraints) {
223 val constraint = pair.key
224 val containerCoefficients = subtypeDimensions.get(constraint.sourceType)
225 if (constraint.isUpperBoundFinite) {
226 orphansLowerBoundCoefficients.addCoefficients(-constraint.upperBound, containerCoefficients)
227 } else {
228 orphansLowerBoundCoefficients.addCoefficients(-infinity, containerCoefficients)
229 }
230 orphansUpperBoundCoefficients.addCoefficients(-constraint.lowerBound, containerCoefficients)
231 val queries = pair.value
232 if (constraint.constrainsUnfinished) {
233 if (queries.unfinishedMultiplicityQuery === null) {
234 throw new IllegalArgumentException(
235 "Containment constraints need unfinished multiplicity queries")
236 }
237 unfinishedMultiplicitiesMatchersBuilder.add(
238 queries.unfinishedMultiplicityQuery.getMatcher(queryEngine))
239 }
240 if (queries.remainingContentsQuery === null) {
241 throw new IllegalArgumentException("Containment constraints need remaining contents queries")
242 }
243 remainingContentsQueriesBuilder.add(queries.remainingContentsQuery.getMatcher(queryEngine))
244 }
245 val orphanLowerBound = orphansLowerBoundCoefficients.toExpression
246 val orphanUpperBound = orphansUpperBoundCoefficients.toExpression
247 val updater = new ContainmentConstraintUpdater(containedType.name, orphanLowerBound, orphanUpperBound,
248 unfinishedMultiplicitiesMatchersBuilder.build, remainingContentsQueriesBuilder.build)
249 updatersBuilder.add(updater)
250 }
251
252 private def buildNonContainmentConstraints(RelationMultiplicityConstraint constraint,
253 UnifinishedMultiplicityQueries queries) {
254 }
255
256 private def addCoefficients(Map<Dimension, Integer> accumulator, int scale, Map<Dimension, Integer> a) {
257 for (pair : a.entrySet) {
258 val dimension = pair.key
259 val currentValue = accumulator.get(pair.key) ?: 0
260 val newValue = currentValue + scale * pair.value
261 if (newValue == 0) {
262 accumulator.remove(dimension)
263 } else {
264 accumulator.put(dimension, newValue)
265 }
266 }
267 }
268
269 private def findSubtypeDimensions(Type type) {
270 val subtypes = new HashSet
271 val dimensions = new HashSet
272 val stack = new ArrayDeque
273 stack.addLast(type)
274 while (!stack.empty) {
275 val subtype = stack.removeLast
276 if (subtypes.add(subtype)) {
277 val dimension = instanceCounts.get(subtype)
278 if (dimension !== null) {
279 dimensions.add(dimension)
280 }
281 stack.addAll(subtype.subtypes)
282 }
283 }
284 dimensions
285 }
286
287 private def toExpression(Map<Dimension, Integer> coefficients) {
288 expressionsCache.computeIfAbsent(coefficients) [ c |
289 if (c.size == 1 && c.entrySet.head.value == 1) {
290 c.entrySet.head.key
291 } else {
292 new LinearConstraint(c, null, null)
293 }
294 ]
295 }
296
297 private def buildScopeBounds() {
298 val scopeBoundsBuilder = ImmutableMap.builder
299 for (scope : p.scopes) {
300 switch (targetTypeInterpretation : scope.targetTypeInterpretation) {
301 PartialPrimitiveInterpretation:
302 throw new OperationNotSupportedException("Primitive type scopes are not yet implemented")
303 PartialComplexTypeInterpretation: {
304 val complexType = targetTypeInterpretation.interpretationOf
305 val typeBound = typeBounds.get(complexType)
306 if (typeBound === null) {
307 if (scope.minNewElements > 0) {
308 throw new IllegalArgumentException("Found scope for " + complexType.name +
309 ", but the type cannot be instantiated")
310 }
311 } else {
312 scopeBoundsBuilder.put(scope, typeBound)
313 }
314 }
315 default:
316 throw new IllegalArgumentException("Unknown PartialTypeInterpretation: " +
317 targetTypeInterpretation)
318 }
319 }
320 scopeBoundsBuilder.build
321 }
322 }
323
324 private static interface RelationConstraintUpdater {
325 def void update(PartialInterpretation p)
326 }
327
328 @FinalFieldsConstructor
329 static class ContainmentConstraintUpdater implements RelationConstraintUpdater {
330 val String name
331 val LinearBoundedExpression orphansLowerBound
332 val LinearBoundedExpression orphansUpperBound
333 val List<ViatraQueryMatcher<? extends IPatternMatch>> unfinishedMultiplicitiesMatchers
334 val List<ViatraQueryMatcher<? extends IPatternMatch>> remainingContentsQueries
335
336 override update(PartialInterpretation p) {
337 tightenLowerBound(p)
338 tightenUpperBound(p)
339 }
340
341 private def tightenLowerBound(PartialInterpretation p) {
342 var int sum = 0
343 for (matcher : remainingContentsQueries) {
344 val value = matcher.getCalculatedMultiplicity(p)
345 if (value === null) {
346 throw new IllegalArgumentException("Remaining contents count is missing for " + name)
347 }
348 if (value == -1) {
349 // Infinite upper bound, no need to tighten.
350 return
351 }
352 sum += value
353 }
354 orphansLowerBound.tightenUpperBound(sum)
355 }
356
357 private def tightenUpperBound(PartialInterpretation p) {
358 var int sum = 0
359 for (matcher : unfinishedMultiplicitiesMatchers) {
360 val value = matcher.getCalculatedMultiplicity(p)
361 if (value === null) {
362 throw new IllegalArgumentException("Unfinished multiplicity is missing for " + name)
363 }
364 sum += value
365 }
366 orphansUpperBound.tightenLowerBound(sum)
367 }
368 }
369
370 @FinalFieldsConstructor
371 static class ContainmentRootConstraintUpdater implements RelationConstraintUpdater {
372
373 override update(PartialInterpretation p) {
374 throw new UnsupportedOperationException("TODO: auto-generated method stub")
375 }
376 }
154} 377}
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronSolver.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronSolver.xtend
index 08bf25b9..9c6cb82e 100644
--- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronSolver.xtend
+++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/PolyhedronSolver.xtend
@@ -52,18 +52,14 @@ class Polyhedron {
52 val List<LinearBoundedExpression> expressionsToSaturate 52 val List<LinearBoundedExpression> expressionsToSaturate
53 53
54 override toString() ''' 54 override toString() '''
55 Dimensions: 55 Dimensions:
56 «FOR dimension : dimensions» 56 «FOR dimension : dimensions»
57 «dimension» 57 «dimension»
58 «ENDFOR» 58 «ENDFOR»
59 Constraints: 59 Constraints:
60 «FOR constraint : constraints» 60 «FOR constraint : constraints»
61 «constraint» 61 «constraint»
62 «ENDFOR» 62 «ENDFOR»
63««« Saturate:
64««« «FOR expression : expressionsToSaturate»
65««« «IF expression instanceof Dimension»dimension«ELSEIF expression instanceof LinearConstraint»constraint«ELSE»unknown«ENDIF» «expression»
66««« «ENDFOR»
67 ''' 63 '''
68 64
69} 65}
@@ -72,6 +68,18 @@ class Polyhedron {
72abstract class LinearBoundedExpression { 68abstract class LinearBoundedExpression {
73 var Integer lowerBound 69 var Integer lowerBound
74 var Integer upperBound 70 var Integer upperBound
71
72 def void tightenLowerBound(Integer tighterBound) {
73 if (lowerBound === null || (tighterBound !== null && lowerBound < tighterBound)) {
74 lowerBound = tighterBound
75 }
76 }
77
78 def void tightenUpperBound(Integer tighterBound) {
79 if (upperBound === null || (tighterBound !== null && upperBound > tighterBound)) {
80 upperBound = tighterBound
81 }
82 }
75} 83}
76 84
77@Accessors 85@Accessors
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/RelationConstraintCalculator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/RelationConstraintCalculator.xtend
new file mode 100644
index 00000000..ffa9e6e6
--- /dev/null
+++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/RelationConstraintCalculator.xtend
@@ -0,0 +1,133 @@
1package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality
2
3import com.google.common.collect.ImmutableList
4import com.google.common.collect.ImmutableSet
5import hu.bme.mit.inf.dslreasoner.ecore2logic.ecore2logicannotations.InverseRelationAssertion
6import hu.bme.mit.inf.dslreasoner.ecore2logic.ecore2logicannotations.LowerMultiplicityAssertion
7import hu.bme.mit.inf.dslreasoner.ecore2logic.ecore2logicannotations.UpperMultiplicityAssertion
8import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.ComplexTypeReference
9import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Relation
10import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem
11import java.util.HashMap
12import java.util.List
13import org.eclipse.xtend.lib.annotations.Data
14
15@Data
16class RelationConstraints {
17 val List<RelationMultiplicityConstraint> multiplicityConstraints
18}
19
20@Data
21class RelationMultiplicityConstraint {
22 Relation relation
23 boolean containment
24 boolean container
25 int lowerBound
26 int upperBound
27 int inverseUpperBound
28
29 def isUpperBoundFinite() {
30 upperBound >= 0
31 }
32
33 private def isInverseUpperBoundFinite() {
34 inverseUpperBound >= 0
35 }
36
37 private def canHaveMultipleSourcesPerTarget() {
38 inverseUpperBound != 1
39 }
40
41 def constrainsUnfinished() {
42 lowerBound >= 1 && (!container || lowerBound >= 2)
43 }
44
45 def constrainsUnrepairable() {
46 constrainsUnfinished && canHaveMultipleSourcesPerTarget
47 }
48
49 def constrainsRemainingInverse() {
50 !containment && inverseUpperBoundFinite
51 }
52
53 def constrainsRemainingContents() {
54 containment
55 }
56
57 def isActive() {
58 constrainsUnfinished || constrainsUnrepairable || constrainsRemainingInverse || constrainsRemainingContents
59 }
60
61 def getSourceType() {
62 getParamType(0)
63 }
64
65 def getTargetType() {
66 getParamType(1)
67 }
68
69 private def getParamType(int i) {
70 val parameters = relation.parameters
71 if (i < parameters.size) {
72 val firstParam = parameters.get(i)
73 if (firstParam instanceof ComplexTypeReference) {
74 return firstParam.referred
75 }
76 }
77 throw new IllegalArgumentException("Constraint with unknown source type")
78 }
79}
80
81class RelationConstraintCalculator {
82 def calculateRelationConstraints(LogicProblem problem) {
83 val containmentRelations = switch (problem.containmentHierarchies.size) {
84 case 0:
85 <Relation>emptySet
86 case 1:
87 ImmutableSet.copyOf(problem.containmentHierarchies.head.containmentRelations)
88 default:
89 throw new IllegalArgumentException("Only a single containment hierarchy is supported")
90 }
91 val inverseRelations = new HashMap<Relation, Relation>
92 val lowerMultiplicities = new HashMap<Relation, Integer>
93 val upperMultiplicities = new HashMap<Relation, Integer>
94 for (relation : problem.relations) {
95 lowerMultiplicities.put(relation, 0)
96 upperMultiplicities.put(relation, -1)
97 }
98 for (annotation : problem.annotations) {
99 switch (annotation) {
100 InverseRelationAssertion: {
101 inverseRelations.put(annotation.inverseA, annotation.inverseB)
102 inverseRelations.put(annotation.inverseB, annotation.inverseA)
103 }
104 LowerMultiplicityAssertion:
105 lowerMultiplicities.put(annotation.relation, annotation.lower)
106 UpperMultiplicityAssertion:
107 upperMultiplicities.put(annotation.relation, annotation.upper)
108 }
109 }
110 val multiplicityConstraintsBuilder = ImmutableList.builder()
111 for (relation : problem.relations) {
112 val containment = containmentRelations.contains(relation)
113 val lowerMultiplicity = lowerMultiplicities.get(relation)
114 val upperMultiplicity = upperMultiplicities.get(relation)
115 var container = false
116 var inverseUpperMultiplicity = -1
117 val inverseRelation = inverseRelations.get(relation)
118 if (inverseRelation !== null) {
119 inverseUpperMultiplicity = upperMultiplicities.get(relation)
120 container = containmentRelations.contains(inverseRelation)
121 }
122 val constraint = new RelationMultiplicityConstraint(relation, containment, container, lowerMultiplicity,
123 upperMultiplicity, inverseUpperMultiplicity)
124 if (constraint.isActive) {
125 if (relation.parameters.size != 2) {
126 throw new IllegalArgumentException('''Relation «relation.name» has multiplicity or containment constraints, but it is not binary''')
127 }
128 multiplicityConstraintsBuilder.add(constraint)
129 }
130 }
131 new RelationConstraints(multiplicityConstraintsBuilder.build)
132 }
133}
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/ScopePropagator.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/ScopePropagator.xtend
index f0494214..3b442cd3 100644
--- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/ScopePropagator.xtend
+++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/ScopePropagator.xtend
@@ -10,11 +10,6 @@ import java.util.Map
10import java.util.Set 10import java.util.Set
11import org.eclipse.xtend.lib.annotations.Accessors 11import org.eclipse.xtend.lib.annotations.Accessors
12 12
13enum ScopePropagatorStrategy {
14 BasicTypeHierarchy,
15 PolyhedralTypeHierarchy
16}
17
18class ScopePropagator { 13class ScopePropagator {
19 @Accessors(PROTECTED_GETTER) PartialInterpretation partialInterpretation 14 @Accessors(PROTECTED_GETTER) PartialInterpretation partialInterpretation
20 Map<PartialTypeInterpratation, Scope> type2Scope 15 Map<PartialTypeInterpratation, Scope> type2Scope
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/ScopePropagatorStrategy.java b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/ScopePropagatorStrategy.java
new file mode 100644
index 00000000..b1c5a658
--- /dev/null
+++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/cardinality/ScopePropagatorStrategy.java
@@ -0,0 +1,18 @@
1package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality;
2
3public enum ScopePropagatorStrategy {
4 BasicTypeHierarchy,
5
6 PolyhedralTypeHierarchy,
7
8 PolyhedralRelations {
9 @Override
10 public boolean requiresUpperBoundIndexing() {
11 return true;
12 }
13 };
14
15 public boolean requiresUpperBoundIndexing() {
16 return false;
17 }
18}