aboutsummaryrefslogtreecommitdiffstats
path: root/Framework/hu.bme.mit.inf.dslreasoner.ecore2logic/src/hu/bme/mit/inf/dslreasoner/ecore2logic/EReferenceMapper.xtend
blob: 4eb78bc69ba03c61379ad74f05c54e2f0e1bd624 (plain) (blame)
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
157
158
159
160
package hu.bme.mit.inf.dslreasoner.ecore2logic

import hu.bme.mit.inf.dslreasoner.ecore2logic.ecore2logicannotations.Ecore2logicannotationsFactory
import hu.bme.mit.inf.dslreasoner.logic.model.builder.LogicProblemBuilder
import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Assertion
import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RelationDeclaration
import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Term
import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.TermDescription
import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem
import java.util.HashMap
import java.util.Map
import org.eclipse.emf.ecore.EClass
import org.eclipse.emf.ecore.EReference

interface EReferenceMapper{
	def void transformEReferences(Ecore2Logic_Trace trace, LogicProblem problem, Iterable<EReference> classes);
	def Iterable<EReference> allReferencesInScope(Ecore2Logic_Trace trace) 
	def Term IsInReference(Ecore2Logic_Trace trace, TermDescription source, TermDescription target, EReference type)
	def RelationDeclaration relationOfReference(Ecore2Logic_Trace trace, EReference reference)
}

class EReferenceMapper_RelationsOverTypes_Trace implements Trace<EReferenceMapper_RelationsOverTypes> {
	public var Map<EReference, RelationDeclaration> indicators;
	public var Map<EReference, Assertion> typeCompliance
	public var Map<EReference, Assertion> lowerMultiplicity
	public var Map<EReference, Assertion> upperMultiplicity
	public var Map<EReference, Assertion> inverseEdges
}

class EReferenceMapper_RelationsOverTypes implements EReferenceMapper{
	val extension LogicProblemBuilder builder = new LogicProblemBuilder
	val extension Ecore2logicannotationsFactory builder2 = Ecore2logicannotationsFactory.eINSTANCE
	val extension EClassMapper classMapper;
	
	public new(EClassMapper classMapper) {
		this.classMapper = classMapper
	}
	
	def asTrace(Trace<? extends EReferenceMapper> o) { o as EReferenceMapper_RelationsOverTypes_Trace }
	
	override transformEReferences(Ecore2Logic_Trace trace, LogicProblem problem, Iterable<EReference> references) {
		val newTrace = new EReferenceMapper_RelationsOverTypes_Trace
		trace.referenceMapperTrace = newTrace
		trace.createIndicatorDeclarations(problem,references)
		trace.createMultiplicityConstraints(problem,references)
		trace.createInverseReferenceConstraints(problem,references)
	}
	
	def protected void createIndicatorDeclarations(Ecore2Logic_Trace trace, LogicProblem problem, Iterable<EReference> references) {
		trace.referenceMapperTrace.asTrace.indicators = new HashMap
		for(reference : references) {
			val relation = problem.add(RelationDeclaration(
				'''«reference.name» reference «reference.EContainingClass.name»''',
				TypeofEClass(trace,reference.EContainingClass),
				TypeofEClass(trace,reference.EType as EClass)))
			trace.referenceMapperTrace.asTrace.indicators.put(reference,relation as RelationDeclaration)
		}
	}
	
