/
ScoreDirector.java
167 lines (135 loc) · 6.57 KB
/
ScoreDirector.java
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
161
162
163
164
165
166
167
/*
* Copyright 2011 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.optaplanner.core.impl.score.director;
import java.util.Collection;
import java.util.Map;
import org.optaplanner.core.api.domain.lookup.LookUpStrategyType;
import org.optaplanner.core.api.domain.lookup.PlanningId;
import org.optaplanner.core.api.domain.solution.PlanningSolution;
import org.optaplanner.core.api.score.Score;
import org.optaplanner.core.api.score.constraint.ConstraintMatch;
import org.optaplanner.core.api.score.constraint.ConstraintMatchTotal;
import org.optaplanner.core.api.score.constraint.Indictment;
import org.optaplanner.core.api.solver.Solver;
import org.optaplanner.core.impl.domain.variable.descriptor.VariableDescriptor;
import org.optaplanner.core.impl.heuristic.move.Move;
import org.optaplanner.core.impl.solver.ProblemFactChange;
/**
* The ScoreDirector holds the {@link PlanningSolution working solution}
* and calculates the {@link Score} for it.
* @param <Solution_> the solution type, the class with the {@link PlanningSolution} annotation
*/
public interface ScoreDirector<Solution_> extends AutoCloseable {
/**
* The {@link PlanningSolution} that is used to calculate the {@link Score}.
* <p>
* Because a {@link Score} is best calculated incrementally (by deltas),
* the {@link ScoreDirector} needs to be notified when its {@link PlanningSolution working solution} changes.
* <p>
* If the {@link PlanningSolution working solution} has been changed since {@link #calculateScore} was called,
* its {@link Score} won't be correct.
* @return never null
*/
Solution_ getWorkingSolution();
/**
* The {@link PlanningSolution working solution} must never be the same instance as the
* {@link PlanningSolution best solution}, it should be a (un)changed clone.
* <p>
* Only call this method on a separate {@link ScoreDirector} instance,
* built by {@link Solver#getScoreDirectorFactory()},
* not on the one used inside the {@link Solver} itself.
* @param workingSolution never null
*/
void setWorkingSolution(Solution_ workingSolution);
/**
* Calculates the {@link Score} and updates the {@link PlanningSolution working solution} accordingly.
* @return never null, the {@link Score} of the {@link PlanningSolution working solution}
*/
Score calculateScore();
/**
* @return true if {@link #getConstraintMatchTotals()} can be called
*/
boolean isConstraintMatchEnabled();
/**
* Explains the {@link Score} of {@link #calculateScore()} by splitting it up per constraint type
* (which is usually a score rule).
* <p>
* The sum of {@link ConstraintMatchTotal#getScoreTotal()} equals {@link #calculateScore()}.
* @return never null
* @throws IllegalStateException if {@link #isConstraintMatchEnabled()} returns false
*/
Collection<ConstraintMatchTotal> getConstraintMatchTotals();
/**
* Explains the impact of each planning entity or problem fact on the {@link Score}.
* An indictment is basically the inverse of {@link #getConstraintMatchTotals()}:
* it is a {@link Score} total for each justification {@link Object}
* in {@link ConstraintMatch#getJustificationList()}.
* <p>
* Warning: In practice, it often doesn't include the full impact on the {@link Score},
* for example in DRL score rules with accumulate, the accumulate elements won't be indicted.
* <p>
* The sum of {@link ConstraintMatchTotal#getScoreTotal()} differs from {@link #calculateScore()}
* because each {@link ConstraintMatch#getScore()} is counted
* for each justification in {@link ConstraintMatch#getJustificationList()}.
* @return never null
* @throws IllegalStateException if {@link #isConstraintMatchEnabled()} returns false
*/
Map<Object, Indictment> getIndictmentMap();
void beforeEntityAdded(Object entity);
void afterEntityAdded(Object entity);
void beforeVariableChanged(Object entity, String variableName);
void afterVariableChanged(Object entity, String variableName);
// TODO VariableDescriptor is not likely to go to public API
void beforeVariableChanged(VariableDescriptor variableDescriptor, Object entity);
void afterVariableChanged(VariableDescriptor variableDescriptor, Object entity);
void changeVariableFacade(VariableDescriptor variableDescriptor, Object entity, Object newValue);
void triggerVariableListeners();
void beforeEntityRemoved(Object entity);
void afterEntityRemoved(Object entity);
// TODO extract this set of methods into a separate interface, only used by ProblemFactChange
void beforeProblemFactAdded(Object problemFact);
void afterProblemFactAdded(Object problemFact);
void beforeProblemPropertyChanged(Object problemFactOrEntity);
void afterProblemPropertyChanged(Object problemFactOrEntity);
void beforeProblemFactRemoved(Object problemFact);
void afterProblemFactRemoved(Object problemFact);
/**
* Translates an entity or fact instance (often from another {@link Thread} or JVM)
* to this {@link ScoreDirector}'s internal working instance.
* Useful for {@link Move#rebase(ScoreDirector)} and in a {@link ProblemFactChange}.
* <p>
* Matching is determined by the {@link LookUpStrategyType} on {@link PlanningSolution}.
* Matching uses a {@link PlanningId} by default.
* @param externalObject sometimes null
* @return null if externalObject is null or if there is no workingObject for externalObject
* @throws IllegalArgumentException if it cannot be looked up or if the externalObject's class is not supported
* @throws IllegalStateException if it cannot be looked up
* @param <E> the object type
*/
<E> E lookUpWorkingObject(E externalObject);
/**
* Needs to be called after use because some implementations need to clean up their resources.
*/
@Override
void close();
/**
* @deprecated in favor of {@link #close()}
*/
@Deprecated
default void dispose() {
close();
}
}