aboutsummaryrefslogtreecommitdiffstats
path: root/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra/src/hu/bme/mit/inf/dslreasoner/viatrasolver/logic2viatra/patterns/RelationDeclarationIndexer.xtend
blob: f384cd50b51283d689a8aa43e63b3e6d3c748afe (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
package hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns

import hu.bme.mit.inf.dslreasoner.ecore2logic.ecore2logicannotations.UpperMultiplicityAssertion
import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Relation
import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RelationDeclaration
import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem
import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.Modality
import java.util.HashMap
import java.util.List
import java.util.Map
import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery

import static extension hu.bme.mit.inf.dslreasoner.util.CollectionsUtil.*

class RelationDeclarationIndexer {
	val PatternGenerator base;
	
	new(PatternGenerator base) {
		this.base = base
	}
	
	public def generateRelationIndexers(LogicProblem problem, Iterable<RelationDeclaration> relations, Map<String,PQuery> fqn2PQuery) {
		val upperMultiplicities = new HashMap
		problem.annotations.filter(UpperMultiplicityAssertion).forEach[
			upperMultiplicities.put(it.relation,it.upper)
		]
		
		return '''
		«FOR relation : relations»
			«IF base.isDerived(relation)»
				«generateDerivedMustRelation(problem,relation,base.getDerivedDefinition(relation).patternFullyQualifiedName.lookup(fqn2PQuery))»
				«generateDerivedMayRelation(problem,relation,base.getDerivedDefinition(relation).patternFullyQualifiedName.lookup(fqn2PQuery))»
			«ELSE»
				«generateMustRelation(problem,relation)»
				«generateMayRelation(problem,relation,upperMultiplicities,base.getContainments(problem),base.getInverseRelations(problem),fqn2PQuery)»
			«ENDIF»
		«ENDFOR»
		'''
	}
	
	def private patternName(RelationDeclaration r, Modality modality) {
		'''«modality.name.toLowerCase»InRelation«base.canonizeName(r.name)»'''
	}
	
	public def referRelation(
		RelationDeclaration referred,
		String sourceVariable,
		String targetVariable,
		Modality modality)
	'''find «referred.patternName(modality)»(problem,interpretation,«sourceVariable»,«targetVariable»);'''
	
	def generateMustRelation(LogicProblem problem, RelationDeclaration relation) '''
		/**
		 * Matcher for detecting tuples t where []«relation.name»(source,target)
		 */
		private pattern «relation.patternName(Modality.MUST)»(
			problem:LogicProblem, interpretation:PartialInterpretation,
			source: DefinedElement, target:DefinedElement)
		{
			find interpretation(problem,interpretation);
			PartialInterpretation.partialrelationinterpretation(interpretation,relationIterpretation);
			PartialRelationInterpretation.interpretationOf.name(relationIterpretation,"«relation.name»");
			PartialRelationInterpretation.relationlinks(relationIterpretation,link);
			BinaryElementRelationLink.param1(link,source);
			BinaryElementRelationLink.param2(link,target);
		}
	'''
	def generateMayRelation(LogicProblem problem, RelationDeclaration relation,
		Map<Relation, Integer> upperMultiplicities,
		List<Relation> containments,
		HashMap<Relation, Relation> inverseRelations,
		Map<String,PQuery> fqn2PQuery)
	{
		return '''
		/**
		 * Matcher for detecting tuples t where <>«relation.name»(source,target)
		 */
		private pattern «relation.patternName(Modality.MAY)»(
			problem:LogicProblem, interpretation:PartialInterpretation,
			source: DefinedElement, target:DefinedElement)
		{
			find interpretation(problem,interpretation);
			// The two endpoint of the link have to exist
			find mayExist(problem, interpretation, source);
			find mayExist(problem, interpretation, target);
			// Type consistency
			«base.typeIndexer.referInstanceOfByReference(relation.parameters.get(0),Modality.MAY,"source")»
			«base.typeIndexer.referInstanceOfByReference(relation.parameters.get(1),Modality.MAY,"target")»
			«IF upperMultiplicities.containsKey(relation)»
				// There are "numberOfExistingReferences" currently existing instances of the reference from the source,
				// the upper bound of the multiplicity should be considered.
				numberOfExistingReferences == count «referRelation(relation,"source","_",Modality.MUST)»
				check(numberOfExistingReferences < «upperMultiplicities.get(relation)»);
			«ENDIF»
			«IF inverseRelations.containsKey(relation) && upperMultiplicities.containsKey(inverseRelations.get(relation))»
				// There are "numberOfExistingReferences" currently existing instances of the reference to the target,
				// the upper bound of the opposite reference multiplicity should be considered.
				numberOfExistingOppositeReferences == count «base.referRelation(inverseRelations.get(relation),"target","_",Modality.MUST,fqn2PQuery)»
				check(numberOfExistingOppositeReferences < «upperMultiplicities.get(inverseRelations.get(relation))»);
			«ENDIF»
			«IF containments.contains(relation)»
				// The reference is containment, then a new reference cannot be create if:
				// 1. Multiple parents
				neg «base.containmentIndexer.referMustContaint("_","target")»
				// 2. Circle in the containment hierarchy
				neg «base.containmentIndexer.referTransitiveMustContains("target","source")»
			«ENDIF»
			«IF inverseRelations.containsKey(relation) && containments.contains(inverseRelations.get(relation))»
				// The eOpposite of the reference is containment, then a referene cannot be created if
				// 1. Multiple parents
				neg «base.containmentIndexer.referMustContaint("source","_")»
				// 2. Circle in the containment hierarchy
				neg «base.containmentIndexer.referTransitiveMustContains("source","target")»
			«ENDIF»
		} or {
			«relation.referRelation("source","target",Modality.MUST)»
		}
	'''
	}
	
	def generateDerivedMustRelation(LogicProblem problem, RelationDeclaration relation, PQuery definition) '''
		/**
		 * Matcher for detecting tuples t where []«relation.name»(source,target)
		 */
		 private pattern «relation.patternName(Modality.MUST)»(
		 	problem:LogicProblem, interpretation:PartialInterpretation,
		 	source: DefinedElement, target:DefinedElement)
		 {
		 	«base.relationDefinitionIndexer.referPattern(definition,#["source","target"],Modality::MUST,true,false)»
		 }
	'''
	def generateDerivedMayRelation(LogicProblem problem, RelationDeclaration relation, PQuery definition) '''
		/**
		 * Matcher for detecting tuples t where []«relation.name»(source,target)
		 */
		 private pattern «relation.patternName(Modality.MAY)»(
		 	problem:LogicProblem, interpretation:PartialInterpretation,
		 	source: DefinedElement, target:DefinedElement)
		 {
		 	«base.relationDefinitionIndexer.referPattern(definition,#["source","target"],Modality::MAY,true,false)»
		 }
	'''
}