diff options
Diffstat (limited to 'Solvers/VIATRA-Solver/hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner/src/hu/bme/mit/inf/dslreasoner/viatrasolver/reasoner/optimization')
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 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization | ||
2 | |||
3 | import com.google.common.collect.ImmutableList | ||
4 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicproblemPackage | ||
5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialinterpretationPackage | ||
6 | import java.util.List | ||
7 | import org.eclipse.emf.ecore.EObject | ||
8 | import org.eclipse.viatra.query.runtime.api.IPatternMatch | ||
9 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher | ||
10 | import org.eclipse.xtend.lib.annotations.Data | ||
11 | import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem | ||
12 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
13 | |||
14 | @FunctionalInterface | ||
15 | interface ParameterScopeBound { | ||
16 | def double getUpperBound() | ||
17 | } | ||
18 | |||
19 | @Data | ||
20 | class CostElementMatch { | ||
21 | val IPatternMatch match | ||
22 | val boolean must | ||
23 | |||
24 | def isMulti() { | ||
25 | CostElementMatchers.isMultiMatch(match) | ||
26 | } | ||
27 | } | ||
28 | |||
29 | @Data | ||
30 | class 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 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization | ||
2 | |||
3 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.BoundSaturationListener | ||
4 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.ExtendedLinearExpressionBuilder | ||
5 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.LinearTypeConstraintHint | ||
6 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.LinearTypeExpressionBuilderFactory | ||
7 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.PolyhedronExtensionOperator | ||
8 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.PatternGenerator | ||
9 | import java.util.Map | ||
10 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery | ||
11 | import org.eclipse.xtend.lib.annotations.Accessors | ||
12 | |||
13 | abstract 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 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization | ||
2 | |||
3 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.Bounds | ||
4 | import org.eclipse.viatra.dse.objectives.IObjective | ||
5 | |||
6 | interface 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 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization | 1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization |
2 | 2 | ||
3 | import com.google.common.collect.ImmutableList | 3 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.BoundSaturationListener |
4 | import java.util.Collection | 4 | import java.util.Map |
5 | import org.eclipse.viatra.dse.base.ThreadContext | 5 | import org.eclipse.viatra.dse.base.ThreadContext |
6 | import org.eclipse.viatra.query.runtime.api.IPatternMatch | 6 | import org.eclipse.xtend.lib.annotations.Accessors |
7 | import org.eclipse.viatra.query.runtime.api.IQuerySpecification | ||
8 | import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher | ||
9 | import org.eclipse.xtend.lib.annotations.Data | ||
10 | 7 | ||
11 | @Data | 8 | class ThreeValuedCostObjective extends AbstractThreeValuedObjective implements BoundSaturationListener { |
12 | class 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 | |||
19 | class 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 @@ | |||
1 | package hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization | ||
2 | |||
3 | import com.google.common.collect.ImmutableList | ||
4 | import com.google.common.collect.ImmutableMap | ||
5 | import com.google.common.collect.Lists | ||
6 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.BoolTypeReference | ||
7 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.ComplexTypeReference | ||
8 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.IntTypeReference | ||
9 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RealTypeReference | ||
10 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Relation | ||
11 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.StringTypeReference | ||
12 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.TypeDeclaration | ||
13 | import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.TypeReference | ||
14 | import hu.bme.mit.inf.dslreasoner.viatra2logic.viatra2logicannotations.TransfomedViatraQuery | ||
15 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.PolyhedronExtensionOperator | ||
16 | import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.patterns.ModalPatternQueries | ||
17 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialBooleanInterpretation | ||
18 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialComplexTypeInterpretation | ||
19 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialIntegerInterpretation | ||
20 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialInterpretation | ||
21 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialRealInterpretation | ||
22 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.PartialStringInterpretation | ||
23 | import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partialinterpretation.Scope | ||
24 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.CostObjectiveConfiguration | ||
25 | import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.CostObjectiveElementConfiguration | ||
26 | import java.util.Collection | ||
27 | import java.util.Map | ||
28 | import org.eclipse.viatra.dse.objectives.IObjective | ||
29 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine | ||
30 | import org.eclipse.xtend.lib.annotations.Data | ||
31 | |||
32 | @Data | ||
33 | class 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 | |||
41 | class 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 | } | ||