	def void createMultiplicityConstraints(Ecore2Logic_Trace trace, LogicProblem problem, Iterable<EReference> references) {
		trace.referenceMapperTrace.asTrace.lowerMultiplicity = new HashMap
		trace.referenceMapperTrace.asTrace.upperMultiplicity = new HashMap
		
		for(reference : references) {
			val sourceType = reference.EContainingClass
			val targetType = reference.EType as EClass
			val lower = reference.lowerBound
			val upper = reference.upperBound
			
			if (lower > 0) {
				val assertion = Assertion('''lowerMultiplicity «reference.name» «sourceType.name»''',
					Forall[
						val source = addVar('''src''', trace.TypeofEClass(sourceType))
						Exists[ context |
							val targets = (1 .. lower).map[
								context.addVar('''trg «it»''', trace.TypeofEClass(targetType))].toList
							val inReference = And(targets.map[IsInReference(trace, source, it, reference)])
							if(targets.size > 1) return Distinct(targets) && inReference
							else return inReference
						]
					]
				)
				val annotation = createLowerMultiplicityAssertion => [
					it.lower = lower
					it.relation = trace.referenceMapperTrace.asTrace.indicators.get(reference)
				]
				
				problem.add(assertion)
				problem.annotations += annotation
				assertion.annotations +=annotation
				trace.referenceMapperTrace.asTrace.lowerMultiplicity.put(reference,assertion)
			}
			else trace.referenceMapperTrace.asTrace.lowerMultiplicity.put(reference,null)
			
			if(upper != -1) {
				val assertion = Assertion('''upperMultiplicity «reference.name» «sourceType.name»''',
					Forall[ context |
						val source = context.addVar('''src''', trace.TypeofEClass(sourceType))
						val targets = (1 .. upper+1).map[
								context.addVar('''trg «it»''', trace.TypeofEClass(targetType))].toList
						And(targets.map[IsInReference(trace, source, it, reference)]) => ! Distinct(targets)
					])
				val annotation = createUpperMultiplicityAssertion => [
					it.upper = upper
					it.relation = trace.referenceMapperTrace.asTrace.indicators.get(reference)
				]
				
				problem.add(assertion)
				problem.annotations += annotation
				assertion.annotations += annotation
				trace.referenceMapperTrace.asTrace.lowerMultiplicity.put(reference,assertion)
			}
			else trace.referenceMapperTrace.asTrace.upperMultiplicity.put(reference,null)
		}
	}
	
	def createInverseReferenceConstraints(Ecore2Logic_Trace trace, LogicProblem problem, Iterable<EReference> references) {
		trace.referenceMapperTrace.asTrace.inverseEdges = new HashMap
		for(reference : references) {
			if(reference.EOpposite!=null) {
				val opposite = reference.EOpposite
				if(trace.referenceMapperTrace.asTrace.inverseEdges.containsKey(opposite)) {
					trace.referenceMapperTrace.asTrace.inverseEdges.put(reference,trace.referenceMapperTrace.asTrace.inverseEdges.get(opposite))
				} else {
					val sourceType = reference.EContainingClass
					val targetType = reference.EType as EClass
					val assertion = Assertion('''oppositeReference «reference.name» «sourceType.name»''',
						Forall[
							val src = addVar('''src''', trace.TypeofEClass(sourceType))
							val trg = addVar('''trg''', trace.TypeofEClass(targetType))
							IsInReference(trace,src,trg,reference) <=> IsInReference(trace,trg,src,opposite)
						]
					)
					problem.add(assertion)
					trace.referenceMapperTrace.asTrace.inverseEdges.put(reference,assertion)
					val annotation = createInverseRelationAssertion => [
						it.target = assertion
						it.inverseA = trace.referenceMapperTrace.asTrace.indicators.get(reference)
						it.inverseB = trace.referenceMapperTrace.asTrace.indicators.get(reference.EOpposite)
					]
					problem.annotations += annotation
				}
			}
			else trace.referenceMapperTrace.asTrace.inverseEdges.put(reference,null)
		}
	}
	
	override IsInReference(Ecore2Logic_Trace trace, TermDescription source, TermDescription target, EReference type) {
		trace.referenceMapperTrace.asTrace.indicators.get(type).call(source,target)
	}
	
	override relationOfReference(Ecore2Logic_Trace trace, EReference reference) {
		trace.referenceMapperTrace.asTrace.indicators.get(reference)
	}
	
	override allReferencesInScope(Ecore2Logic_Trace trace) {
		trace.referenceMapperTrace.asTrace.indicators.keySet
	}
	
}