aboutsummaryrefslogtreecommitdiffstats
path: root/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <marussy@mit.bme.hu>2020-11-02 02:02:40 +0100
committerLibravatar Kristóf Marussy <marussy@mit.bme.hu>2020-11-02 02:02:40 +0100
commitf06427cd7375551582461f91b3458339a8227f9b (patch)
tree97bc6ec85f4c384e5080a6611b492caf460b6ce9 /Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization
parentMust unit propagation (diff)
downloadVIATRA-Generator-f06427cd7375551582461f91b3458339a8227f9b.tar.gz
VIATRA-Generator-f06427cd7375551582461f91b3458339a8227f9b.tar.zst
VIATRA-Generator-f06427cd7375551582461f91b3458339a8227f9b.zip
Optimizing generator with linear objective functions
Diffstat (limited to 'Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization')
-rw-r--r--Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/CostElementMatchers.xtend137
-rw-r--r--Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/CostObjectiveHint.xtend68
-rw-r--r--Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/IObjectiveBoundsProvider.xtend8
-rw-r--r--Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/ThreeValuedCostObjective.xtend99
-rw-r--r--Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/ThreeValuedCostObjectiveProvider.xtend205
5 files changed, 465 insertions, 52 deletions
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/CostElementMatchers.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/CostElementMatchers.xtend
new file mode 100644
index 00000000..885b14e8
--- /dev/null
+++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/CostElementMatchers.xtend
@@ -0,0 +1,137 @@
1package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization
2
3import com.google.common.collect.ImmutableList
4import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicproblemPackage
5import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialinterpretationPackage
6import java.util.List
7import org.eclipse.emf.ecore.EObject
8import org.eclipse.viatra.query.runtime.api.IPatternMatch
9import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher
10import org.eclipse.xtend.lib.annotations.Data
11import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem
12import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation
13
14@FunctionalInterface
15interface ParameterScopeBound {
16 def double getUpperBound()
17}
18
19@Data
20class CostElementMatch {
21 val IPatternMatch match
22 val boolean must
23
24 def isMulti() {
25 CostElementMatchers.isMultiMatch(match)
26 }
27}
28
29@Data
30class CostElementMatchers {
31 val ViatraQueryMatcher<? extends IPatternMatch> currentMatcher
32 val ViatraQueryMatcher<? extends IPatternMatch> mayMatcher
33 val ViatraQueryMatcher<? extends IPatternMatch> mustMatcher
34 val List<ParameterScopeBound> parameterScopeBounds
35 val int weight
36
37 def getCurrentNumberOfMatches() {
38 currentMatcher.countMatches
39 }
40
41 def getMinimumNumberOfMatches() {
42 mustMatcher.countMatches
43 }
44
45 def getMaximumNumberOfMatches() {
46 var double sum = 0
47 val iterator = mayMatcher.streamAllMatches.iterator
48 while (iterator.hasNext) {
49 val match = iterator.next
50 var double product = 1
51 val numberOfParameters = parameterScopeBounds.size
52 for (var int i = 0; i < numberOfParameters; i++) {
53 if (isMulti(match.get(i + 2))) {
54 val scopeBound = parameterScopeBounds.get(i)
55 product *= scopeBound.upperBound
56 }
57
58 }
59 sum += product
60 }
61 sum
62 }
63
64 def getMatches() {
65 ImmutableList.copyOf(mayMatcher.streamAllMatches.iterator.map [ match |
66 new CostElementMatch(match, mustMatcher.isMatch(match))
67 ])
68 }
69
70 def projectMayMatch(IPatternMatch match, int... indices) {
71 mayMatcher.projectMatch(match, indices)
72 }
73
74 private static def <T extends IPatternMatch> projectMatch(ViatraQueryMatcher<T> matcher, IPatternMatch match, int... indices) {
75 checkMatch(match)
76 val n = matcher.specification.parameters.length - 2
77 if (indices.length != n) {
78 throw new IllegalArgumentException("Invalid number of projection indices")
79 }
80 val newMatch = matcher.newEmptyMatch
81 newMatch.set(0, match.get(0))
82 newMatch.set(1, match.get(1))
83 for (var int i = 0; i < n; i++) {
84 newMatch.set(i + 2, match.get(indices.get(i)))
85 }
86 if (!matcher.hasMatch(newMatch)) {
87 throw new IllegalArgumentException("Projected match does not exist")
88 }
89 return newMatch
90 }
91
92 private static def <T extends IPatternMatch> isMatch(ViatraQueryMatcher<T> matcher, IPatternMatch match) {
93 val n = matcher.specification.parameters.length
94 if (n != match.specification.parameters.length) {
95 throw new IllegalArgumentException("Invalid number of match arguments")
96 }
97 val newMatch = matcher.newEmptyMatch
98 for (var int i = 0; i < n; i++) {
99 newMatch.set(i, match.get(i))
100 }
101 return matcher.hasMatch(newMatch)
102 }
103
104 static def isMulti(Object o) {
105 if (o instanceof EObject) {
106 switch (feature : o.eContainmentFeature) {
107 case LogicproblemPackage.eINSTANCE.logicProblem_Elements,
108 case PartialinterpretationPackage.eINSTANCE.partialInterpretation_NewElements:
109 false
110 case PartialinterpretationPackage.eINSTANCE.partialInterpretation_OpenWorldElements:
111 true
112 default:
113 throw new IllegalStateException("Unknown containment feature for element: " + feature)
114 }
115 } else {
116 false
117 }
118 }
119
120 static def isMultiMatch(IPatternMatch match) {
121 checkMatch(match)
122 val n = match.specification.parameters.length
123 for (var int i = 2; i < n; i++) {
124 if (isMulti(match.get(i))) {
125 return true
126 }
127 }
128 false
129 }
130
131 private static def checkMatch(IPatternMatch match) {
132 val n = match.specification.parameters.length
133 if (n < 2 || !(match.get(0) instanceof LogicProblem) || !(match.get(1) instanceof PartialInterpretation)) {
134 throw new IllegalArgumentException("Match is not from the partial interpretation")
135 }
136 }
137}
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/CostObjectiveHint.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/CostObjectiveHint.xtend
new file mode 100644
index 00000000..2434073d
--- /dev/null
+++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/CostObjectiveHint.xtend
@@ -0,0 +1,68 @@
1package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization
2
3import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.BoundSaturationListener
4import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.ExtendedLinearExpressionBuilder
5import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.LinearTypeConstraintHint
6import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.LinearTypeExpressionBuilderFactory
7import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.PolyhedronExtensionOperator
8import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.PatternGenerator
9import java.util.Map
10import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery
11import org.eclipse.xtend.lib.annotations.Accessors
12
13abstract class CostObjectiveHint implements LinearTypeConstraintHint, BoundSaturationListener {
14 @Accessors ThreeValuedCostObjective objective
15 @Accessors IObjectiveBoundsProvider boundsProvider
16
17 Integer bestUpper = null
18
19 override getAdditionalPatterns(PatternGenerator patternGenerator, Map<String, PQuery> fqnToPQuery) {
20 ''''''
21 }
22
23 override createConstraintUpdater(LinearTypeExpressionBuilderFactory builderFactory) {
24 null
25 }
26
27 def isExact() {
28 false
29 }
30
31 def PolyhedronExtensionOperator createPolyhedronExtensionOperator(
32 Map<String, CostElementMatchers> costElementMatchers) {
33 null
34 }
35
36 def setObjective(ThreeValuedCostObjective objective) {
37 if (this.objective !== null) {
38 throw new IllegalStateException("Objective was already set")
39 }
40 this.objective = objective
41 }
42
43 def setBoundsProvider(IObjectiveBoundsProvider boundsProvider) {
44 if (this.boundsProvider !== null) {
45 throw new IllegalStateException("Objective bounds provider was already set")
46 }
47 this.boundsProvider = boundsProvider
48 }
49
50 protected def buildWithBounds(ExtendedLinearExpressionBuilder builder) {
51 val bounds = builder.build(this)
52 if (objective !== null && boundsProvider !== null) {
53 boundsProvider.computeRequiredBounds(objective, bounds)
54 }
55 if (exact && bestUpper !== null) {
56 bounds.tightenLowerBound(bestUpper)
57 }
58 bounds
59 }
60
61 override boundsSaturated(Integer lower, Integer upper) {
62 if (upper !== null && (bestUpper === null || bestUpper < upper)) {
63 bestUpper = upper
64 }
65 objective?.boundsSaturated(lower, upper)
66 }
67
68}
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/IObjectiveBoundsProvider.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/IObjectiveBoundsProvider.xtend
new file mode 100644
index 00000000..3c4d36a5
--- /dev/null
+++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/IObjectiveBoundsProvider.xtend
@@ -0,0 +1,8 @@
1package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization
2
3import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.Bounds
4import org.eclipse.viatra.dse.objectives.IObjective
5
6interface IObjectiveBoundsProvider {
7 def void computeRequiredBounds(IObjective objective, Bounds bounds)
8}
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/ThreeValuedCostObjective.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/ThreeValuedCostObjective.xtend
index 0a6fd55b..9b1a7e9f 100644
--- a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/ThreeValuedCostObjective.xtend
+++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/ThreeValuedCostObjective.xtend
@@ -1,85 +1,80 @@
1package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization 1package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization
2 2
3import com.google.common.collect.ImmutableList 3import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.BoundSaturationListener
4import java.util.Collection 4import java.util.Map
5import org.eclipse.viatra.dse.base.ThreadContext 5import org.eclipse.viatra.dse.base.ThreadContext
6import org.eclipse.viatra.query.runtime.api.IPatternMatch 6import org.eclipse.xtend.lib.annotations.Accessors
7import org.eclipse.viatra.query.runtime.api.IQuerySpecification
8import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher
9import org.eclipse.xtend.lib.annotations.Data
10 7
11@Data 8class ThreeValuedCostObjective extends AbstractThreeValuedObjective implements BoundSaturationListener {
12class ThreeValuedCostElement { 9 @Accessors val Map<String, CostElementMatchers> matchers
13 val IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> currentMatchQuery 10 double lowerBoundHint = Double.NEGATIVE_INFINITY
14 val IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> mayMatchQuery 11 double upperBoundHint = Double.POSITIVE_INFINITY
15 val IQuerySpecification<? extends ViatraQueryMatcher<? extends IPatternMatch>> mustMatchQuery
16 val int weight
17}
18
19class ThreeValuedCostObjective extends AbstractThreeValuedObjective {
20 val Collection<ThreeValuedCostElement> costElements
21 Collection<CostElementMatchers> matchers
22 12
23 new(String name, Collection<ThreeValuedCostElement> costElements, ObjectiveKind kind, ObjectiveThreshold threshold, 13 new(String name, Map<String, CostElementMatchers> matchers, ObjectiveKind kind, ObjectiveThreshold threshold,
24 int level) { 14 int level) {
25 super(name, kind, threshold, level) 15 super(name, kind, threshold, level)
26 this.costElements = costElements 16 this.matchers = matchers
27 } 17 }
28 18
29 override createNew() { 19 override createNew() {
30 new ThreeValuedCostObjective(name, costElements, kind, threshold, level) 20 // new ThreeValuedCostObjective(name, matchers, kind, threshold, level)
21 throw new UnsupportedOperationException("ThreeValuedCostObjective can only be used from a single thread")
31 } 22 }
32 23
33 override init(ThreadContext context) { 24 override init(ThreadContext context) {
34 val queryEngine = context.queryEngine
35 matchers = ImmutableList.copyOf(costElements.map [ element |
36 new CostElementMatchers(
37 queryEngine.getMatcher(element.currentMatchQuery),
38 queryEngine.getMatcher(element.mayMatchQuery),
39 queryEngine.getMatcher(element.mustMatchQuery),
40 element.weight
41 )
42 ])
43 } 25 }
44 26
45 override getRawFitness(ThreadContext context) { 27 override getRawFitness(ThreadContext context) {
46 var int cost = 0 28 var double cost = 0
47 for (matcher : matchers) { 29 for (matcher : matchers.values) {
48 cost += matcher.weight * matcher.currentMatcher.countMatches 30 cost += matcher.weight * matcher.currentNumberOfMatches
49 } 31 }
50 cost as double 32 cost
51 } 33 }
52 34
53 override getLowestPossibleFitness(ThreadContext threadContext) { 35 override getLowestPossibleFitness(ThreadContext threadContext) {
54 var int cost = 0 36 var double cost = 0
55 for (matcher : matchers) { 37 for (matcher : matchers.values) {
56 if (matcher.weight >= 0) { 38 if (matcher.weight >= 0) {
57 cost += matcher.weight * matcher.mustMatcher.countMatches 39 cost += matcher.weight * matcher.minimumNumberOfMatches
58 } else if (matcher.mayMatcher.countMatches > 0) { 40 } else {
59 // TODO Count may matches. 41 cost += matcher.weight * matcher.maximumNumberOfMatches
60 return Double.NEGATIVE_INFINITY
61 } 42 }
62 } 43 }
63 cost as double 44 val boundWithHint = Math.max(lowerBoundHint, cost)
45 if (boundWithHint > upperBoundHint) {
46 throw new IllegalStateException("Inconsistent cost bounds")
47 }
48 boundWithHint
64 } 49 }
65 50
66 override getHighestPossibleFitness(ThreadContext threadContext) { 51 override getHighestPossibleFitness(ThreadContext threadContext) {
67 var int cost = 0 52 var double cost = 0
68 for (matcher : matchers) { 53 for (matcher : matchers.values) {
69 if (matcher.weight <= 0) { 54 if (matcher.weight <= 0) {
70 cost += matcher.weight * matcher.mustMatcher.countMatches 55 cost += matcher.weight * matcher.minimumNumberOfMatches
71 } else if (matcher.mayMatcher.countMatches > 0) { 56 } else {
72 return Double.POSITIVE_INFINITY 57 cost += matcher.weight * matcher.maximumNumberOfMatches
73 } 58 }
74 } 59 }
75 cost as double 60 val boundWithHint = Math.min(upperBoundHint, cost)
61 if (boundWithHint < lowerBoundHint) {
62 throw new IllegalStateException("Inconsistent cost bounds")
63 }
64 boundWithHint
76 } 65 }
77 66
78 @Data 67 override boundsSaturated(Integer lower, Integer upper) {
79 private static class CostElementMatchers { 68 lowerBoundHint = if (lower === null) {
80 val ViatraQueryMatcher<? extends IPatternMatch> currentMatcher 69 Double.NEGATIVE_INFINITY
81 val ViatraQueryMatcher<? extends IPatternMatch> mayMatcher 70 } else {
82 val ViatraQueryMatcher<? extends IPatternMatch> mustMatcher 71 lower
83 val int weight 72 }
73 upperBoundHint = if (upper === null) {
74 Double.POSITIVE_INFINITY
75 } else {
76 upper
77 }
78 println('''Bounds saturated: «lower»..«upper»''')
84 } 79 }
85} 80}
diff --git a/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/ThreeValuedCostObjectiveProvider.xtend b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/ThreeValuedCostObjectiveProvider.xtend
new file mode 100644
index 00000000..c2750acd
--- /dev/null
+++ b/Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization/ThreeValuedCostObjectiveProvider.xtend
@@ -0,0 +1,205 @@
1package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization
2
3import com.google.common.collect.ImmutableList
4import com.google.common.collect.ImmutableMap
5import com.google.common.collect.Lists
6import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.BoolTypeReference
7import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.ComplexTypeReference
8import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.IntTypeReference
9import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RealTypeReference
10import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Relation
11import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.StringTypeReference
12import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.TypeDeclaration
13import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.TypeReference
14import hu.bme.mit.inf.dslreasoner.viatra2logic.viatra2logicannotations.TransfomedViatraQuery
15import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.PolyhedronExtensionOperator
16import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.ModalPatternQueries
17import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialBooleanInterpretation
18import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialComplexTypeInterpretation
19import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialIntegerInterpretation
20import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation
21import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialRealInterpretation
22import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialStringInterpretation
23import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.Scope
24import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.CostObjectiveConfiguration
25import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.CostObjectiveElementConfiguration
26import java.util.Collection
27import java.util.Map
28import org.eclipse.viatra.dse.objectives.IObjective
29import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine
30import org.eclipse.xtend.lib.annotations.Data
31
32@Data
33class ThreeValuedCostObjectiveProviderResult {
34 val Collection<IObjective> objectives
35 val Collection<CostObjectiveHint> hints
36 val Collection<PolyhedronExtensionOperator> extensionOperators
37 val IObjective[][] leveledExtremalObjectives
38 val boolean optimizationProblem
39}
40
41class ThreeValuedCostObjectiveProvider {
42 static val COST_OBJECTIVE_LEVEL = 3
43
44 val ViatraQueryEngine queryEngine
45 val Map<String, ModalPatternQueries> modalRelationQueries
46 val Map<String, Relation> qualifiedNameToRelationMap
47 val ParameterScopeBound defaultBounds
48 val ParameterScopeBound booleanBounds
49 val ParameterScopeBound integerBounds
50 val ParameterScopeBound realBounds
51 val ParameterScopeBound stringBounds
52 val Map<TypeDeclaration, ParameterScopeBound> typeDeclarationToBoundsMap
53
54 new(ViatraQueryEngine queryEngine, PartialInterpretation interpretation,
55 Map<String, ModalPatternQueries> modalRelationQueries) {
56 this.queryEngine = queryEngine
57 this.modalRelationQueries = modalRelationQueries
58 qualifiedNameToRelationMap = ImmutableMap.copyOf(
59 interpretation.problem.annotations.filter(TransfomedViatraQuery).
60 toMap([patternFullyQualifiedName], [target]))
61 defaultBounds = new PartialInterpretationBasedParameterScopeBound(interpretation)
62 var ParameterScopeBound booleanBounds = null
63 var ParameterScopeBound integerBounds = null
64 var ParameterScopeBound realBounds = null
65 var ParameterScopeBound stringBounds = null
66 val typeDeclarationToBoundsMapBuilder = ImmutableMap.builder
67 for (scope : interpretation.scopes) {
68 val bounds = new ScopeBasedParameterScopeBound(scope)
69 switch (typeInterpretation : scope.targetTypeInterpretation) {
70 PartialBooleanInterpretation:
71 if (booleanBounds === null) {
72 booleanBounds = bounds
73 } else {
74 throw new IllegalStateException("Duplicate partial boolean interpretation")
75 }
76 PartialIntegerInterpretation:
77 if (integerBounds === null) {
78 integerBounds = bounds
79 } else {
80 throw new IllegalStateException("Duplicate partial integer interpretation")
81 }
82 PartialRealInterpretation:
83 if (realBounds === null) {
84 realBounds = bounds
85 } else {
86 throw new IllegalStateException("Duplicate partial real interpretation")
87 }
88 PartialStringInterpretation:
89 if (stringBounds === null) {
90 stringBounds = bounds
91 } else {
92 throw new IllegalStateException("Duplicate partial string interpretation")
93 }
94 PartialComplexTypeInterpretation:
95 typeDeclarationToBoundsMapBuilder.put(typeInterpretation.interpretationOf, bounds)
96 }
97 }
98 this.booleanBounds = booleanBounds ?: defaultBounds
99 this.integerBounds = integerBounds ?: defaultBounds
100 this.realBounds = realBounds ?: defaultBounds
101 this.stringBounds = stringBounds ?: defaultBounds
102 typeDeclarationToBoundsMap = typeDeclarationToBoundsMapBuilder.build
103 }
104
105 def getCostObjectives(Collection<CostObjectiveConfiguration> costObjectives) {
106 val objectives = ImmutableList.<IObjective>builder
107 val hints = ImmutableList.<CostObjectiveHint>builder
108 val extensionOperators = ImmutableList.<PolyhedronExtensionOperator>builder
109 val extremalObjectives = Lists.newArrayListWithExpectedSize(costObjectives.size)
110 for (entry : costObjectives.indexed) {
111 val objectiveName = '''costObjective«entry.key»'''
112 val objectiveConfig = entry.value
113 val costObjective = transformCostObjective(objectiveConfig, objectiveName)
114 objectives.add(costObjective)
115 if (objectiveConfig.findExtremum) {
116 extremalObjectives += costObjective
117 }
118 val hint = objectiveConfig.hint
119 if (hint !== null) {
120 hints.add(hint)
121 hint.objective = costObjective
122 val extensionOperator = hint.createPolyhedronExtensionOperator(costObjective.matchers)
123 if (extensionOperator !== null) {
124 extensionOperators.add(extensionOperator)
125 }
126 }
127 }
128 new ThreeValuedCostObjectiveProviderResult(
129 objectives.build,
130 hints.build,
131 extensionOperators.build,
132 newArrayList(extremalObjectives),
133 !extremalObjectives.empty
134 )
135 }
136
137 private def transformCostObjective(CostObjectiveConfiguration configuration, String name) {
138 val costElements = ImmutableMap.copyOf(configuration.elements.toMap([patternQualifiedName], [
139 transformCostElement
140 ]))
141 new ThreeValuedCostObjective(name, costElements, configuration.kind, configuration.threshold,
142 COST_OBJECTIVE_LEVEL)
143 }
144
145 private def transformCostElement(CostObjectiveElementConfiguration elementConfig) {
146 val relationName = elementConfig.patternQualifiedName
147 val modalQueries = modalRelationQueries.get(relationName)
148 if (modalQueries === null) {
149 throw new IllegalArgumentException("Unknown relation queries: " + relationName)
150 }
151 val relation = qualifiedNameToRelationMap.get(relationName)
152 if (relation === null) {
153 throw new IllegalArgumentException("Unknown transformed relation: " + relationName)
154 }
155 val parameterBounds = ImmutableList.copyOf(relation.parameters.map[parameterBound])
156 new CostElementMatchers(
157 queryEngine.getMatcher(modalQueries.currentQuery),
158 queryEngine.getMatcher(modalQueries.mayQuery),
159 queryEngine.getMatcher(modalQueries.mustQuery),
160 parameterBounds,
161 elementConfig.weight
162 )
163 }
164
165 private def getParameterBound(TypeReference typeReference) {
166 switch (typeReference) {
167 BoolTypeReference: booleanBounds
168 IntTypeReference: integerBounds
169 RealTypeReference: realBounds
170 StringTypeReference: stringBounds
171 ComplexTypeReference: typeDeclarationToBoundsMap.getOrDefault(typeReference.referred, defaultBounds)
172 }
173 }
174
175 private static abstract class AbstractParameterScopeBound implements ParameterScopeBound {
176 override getUpperBound() {
177 val rawValue = rawUpperBound
178 if (rawValue < 0) {
179 Double.POSITIVE_INFINITY
180 } else {
181 rawValue
182 }
183 }
184
185 protected def int getRawUpperBound()
186 }
187
188 @Data
189 private static class ScopeBasedParameterScopeBound extends AbstractParameterScopeBound {
190 val Scope scope
191
192 override protected getRawUpperBound() {
193 scope.maxNewElements
194 }
195 }
196
197 @Data
198 private static class PartialInterpretationBasedParameterScopeBound extends AbstractParameterScopeBound {
199 val PartialInterpretation interpretation
200
201 override protected getRawUpperBound() {
202 interpretation.maxNewElements
203 }
204 }
205}