33import java .util .HashMap ;
44import java .util .Map ;
55import java .util .Random ;
6+ import java .util .Set ;
67import java .util .concurrent .ThreadFactory ;
78
89import ai .timefold .solver .core .config .heuristic .selector .entity .EntitySorterManner ;
910import ai .timefold .solver .core .config .heuristic .selector .value .ValueSorterManner ;
1011import ai .timefold .solver .core .config .solver .EnvironmentMode ;
12+ import ai .timefold .solver .core .config .solver .PreviewFeature ;
1113import ai .timefold .solver .core .config .util .ConfigUtils ;
1214import ai .timefold .solver .core .impl .domain .solution .descriptor .SolutionDescriptor ;
1315import ai .timefold .solver .core .impl .heuristic .selector .common .nearby .NearbyDistanceMeter ;
2527
2628public class HeuristicConfigPolicy <Solution_ > {
2729
30+ private final Set <PreviewFeature > previewFeatureList ;
2831 private final EnvironmentMode environmentMode ;
2932 private final String logIndentation ;
3033 private final Integer moveThreadCount ;
@@ -46,6 +49,7 @@ public class HeuristicConfigPolicy<Solution_> {
4649 private final Map <String , ValueMimicRecorder <Solution_ >> valueMimicRecorderMap = new HashMap <>();
4750
4851 private HeuristicConfigPolicy (Builder <Solution_ > builder ) {
52+ this .previewFeatureList = builder .previewFeatureList ;
4953 this .environmentMode = builder .environmentMode ;
5054 this .logIndentation = builder .logIndentation ;
5155 this .moveThreadCount = builder .moveThreadCount ;
@@ -128,8 +132,17 @@ public Random getRandom() {
128132 // ************************************************************************
129133
130134 public Builder <Solution_ > cloneBuilder () {
131- return new Builder <>(environmentMode , moveThreadCount , moveThreadBufferSize , threadFactoryClass ,
132- nearbyDistanceMeterClass , random , initializingScoreTrend , solutionDescriptor , classInstanceCache )
135+ return new Builder <Solution_ >()
136+ .withPreviewFeatureList (previewFeatureList )
137+ .withEnvironmentMode (environmentMode )
138+ .withMoveThreadCount (moveThreadCount )
139+ .withMoveThreadBufferSize (moveThreadBufferSize )
140+ .withThreadFactoryClass (threadFactoryClass )
141+ .withNearbyDistanceMeterClass (nearbyDistanceMeterClass )
142+ .withRandom (random )
143+ .withInitializingScoreTrend (initializingScoreTrend )
144+ .withSolutionDescriptor (solutionDescriptor )
145+ .withClassInstanceCache (classInstanceCache )
133146 .withLogIndentation (logIndentation );
134147 }
135148
@@ -148,11 +161,13 @@ public HeuristicConfigPolicy<Solution_> createChildThreadConfigPolicy(ChildThrea
148161 // ************************************************************************
149162
150163 public void addEntityMimicRecorder (String id , EntityMimicRecorder <Solution_ > mimicRecordingEntitySelector ) {
151- EntityMimicRecorder < Solution_ > put = entityMimicRecorderMap .put (id , mimicRecordingEntitySelector );
164+ var put = entityMimicRecorderMap .put (id , mimicRecordingEntitySelector );
152165 if (put != null ) {
153- throw new IllegalStateException ("Multiple " + EntityMimicRecorder .class .getSimpleName () + "s (usually "
154- + EntitySelector .class .getSimpleName () + "s) have the same id (" + id + ").\n " +
155- "Maybe specify a variable name for the mimicking selector in situations with multiple variables on the same entity?" );
166+ throw new IllegalStateException (
167+ """
168+ Multiple %ss (usually %ss) have the same id (%s).
169+ Maybe specify a variable name for the mimicking selector in situations with multiple variables on the same entity?"""
170+ .formatted (EntityMimicRecorder .class .getSimpleName (), EntitySelector .class .getSimpleName (), id ));
156171 }
157172 }
158173
@@ -161,11 +176,13 @@ public EntityMimicRecorder<Solution_> getEntityMimicRecorder(String id) {
161176 }
162177
163178 public void addSubListMimicRecorder (String id , SubListMimicRecorder <Solution_ > mimicRecordingSubListSelector ) {
164- SubListMimicRecorder < Solution_ > put = subListMimicRecorderMap .put (id , mimicRecordingSubListSelector );
179+ var put = subListMimicRecorderMap .put (id , mimicRecordingSubListSelector );
165180 if (put != null ) {
166- throw new IllegalStateException ("Multiple " + SubListMimicRecorder .class .getSimpleName () + "s (usually "
167- + SubListSelector .class .getSimpleName () + "s) have the same id (" + id + ").\n " +
168- "Maybe specify a variable name for the mimicking selector in situations with multiple variables on the same entity?" );
181+ throw new IllegalStateException (
182+ """
183+ Multiple %ss (usually %ss) have the same id (%s).
184+ Maybe specify a variable name for the mimicking selector in situations with multiple variables on the same entity?"""
185+ .formatted (SubListMimicRecorder .class .getSimpleName (), SubListSelector .class .getSimpleName (), id ));
169186 }
170187 }
171188
@@ -174,11 +191,13 @@ public SubListMimicRecorder<Solution_> getSubListMimicRecorder(String id) {
174191 }
175192
176193 public void addValueMimicRecorder (String id , ValueMimicRecorder <Solution_ > mimicRecordingValueSelector ) {
177- ValueMimicRecorder < Solution_ > put = valueMimicRecorderMap .put (id , mimicRecordingValueSelector );
194+ var put = valueMimicRecorderMap .put (id , mimicRecordingValueSelector );
178195 if (put != null ) {
179- throw new IllegalStateException ("Multiple " + ValueMimicRecorder .class .getSimpleName () + "s (usually "
180- + ValueSelector .class .getSimpleName () + "s) have the same id (" + id + ").\n " +
181- "Maybe specify a variable name for the mimicking selector in situations with multiple variables on the same entity?" );
196+ throw new IllegalStateException (
197+ """
198+ Multiple %ss (usually %ss) have the same id (%s).
199+ Maybe specify a variable name for the mimicking selector in situations with multiple variables on the same entity?"""
200+ .formatted (ValueMimicRecorder .class .getSimpleName (), ValueSelector .class .getSimpleName (), id ));
182201 }
183202 }
184203
@@ -198,20 +217,31 @@ public ThreadFactory buildThreadFactory(ChildThreadType childThreadType) {
198217 }
199218 }
200219
220+ public void ensurePreviewFeature (PreviewFeature previewFeature ) {
221+ if (previewFeatureList == null || !previewFeatureList .contains (previewFeature )) {
222+ throw new IllegalStateException (
223+ """
224+ The preview feature %s is not enabled.
225+ Maybe add %s to <enablePreviewFeature> in your configuration file?"""
226+ .formatted (previewFeature , previewFeature ));
227+ }
228+ }
229+
201230 @ Override
202231 public String toString () {
203232 return getClass ().getSimpleName () + "(" + environmentMode + ")" ;
204233 }
205234
206235 public static class Builder <Solution_ > {
207236
208- private final EnvironmentMode environmentMode ;
209- private final Integer moveThreadCount ;
210- private final Integer moveThreadBufferSize ;
211- private final Class <? extends ThreadFactory > threadFactoryClass ;
212- private final InitializingScoreTrend initializingScoreTrend ;
213- private final SolutionDescriptor <Solution_ > solutionDescriptor ;
214- private final ClassInstanceCache classInstanceCache ;
237+ private Set <PreviewFeature > previewFeatureList ;
238+ private EnvironmentMode environmentMode ;
239+ private Integer moveThreadCount ;
240+ private Integer moveThreadBufferSize ;
241+ private Class <? extends ThreadFactory > threadFactoryClass ;
242+ private InitializingScoreTrend initializingScoreTrend ;
243+ private SolutionDescriptor <Solution_ > solutionDescriptor ;
244+ private ClassInstanceCache classInstanceCache ;
215245
216246 private String logIndentation = "" ;
217247
@@ -222,23 +252,58 @@ public static class Builder<Solution_> {
222252 private boolean initializedChainedValueFilterEnabled = false ;
223253 private boolean unassignedValuesAllowed = false ;
224254
225- private final Class <? extends NearbyDistanceMeter <?, ?>> nearbyDistanceMeterClass ;
226- private final Random random ;
255+ private Class <? extends NearbyDistanceMeter <?, ?>> nearbyDistanceMeterClass ;
256+ private Random random ;
257+
258+ public Builder <Solution_ > withPreviewFeatureList (Set <PreviewFeature > previewFeatureList ) {
259+ this .previewFeatureList = previewFeatureList ;
260+ return this ;
261+ }
227262
228- public Builder (EnvironmentMode environmentMode , Integer moveThreadCount , Integer moveThreadBufferSize ,
229- Class <? extends ThreadFactory > threadFactoryClass ,
230- Class <? extends NearbyDistanceMeter <?, ?>> nearbyDistanceMeterClass , Random random ,
231- InitializingScoreTrend initializingScoreTrend , SolutionDescriptor <Solution_ > solutionDescriptor ,
232- ClassInstanceCache classInstanceCache ) {
263+ public Builder <Solution_ > withEnvironmentMode (EnvironmentMode environmentMode ) {
233264 this .environmentMode = environmentMode ;
265+ return this ;
266+ }
267+
268+ public Builder <Solution_ > withMoveThreadCount (Integer moveThreadCount ) {
234269 this .moveThreadCount = moveThreadCount ;
270+ return this ;
271+ }
272+
273+ public Builder <Solution_ > withMoveThreadBufferSize (Integer moveThreadBufferSize ) {
235274 this .moveThreadBufferSize = moveThreadBufferSize ;
275+ return this ;
276+ }
277+
278+ public Builder <Solution_ > withThreadFactoryClass (Class <? extends ThreadFactory > threadFactoryClass ) {
236279 this .threadFactoryClass = threadFactoryClass ;
280+ return this ;
281+ }
282+
283+ public Builder <Solution_ >
284+ withNearbyDistanceMeterClass (Class <? extends NearbyDistanceMeter <?, ?>> nearbyDistanceMeterClass ) {
237285 this .nearbyDistanceMeterClass = nearbyDistanceMeterClass ;
286+ return this ;
287+ }
288+
289+ public Builder <Solution_ > withRandom (Random random ) {
238290 this .random = random ;
291+ return this ;
292+ }
293+
294+ public Builder <Solution_ > withInitializingScoreTrend (InitializingScoreTrend initializingScoreTrend ) {
239295 this .initializingScoreTrend = initializingScoreTrend ;
296+ return this ;
297+ }
298+
299+ public Builder <Solution_ > withSolutionDescriptor (SolutionDescriptor <Solution_ > solutionDescriptor ) {
240300 this .solutionDescriptor = solutionDescriptor ;
301+ return this ;
302+ }
303+
304+ public Builder <Solution_ > withClassInstanceCache (ClassInstanceCache classInstanceCache ) {
241305 this .classInstanceCache = classInstanceCache ;
306+ return this ;
242307 }
243308
244309 public Builder <Solution_ > withLogIndentation (String logIndentation ) {
0 commit comments