Skip to content

Commit 8dfa1a1

Browse files
authored
chore: improve the new list variable logic (#1248)
For some reason, this commit was not merged together with ee760ca and I only discovered it now.
1 parent 05539ad commit 8dfa1a1

File tree

6 files changed

+75
-108
lines changed

6 files changed

+75
-108
lines changed

core/src/main/java/ai/timefold/solver/core/impl/domain/variable/AbstractExternalizedNextPrevElementVariableProcessor.java

Lines changed: 0 additions & 36 deletions
This file was deleted.

core/src/main/java/ai/timefold/solver/core/impl/domain/variable/ExternalizedListVariableStateSupply.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,23 @@ public ExternalizedListVariableStateSupply(ListVariableDescriptor<Solution_> sou
2727

2828
@Override
2929
public void externalize(IndexShadowVariableDescriptor<Solution_> shadowVariableDescriptor) {
30-
listVariableState.linkDescriptor(shadowVariableDescriptor);
30+
listVariableState.linkShadowVariable(shadowVariableDescriptor);
3131
}
3232

3333
@Override
3434
public void externalize(InverseRelationShadowVariableDescriptor<Solution_> shadowVariableDescriptor) {
35-
listVariableState.linkDescriptor(shadowVariableDescriptor);
35+
listVariableState.linkShadowVariable(shadowVariableDescriptor);
3636
}
3737

3838
@Override
3939
public void externalize(PreviousElementShadowVariableDescriptor<Solution_> shadowVariableDescriptor) {
40-
listVariableState.linkDescriptor(shadowVariableDescriptor);
40+
listVariableState.linkShadowVariable(shadowVariableDescriptor);
4141
previousExternalized = true;
4242
}
4343

4444
@Override
4545
public void externalize(NextElementShadowVariableDescriptor<Solution_> shadowVariableDescriptor) {
46-
listVariableState.linkDescriptor(shadowVariableDescriptor);
46+
listVariableState.linkShadowVariable(shadowVariableDescriptor);
4747
nextExternalized = true;
4848
}
4949

core/src/main/java/ai/timefold/solver/core/impl/domain/variable/ExternalizedNextElementVariableProcessor.java

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package ai.timefold.solver.core.impl.domain.variable;
2+
3+
import java.util.List;
4+
import java.util.Objects;
5+
6+
import ai.timefold.solver.core.impl.domain.variable.descriptor.ShadowVariableDescriptor;
7+
import ai.timefold.solver.core.impl.domain.variable.nextprev.NextElementShadowVariableDescriptor;
8+
import ai.timefold.solver.core.impl.domain.variable.nextprev.PreviousElementShadowVariableDescriptor;
9+
import ai.timefold.solver.core.impl.score.director.InnerScoreDirector;
10+
11+
final class ExternalizedNextPrevElementVariableProcessor<Solution_> {
12+
13+
public static <Solution_> ExternalizedNextPrevElementVariableProcessor<Solution_>
14+
ofPrevious(PreviousElementShadowVariableDescriptor<Solution_> shadowVariableDescriptor) {
15+
return new ExternalizedNextPrevElementVariableProcessor<>(shadowVariableDescriptor, -1);
16+
}
17+
18+
public static <Solution_> ExternalizedNextPrevElementVariableProcessor<Solution_>
19+
ofNext(NextElementShadowVariableDescriptor<Solution_> shadowVariableDescriptor) {
20+
return new ExternalizedNextPrevElementVariableProcessor<>(shadowVariableDescriptor, 1);
21+
}
22+
23+
private final ShadowVariableDescriptor<Solution_> shadowVariableDescriptor;
24+
private final int modifier;
25+
26+
private ExternalizedNextPrevElementVariableProcessor(ShadowVariableDescriptor<Solution_> shadowVariableDescriptor,
27+
int modifier) {
28+
this.shadowVariableDescriptor = Objects.requireNonNull(shadowVariableDescriptor);
29+
this.modifier = modifier;
30+
}
31+
32+
public void setElement(InnerScoreDirector<Solution_, ?> scoreDirector, List<Object> listVariable, Object element,
33+
int index) {
34+
var target = index + modifier;
35+
if (target < 0 || target >= listVariable.size()) {
36+
setValue(scoreDirector, element, null);
37+
} else {
38+
setValue(scoreDirector, element, listVariable.get(target));
39+
}
40+
}
41+
42+
private void setValue(InnerScoreDirector<Solution_, ?> scoreDirector, Object element, Object value) {
43+
if (getElement(element) != value) {
44+
scoreDirector.beforeVariableChanged(shadowVariableDescriptor, element);
45+
shadowVariableDescriptor.setValue(element, value);
46+
scoreDirector.afterVariableChanged(shadowVariableDescriptor, element);
47+
}
48+
}
49+
50+
public Object getElement(Object element) {
51+
return shadowVariableDescriptor.getValue(element);
52+
}
53+
54+
public void unsetElement(InnerScoreDirector<Solution_, ?> scoreDirector, Object element) {
55+
setValue(scoreDirector, element, null);
56+
}
57+
58+
}

core/src/main/java/ai/timefold/solver/core/impl/domain/variable/ExternalizedPreviousElementVariableProcessor.java

Lines changed: 0 additions & 27 deletions
This file was deleted.

core/src/main/java/ai/timefold/solver/core/impl/domain/variable/ListVariableState.java

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@ final class ListVariableState<Solution_> {
2020

2121
private ExternalizedIndexVariableProcessor<Solution_> externalizedIndexProcessor = null;
2222
private ExternalizedListInverseVariableProcessor<Solution_> externalizedInverseProcessor = null;
23-
private AbstractExternalizedNextPrevElementVariableProcessor<Solution_> externalizedPreviousElementProcessor = null;
24-
private AbstractExternalizedNextPrevElementVariableProcessor<Solution_> externalizedNextElementProcessor = null;
23+
private ExternalizedNextPrevElementVariableProcessor<Solution_> externalizedPreviousElementProcessor = null;
24+
private ExternalizedNextPrevElementVariableProcessor<Solution_> externalizedNextElementProcessor = null;
2525

26-
private boolean canUseExternalizedLocation = false;
2726
private boolean requiresLocationMap = true;
2827
private InnerScoreDirector<Solution_, ?> scoreDirector;
2928
private int unassignedCount = 0;
@@ -33,30 +32,29 @@ public ListVariableState(ListVariableDescriptor<Solution_> sourceVariableDescrip
3332
this.sourceVariableDescriptor = sourceVariableDescriptor;
3433
}
3534

36-
public void linkDescriptor(IndexShadowVariableDescriptor<Solution_> shadowVariableDescriptor) {
35+
public void linkShadowVariable(IndexShadowVariableDescriptor<Solution_> shadowVariableDescriptor) {
3736
this.externalizedIndexProcessor = new ExternalizedIndexVariableProcessor<>(shadowVariableDescriptor);
3837
}
3938

40-
public void linkDescriptor(InverseRelationShadowVariableDescriptor<Solution_> shadowVariableDescriptor) {
39+
public void linkShadowVariable(InverseRelationShadowVariableDescriptor<Solution_> shadowVariableDescriptor) {
4140
this.externalizedInverseProcessor =
4241
new ExternalizedListInverseVariableProcessor<>(shadowVariableDescriptor, sourceVariableDescriptor);
4342
}
4443

45-
public void linkDescriptor(PreviousElementShadowVariableDescriptor<Solution_> shadowVariableDescriptor) {
44+
public void linkShadowVariable(PreviousElementShadowVariableDescriptor<Solution_> shadowVariableDescriptor) {
4645
this.externalizedPreviousElementProcessor =
47-
new ExternalizedPreviousElementVariableProcessor<>(shadowVariableDescriptor);
46+
ExternalizedNextPrevElementVariableProcessor.ofPrevious(shadowVariableDescriptor);
4847
}
4948

50-
public void linkDescriptor(NextElementShadowVariableDescriptor<Solution_> shadowVariableDescriptor) {
51-
this.externalizedNextElementProcessor = new ExternalizedNextElementVariableProcessor<>(shadowVariableDescriptor);
49+
public void linkShadowVariable(NextElementShadowVariableDescriptor<Solution_> shadowVariableDescriptor) {
50+
this.externalizedNextElementProcessor = ExternalizedNextPrevElementVariableProcessor.ofNext(shadowVariableDescriptor);
5251
}
5352

5453
public void initialize(InnerScoreDirector<Solution_, ?> scoreDirector, int initialUnassignedCount) {
5554
this.scoreDirector = scoreDirector;
5655
this.unassignedCount = initialUnassignedCount;
5756

58-
this.canUseExternalizedLocation = externalizedIndexProcessor != null && externalizedInverseProcessor != null;
59-
this.requiresLocationMap = !canUseExternalizedLocation
57+
this.requiresLocationMap = externalizedIndexProcessor == null || externalizedInverseProcessor == null
6058
|| externalizedPreviousElementProcessor == null || externalizedNextElementProcessor == null;
6159
if (requiresLocationMap) {
6260
if (elementLocationMap == null) {
@@ -220,14 +218,14 @@ private enum ChangeType {
220218
}
221219

222220
public ElementLocation getLocationInList(Object planningValue) {
223-
if (!canUseExternalizedLocation) {
221+
if (requiresLocationMap) {
224222
return Objects.requireNonNullElse(elementLocationMap.get(planningValue), ElementLocation.unassigned());
225-
} else {
226-
var inverse = getInverseSingleton(planningValue);
223+
} else { // At this point, both inverse and index are externalized.
224+
var inverse = externalizedInverseProcessor.getInverseSingleton(planningValue);
227225
if (inverse == null) {
228226
return ElementLocation.unassigned();
229227
}
230-
return ElementLocation.of(inverse, getIndex(planningValue));
228+
return ElementLocation.of(inverse, externalizedIndexProcessor.getIndex(planningValue));
231229
}
232230
}
233231

0 commit comments

Comments
 (0)