1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableSet
import hu.bme.mit.inf.dslreasoner.ecore2logic.ecore2logicannotations.InverseRelationAssertion
import hu.bme.mit.inf.dslreasoner.ecore2logic.ecore2logicannotations.LowerMultiplicityAssertion
import hu.bme.mit.inf.dslreasoner.ecore2logic.ecore2logicannotations.UpperMultiplicityAssertion
import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.ComplexTypeReference
import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Relation
import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem
import java.util.HashMap
import java.util.List
import org.eclipse.xtend.lib.annotations.Data
@Data
class RelationConstraints {
val List<RelationMultiplicityConstraint> multiplicityConstraints
}
@Data
class RelationMultiplicityConstraint {
Relation relation
Relation inverseRelation
boolean containment
boolean container
int lowerBound
int upperBound
int inverseUpperBound
def isUpperBoundFinite() {
upperBound >= 0
}
private def isInverseUpperBoundFinite() {
inverseUpperBound >= 0
}
private def canHaveMultipleSourcesPerTarget() {
inverseUpperBound != 1
}
def constrainsUnfinished() {
lowerBound >= 1 && (!container || lowerBound >= 2)
}
def constrainsUnrepairable() {
// TODO Optimize the unrepairable matches computation,
// or come up with a heuristic when does computing unrepairables worth the overhead.
false && constrainsUnfinished && canHaveMultipleSourcesPerTarget && reference
}
def constrainsRemainingInverse() {
lowerBound >= 1 && !containment && !container && inverseUpperBoundFinite && reference
}
def constrainsRemainingContents() {
containment
}
def isActive() {
constrainsUnfinished || constrainsUnrepairable || constrainsRemainingInverse || constrainsRemainingContents
}
def isSourceTypeComplex() {
getParamTypeReference(0) instanceof ComplexTypeReference
}
def isTargetTypeComplex() {
getParamTypeReference(1) instanceof ComplexTypeReference
}
def isReference() {
sourceTypeComplex && targetTypeComplex
}
def getSourceType() {
getParamType(0)
}
def getTargetType() {
getParamType(1)
}
private def getParamTypeReference(int i) {
val parameters = relation.parameters
if (i < parameters.size) {
return parameters.get(i)
}
throw new IllegalArgumentException("Argument index out of range")
}
private def getParamType(int i) {
val reference = getParamTypeReference(i)
if (reference instanceof ComplexTypeReference) {
return reference.referred
}
throw new IllegalArgumentException("Constraint with primitive type")
}
}
class RelationConstraintCalculator {
def calculateRelationConstraints(LogicProblem problem) {
val containmentRelations = switch (problem.containmentHierarchies.size) {
case 0:
<Relation>emptySet
case 1:
ImmutableSet.copyOf(problem.containmentHierarchies.head.containmentRelations)
default:
throw new IllegalArgumentException("Only a single containment hierarchy is supported")
}
val inverseRelations = new HashMap<Relation, Relation>
val lowerMultiplicities = new HashMap<Relation, Integer>
val upperMultiplicities = new HashMap<Relation, Integer>
for (relation : problem.relations) {
lowerMultiplicities.put(relation, 0)
upperMultiplicities.put(relation, -1)
}
for (annotation : problem.annotations) {
switch (annotation) {
InverseRelationAssertion: {
inverseRelations.put(annotation.inverseA, annotation.inverseB)
inverseRelations.put(annotation.inverseB, annotation.inverseA)
}
LowerMultiplicityAssertion:
lowerMultiplicities.put(annotation.relation, annotation.lower)
UpperMultiplicityAssertion:
upperMultiplicities.put(annotation.relation, annotation.upper)
}
}
val multiplicityConstraintsBuilder = ImmutableList.builder()
for (relation : problem.relations) {
val containment = containmentRelations.contains(relation)
val lowerMultiplicity = lowerMultiplicities.get(relation)
val upperMultiplicity = upperMultiplicities.get(relation)
var container = false
var inverseUpperMultiplicity = -1
val inverseRelation = inverseRelations.get(relation)
if (inverseRelation !== null) {
inverseUpperMultiplicity = upperMultiplicities.get(inverseRelation)
container = containmentRelations.contains(inverseRelation)
}
if (containment) {
inverseUpperMultiplicity = 1
}
val constraint = new RelationMultiplicityConstraint(relation, inverseRelation, containment, container,
lowerMultiplicity, upperMultiplicity, inverseUpperMultiplicity)
if (constraint.isActive) {
if (relation.parameters.size != 2) {
throw new IllegalArgumentException('''Relation «relation.name» has multiplicity or containment constraints, but it is not binary''')
}
multiplicityConstraintsBuilder.add(constraint)
}
}
new RelationConstraints(multiplicityConstraintsBuilder.build)
}
}
|