Skip to content

Commit 8d4595e

Browse files
authored
chore: expose Move Streams as a experimental feature (#1493)
This feature is under heavy development. Any use is discouraged.
1 parent 989a393 commit 8d4595e

File tree

24 files changed

+347
-61
lines changed

24 files changed

+347
-61
lines changed

benchmark/src/main/java/ai/timefold/solver/benchmark/config/blueprint/SolverBenchmarkBluePrintType.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import ai.timefold.solver.core.config.localsearch.LocalSearchPhaseConfig;
1212
import ai.timefold.solver.core.config.localsearch.LocalSearchType;
1313
import ai.timefold.solver.core.config.phase.PhaseConfig;
14-
import ai.timefold.solver.core.config.solver.PreviewFeature;
1514
import ai.timefold.solver.core.config.solver.SolverConfig;
1615

1716
import org.jspecify.annotations.NonNull;
@@ -72,7 +71,7 @@ private List<SolverBenchmarkConfig> buildEveryLocalSearchType(ConstructionHeuris
7271
LocalSearchType[] lsTypes = LocalSearchType.getBluePrintTypes();
7372
List<SolverBenchmarkConfig> solverBenchmarkConfigList = new ArrayList<>(lsTypes.length);
7473
for (LocalSearchType lsType : lsTypes) {
75-
if (PreviewFeature.DIVERSIFIED_LATE_ACCEPTANCE != null && lsType == LocalSearchType.DIVERSIFIED_LATE_ACCEPTANCE) {
74+
if (lsType == LocalSearchType.DIVERSIFIED_LATE_ACCEPTANCE) {
7675
// When the preview feature is removed, this will fail at compile time
7776
// and the code will have to be adjusted.
7877
// Most likely, the preview feature will be promoted to a regular feature,

benchmark/src/main/resources/benchmark.xsd

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2381,6 +2381,9 @@
23812381
</xs:choice>
23822382

23832383

2384+
<xs:element minOccurs="0" name="moveProvidersClass" type="xs:string"/>
2385+
2386+
23842387
<xs:element minOccurs="0" name="acceptor" type="tns:localSearchAcceptorConfig"/>
23852388

23862389

@@ -2604,6 +2607,9 @@
26042607

26052608

26062609
<xs:enumeration value="PLANNING_SOLUTION_DIFF"/>
2610+
2611+
2612+
<xs:enumeration value="MOVE_STREAMS"/>
26072613

26082614

26092615
</xs:restriction>

core/src/build/revapi-differences.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,17 @@
140140
"new": "class ai.timefold.solver.core.config.phase.custom.CustomPhaseConfig",
141141
"annotation": "@org.jspecify.annotations.NullMarked",
142142
"justification": "Less verbose nullability, no practical impact."
143+
},
144+
{
145+
"ignore": true,
146+
"code": "java.annotation.attributeValueChanged",
147+
"old": "class ai.timefold.solver.core.config.localsearch.LocalSearchPhaseConfig",
148+
"new": "class ai.timefold.solver.core.config.localsearch.LocalSearchPhaseConfig",
149+
"annotationType": "jakarta.xml.bind.annotation.XmlType",
150+
"attribute": "propOrder",
151+
"oldValue": "{\"localSearchType\", \"moveSelectorConfig\", \"acceptorConfig\", \"foragerConfig\"}",
152+
"newValue": "{\"localSearchType\", \"moveSelectorConfig\", \"moveProvidersClass\", \"acceptorConfig\", \"foragerConfig\"}",
153+
"justification": "Move Streams arrives as a preview feature."
143154
}
144155
]
145156
}

core/src/main/java/ai/timefold/solver/core/config/localsearch/LocalSearchPhaseConfig.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,17 @@
2727
import ai.timefold.solver.core.config.localsearch.decider.acceptor.LocalSearchAcceptorConfig;
2828
import ai.timefold.solver.core.config.localsearch.decider.forager.LocalSearchForagerConfig;
2929
import ai.timefold.solver.core.config.phase.PhaseConfig;
30+
import ai.timefold.solver.core.config.solver.PreviewFeature;
3031
import ai.timefold.solver.core.config.util.ConfigUtils;
32+
import ai.timefold.solver.core.impl.move.streams.maybeapi.stream.MoveProviders;
3133

3234
import org.jspecify.annotations.NonNull;
3335
import org.jspecify.annotations.Nullable;
3436

3537
@XmlType(propOrder = {
3638
"localSearchType",
3739
"moveSelectorConfig",
40+
"moveProvidersClass",
3841
"acceptorConfig",
3942
"foragerConfig"
4043
})
@@ -74,6 +77,7 @@ public class LocalSearchPhaseConfig extends PhaseConfig<LocalSearchPhaseConfig>
7477
@XmlElement(name = UnionMoveSelectorConfig.XML_ELEMENT_NAME, type = UnionMoveSelectorConfig.class)
7578
})
7679
private MoveSelectorConfig moveSelectorConfig = null;
80+
private Class<? extends MoveProviders> moveProvidersClass = null;
7781
@XmlElement(name = "acceptor")
7882
private LocalSearchAcceptorConfig acceptorConfig = null;
7983
@XmlElement(name = "forager")
@@ -99,6 +103,22 @@ public void setMoveSelectorConfig(@Nullable MoveSelectorConfig moveSelectorConfi
99103
this.moveSelectorConfig = moveSelectorConfig;
100104
}
101105

106+
/**
107+
* Part of {@link PreviewFeature#MOVE_STREAMS}.
108+
*/
109+
@SuppressWarnings("unchecked")
110+
public @Nullable <Solution_> Class<? extends MoveProviders<Solution_>> getMoveProvidersClass() {
111+
return (Class<? extends MoveProviders<Solution_>>) moveProvidersClass;
112+
}
113+
114+
/**
115+
* Part of {@link PreviewFeature#MOVE_STREAMS}.
116+
*/
117+
@SuppressWarnings("rawtypes")
118+
public void setMoveProvidersClass(@Nullable Class<? extends MoveProviders> moveProvidersClass) {
119+
this.moveProvidersClass = moveProvidersClass;
120+
}
121+
102122
public @Nullable LocalSearchAcceptorConfig getAcceptorConfig() {
103123
return acceptorConfig;
104124
}
@@ -129,6 +149,15 @@ public void setForagerConfig(@Nullable LocalSearchForagerConfig foragerConfig) {
129149
return this;
130150
}
131151

152+
/**
153+
* Part of {@link PreviewFeature#MOVE_STREAMS}.
154+
*/
155+
public @NonNull LocalSearchPhaseConfig
156+
withMoveProvidersClass(@NonNull Class<? extends MoveProviders<?>> moveProviderClass) {
157+
this.moveProvidersClass = moveProviderClass;
158+
return this;
159+
}
160+
132161
public @NonNull LocalSearchPhaseConfig withAcceptorConfig(@NonNull LocalSearchAcceptorConfig acceptorConfig) {
133162
this.acceptorConfig = acceptorConfig;
134163
return this;
@@ -146,6 +175,8 @@ public void setForagerConfig(@Nullable LocalSearchForagerConfig foragerConfig) {
146175
inheritedConfig.getLocalSearchType());
147176
setMoveSelectorConfig(ConfigUtils.inheritOverwritableProperty(
148177
getMoveSelectorConfig(), inheritedConfig.getMoveSelectorConfig()));
178+
setMoveProvidersClass(ConfigUtils.inheritOverwritableProperty(getMoveProvidersClass(),
179+
inheritedConfig.getMoveProvidersClass()));
149180
acceptorConfig = ConfigUtils.inheritConfig(acceptorConfig, inheritedConfig.getAcceptorConfig());
150181
foragerConfig = ConfigUtils.inheritConfig(foragerConfig, inheritedConfig.getForagerConfig());
151182
return this;
@@ -164,6 +195,9 @@ public void visitReferencedClasses(@NonNull Consumer<Class<?>> classVisitor) {
164195
if (moveSelectorConfig != null) {
165196
moveSelectorConfig.visitReferencedClasses(classVisitor);
166197
}
198+
if (moveProvidersClass != null) {
199+
classVisitor.accept(moveProvidersClass);
200+
}
167201
if (acceptorConfig != null) {
168202
acceptorConfig.visitReferencedClasses(classVisitor);
169203
}

core/src/main/java/ai/timefold/solver/core/config/localsearch/LocalSearchType.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
import jakarta.xml.bind.annotation.XmlEnum;
66

7+
import ai.timefold.solver.core.config.solver.PreviewFeature;
8+
79
import org.jspecify.annotations.NonNull;
810

911
@XmlEnum
@@ -12,6 +14,9 @@ public enum LocalSearchType {
1214
TABU_SEARCH,
1315
SIMULATED_ANNEALING,
1416
LATE_ACCEPTANCE,
17+
/**
18+
* See {@link PreviewFeature#DIVERSIFIED_LATE_ACCEPTANCE}.
19+
*/
1520
DIVERSIFIED_LATE_ACCEPTANCE,
1621
GREAT_DELUGE,
1722
VARIABLE_NEIGHBORHOOD_DESCENT;

core/src/main/java/ai/timefold/solver/core/config/localsearch/decider/acceptor/AcceptorType.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,30 @@
44

55
@XmlEnum
66
public enum AcceptorType {
7+
78
HILL_CLIMBING,
8-
ENTITY_TABU,
9-
VALUE_TABU,
10-
MOVE_TABU,
11-
UNDO_MOVE_TABU,
9+
ENTITY_TABU(true),
10+
VALUE_TABU(true),
11+
MOVE_TABU(true),
12+
UNDO_MOVE_TABU(true),
1213
SIMULATED_ANNEALING,
1314
LATE_ACCEPTANCE,
1415
DIVERSIFIED_LATE_ACCEPTANCE,
1516
GREAT_DELUGE,
16-
STEP_COUNTING_HILL_CLIMBING
17+
STEP_COUNTING_HILL_CLIMBING;
18+
19+
private final boolean isTabu;
20+
21+
AcceptorType() {
22+
this(false);
23+
}
24+
25+
AcceptorType(boolean isTabu) {
26+
this.isTabu = isTabu;
27+
}
28+
29+
public boolean isTabu() {
30+
return isTabu;
31+
}
32+
1733
}
Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,37 @@
11
package ai.timefold.solver.core.config.solver;
22

3+
/**
4+
* Lists features available in Timefold Solver on a preview basis.
5+
* These preview features are developed to the same standard as the rest of Timefold Solver.
6+
* However, their APIs are not yet considered stable, pending user feedback.
7+
* Any class, method, or field related to these features may change or be removed without prior notice,
8+
* although we will strive to avoid this as much as possible.
9+
* We encourage you to try these preview features and give us feedback on your experience with them.
10+
* Please direct your feedback to our Github Discussions.
11+
*
12+
* <p>
13+
* This list is not constant and is evolving over time,
14+
* with items being added and removed without warning.
15+
* It should not be treated as part of our public API,
16+
* just like the preview features themselves.
17+
*
18+
* @see <a href="https://github.com/TimefoldAI/timefold-solver/discussions">Timefold Solver Github Discussions</a>
19+
*/
320
public enum PreviewFeature {
421

522
DIVERSIFIED_LATE_ACCEPTANCE,
6-
PLANNING_SOLUTION_DIFF
23+
PLANNING_SOLUTION_DIFF,
24+
/**
25+
* Unlike other preview features, Move Streams are an active research project.
26+
* It is intended to simplify the creation of custom moves, eventually replacing move selectors.
27+
* The component is under heavy development, entirely undocumented, and many key features are yet to be delivered.
28+
* Neither the API nor the feature set are complete, and any part can change or be removed at any time.
29+
*
30+
* Move Streams will eventually stabilize and be promoted from a research project to a true preview feature.
31+
* We only expose it now to be able to use it for experimentation and testing.
32+
* As such, it is an exception to the rule;
33+
* this preview feature is not finished, and it is not yet ready for feedback.
34+
*/
35+
MOVE_STREAMS
736

837
}

0 commit comments

Comments
 (0)