1717import ai .timefold .solver .core .impl .localsearch .decider .acceptor .lateacceptance .LateAcceptanceAcceptor ;
1818import ai .timefold .solver .core .impl .localsearch .decider .acceptor .simulatedannealing .SimulatedAnnealingAcceptor ;
1919import ai .timefold .solver .core .impl .localsearch .decider .acceptor .stepcountinghillclimbing .StepCountingHillClimbingAcceptor ;
20+ import ai .timefold .solver .core .impl .localsearch .decider .acceptor .tabu .AbstractTabuAcceptor ;
2021import ai .timefold .solver .core .impl .localsearch .decider .acceptor .tabu .EntityTabuAcceptor ;
2122import ai .timefold .solver .core .impl .localsearch .decider .acceptor .tabu .MoveTabuAcceptor ;
2223import ai .timefold .solver .core .impl .localsearch .decider .acceptor .tabu .ValueTabuAcceptor ;
@@ -54,15 +55,14 @@ public Acceptor<Solution_> buildAcceptor(HeuristicConfigPolicy<Solution_> config
5455 .collect (Collectors .toList ());
5556
5657 if (acceptorList .size () == 1 ) {
57- return acceptorList .get ( 0 );
58+ return acceptorList .getFirst ( );
5859 } else if (acceptorList .size () > 1 ) {
5960 return new CompositeAcceptor <>(acceptorList );
6061 } else {
61- throw new IllegalArgumentException (
62- "The acceptor does not specify any acceptorType (" + acceptorConfig .getAcceptorTypeList ()
63- + ") or other acceptor property.\n "
64- + "For a good starting values,"
65- + " see the docs section \" Which optimization algorithms should I use?\" ." );
62+ throw new IllegalArgumentException ("""
63+ The acceptor does not specify any acceptorType (%s) or other acceptor property.
64+ For good starting values, see the docs section "Which optimization algorithms should I use?"."""
65+ .formatted (acceptorConfig .getAcceptorTypeList ()));
6666 }
6767 }
6868
@@ -94,34 +94,35 @@ private Optional<StepCountingHillClimbingAcceptor<Solution_>> buildStepCountingH
9494 }
9595
9696 private Optional <EntityTabuAcceptor <Solution_ >> buildEntityTabuAcceptor (HeuristicConfigPolicy <Solution_ > configPolicy ) {
97+ var entityTabuSize = acceptorConfig .getEntityTabuSize ();
98+ var entityTabuRatio = acceptorConfig .getEntityTabuRatio ();
99+ var fadingEntityTabuSize = acceptorConfig .getFadingEntityTabuSize ();
100+ var fadingEntityTabuRatio = acceptorConfig .getFadingEntityTabuRatio ();
97101 if (acceptorTypeListsContainsAcceptorType (AcceptorType .ENTITY_TABU )
98- || acceptorConfig . getEntityTabuSize () != null || acceptorConfig . getEntityTabuRatio () != null
99- || acceptorConfig . getFadingEntityTabuSize () != null || acceptorConfig . getFadingEntityTabuRatio () != null ) {
102+ || entityTabuSize != null || entityTabuRatio != null
103+ || fadingEntityTabuSize != null || fadingEntityTabuRatio != null ) {
100104 var acceptor = new EntityTabuAcceptor <Solution_ >(configPolicy .getLogIndentation ());
101- if (acceptorConfig . getEntityTabuSize () != null ) {
102- if (acceptorConfig . getEntityTabuRatio () != null ) {
103- throw new IllegalArgumentException ("The acceptor cannot have both acceptorConfig.getEntityTabuSize() ("
104- + acceptorConfig . getEntityTabuSize () + ") and acceptorConfig.getEntityTabuRatio() ( "
105- + acceptorConfig . getEntityTabuRatio () + ")." );
105+ if (entityTabuSize != null ) {
106+ if (entityTabuRatio != null ) {
107+ throw new IllegalArgumentException (
108+ "The acceptor cannot have both entityTabuSize (%d) and entityTabuRatio (%f). "
109+ . formatted ( entityTabuSize , entityTabuRatio ) );
106110 }
107- acceptor .setTabuSizeStrategy (new FixedTabuSizeStrategy <>(acceptorConfig . getEntityTabuSize () ));
108- } else if (acceptorConfig . getEntityTabuRatio () != null ) {
109- acceptor .setTabuSizeStrategy (new EntityRatioTabuSizeStrategy <>(acceptorConfig . getEntityTabuRatio () ));
110- } else if (acceptorConfig . getFadingEntityTabuSize () == null && acceptorConfig . getFadingEntityTabuRatio () == null ) {
111+ acceptor .setTabuSizeStrategy (new FixedTabuSizeStrategy <>(entityTabuSize ));
112+ } else if (entityTabuRatio != null ) {
113+ acceptor .setTabuSizeStrategy (new EntityRatioTabuSizeStrategy <>(entityTabuRatio ));
114+ } else if (fadingEntityTabuSize == null && fadingEntityTabuRatio == null ) {
111115 acceptor .setTabuSizeStrategy (new EntityRatioTabuSizeStrategy <>(0.1 ));
112116 }
113- if (acceptorConfig . getFadingEntityTabuSize () != null ) {
114- if (acceptorConfig . getFadingEntityTabuRatio () != null ) {
117+ if (fadingEntityTabuSize != null ) {
118+ if (fadingEntityTabuRatio != null ) {
115119 throw new IllegalArgumentException (
116- "The acceptor cannot have both acceptorConfig.getFadingEntityTabuSize() ("
117- + acceptorConfig .getFadingEntityTabuSize ()
118- + ") and acceptorConfig.getFadingEntityTabuRatio() ("
119- + acceptorConfig .getFadingEntityTabuRatio () + ")." );
120+ "The acceptor cannot have both fadingEntityTabuSize (%d) and fadingEntityTabuRatio (%f)."
121+ .formatted (fadingEntityTabuSize , fadingEntityTabuRatio ));
120122 }
121- acceptor .setFadingTabuSizeStrategy (new FixedTabuSizeStrategy <>(acceptorConfig .getFadingEntityTabuSize ()));
122- } else if (acceptorConfig .getFadingEntityTabuRatio () != null ) {
123- acceptor .setFadingTabuSizeStrategy (
124- new EntityRatioTabuSizeStrategy <>(acceptorConfig .getFadingEntityTabuRatio ()));
123+ acceptor .setFadingTabuSizeStrategy (new FixedTabuSizeStrategy <>(fadingEntityTabuSize ));
124+ } else if (fadingEntityTabuRatio != null ) {
125+ acceptor .setFadingTabuSizeStrategy (new EntityRatioTabuSizeStrategy <>(fadingEntityTabuRatio ));
125126 }
126127 if (configPolicy .getEnvironmentMode ().isFullyAsserted ()) {
127128 acceptor .setAssertTabuHashCodeCorrectness (true );
@@ -132,43 +133,47 @@ private Optional<EntityTabuAcceptor<Solution_>> buildEntityTabuAcceptor(Heuristi
132133 }
133134
134135 private Optional <ValueTabuAcceptor <Solution_ >> buildValueTabuAcceptor (HeuristicConfigPolicy <Solution_ > configPolicy ) {
136+ var valueTabuSize = acceptorConfig .getValueTabuSize ();
137+ var fadingValueTabuSize = acceptorConfig .getFadingValueTabuSize ();
135138 if (acceptorTypeListsContainsAcceptorType (AcceptorType .VALUE_TABU )
136- || acceptorConfig .getValueTabuSize () != null || acceptorConfig .getFadingValueTabuSize () != null ) {
137- var acceptor = new ValueTabuAcceptor <Solution_ >(configPolicy .getLogIndentation ());
138- if (acceptorConfig .getValueTabuSize () != null ) {
139- acceptor .setTabuSizeStrategy (new FixedTabuSizeStrategy <>(acceptorConfig .getValueTabuSize ()));
140- }
141- if (acceptorConfig .getFadingValueTabuSize () != null ) {
142- acceptor .setFadingTabuSizeStrategy (new FixedTabuSizeStrategy <>(acceptorConfig .getFadingValueTabuSize ()));
143- }
144-
145- if (acceptorConfig .getValueTabuSize () != null ) {
146- acceptor .setTabuSizeStrategy (new FixedTabuSizeStrategy <>(acceptorConfig .getValueTabuSize ()));
147- }
148- if (acceptorConfig .getFadingValueTabuSize () != null ) {
149- acceptor .setFadingTabuSizeStrategy (new FixedTabuSizeStrategy <>(acceptorConfig .getFadingValueTabuSize ()));
150- }
151- if (configPolicy .getEnvironmentMode ().isFullyAsserted ()) {
152- acceptor .setAssertTabuHashCodeCorrectness (true );
139+ || valueTabuSize != null || fadingValueTabuSize != null ) {
140+ if (valueTabuSize == null && fadingValueTabuSize == null ) {
141+ throw new IllegalArgumentException (
142+ "The acceptorType (%s) requires either valueTabuSize or fadingValueTabuSize to be configured."
143+ .formatted (AcceptorType .VALUE_TABU ));
153144 }
145+ var acceptor = new ValueTabuAcceptor <Solution_ >(configPolicy .getLogIndentation ());
146+ configureFixedSizeTabuAcceptor (acceptor , configPolicy , valueTabuSize , fadingValueTabuSize );
154147 return Optional .of (acceptor );
155148 }
156149 return Optional .empty ();
157150 }
158151
152+ private static <Solution_ > void configureFixedSizeTabuAcceptor (AbstractTabuAcceptor <Solution_ > acceptor ,
153+ HeuristicConfigPolicy <Solution_ > configPolicy , Integer tabuSize , Integer fadingTabuSize ) {
154+ if (tabuSize != null ) {
155+ acceptor .setTabuSizeStrategy (new FixedTabuSizeStrategy <>(tabuSize ));
156+ }
157+ if (fadingTabuSize != null ) {
158+ acceptor .setFadingTabuSizeStrategy (new FixedTabuSizeStrategy <>(fadingTabuSize ));
159+ }
160+ if (configPolicy .getEnvironmentMode ().isFullyAsserted ()) {
161+ acceptor .setAssertTabuHashCodeCorrectness (true );
162+ }
163+ }
164+
159165 private Optional <MoveTabuAcceptor <Solution_ >> buildMoveTabuAcceptor (HeuristicConfigPolicy <Solution_ > configPolicy ) {
166+ var moveTabuSize = acceptorConfig .getMoveTabuSize ();
167+ var fadingMoveTabuSize = acceptorConfig .getFadingMoveTabuSize ();
160168 if (acceptorTypeListsContainsAcceptorType (AcceptorType .MOVE_TABU )
161- || acceptorConfig .getMoveTabuSize () != null || acceptorConfig .getFadingMoveTabuSize () != null ) {
162- var acceptor = new MoveTabuAcceptor <Solution_ >(configPolicy .getLogIndentation ());
163- if (acceptorConfig .getMoveTabuSize () != null ) {
164- acceptor .setTabuSizeStrategy (new FixedTabuSizeStrategy <>(acceptorConfig .getMoveTabuSize ()));
165- }
166- if (acceptorConfig .getFadingMoveTabuSize () != null ) {
167- acceptor .setFadingTabuSizeStrategy (new FixedTabuSizeStrategy <>(acceptorConfig .getFadingMoveTabuSize ()));
168- }
169- if (configPolicy .getEnvironmentMode ().isFullyAsserted ()) {
170- acceptor .setAssertTabuHashCodeCorrectness (true );
169+ || moveTabuSize != null || fadingMoveTabuSize != null ) {
170+ if (moveTabuSize == null && fadingMoveTabuSize == null ) {
171+ throw new IllegalArgumentException (
172+ "The acceptorType (%s) requires either moveTabuSize or fadingMoveTabuSize to be configured."
173+ .formatted (AcceptorType .MOVE_TABU ));
171174 }
175+ var acceptor = new MoveTabuAcceptor <Solution_ >(configPolicy .getLogIndentation ());
176+ configureFixedSizeTabuAcceptor (acceptor , configPolicy , moveTabuSize , fadingMoveTabuSize );
172177 return Optional .of (acceptor );
173178 }
174179 return Optional .empty ();
@@ -181,9 +186,9 @@ private Optional<MoveTabuAcceptor<Solution_>> buildMoveTabuAcceptor(HeuristicCon
181186 var acceptor = new SimulatedAnnealingAcceptor <Solution_ >();
182187 if (acceptorConfig .getSimulatedAnnealingStartingTemperature () == null ) {
183188 // TODO Support SA without a parameter
184- throw new IllegalArgumentException ("The acceptorType (" + AcceptorType . SIMULATED_ANNEALING
185- + ") currently requires a acceptorConfig.getSimulatedAnnealingStartingTemperature() ( "
186- + acceptorConfig . getSimulatedAnnealingStartingTemperature () + ")." );
189+ throw new IllegalArgumentException (
190+ "The acceptorType (%s) requires non-null acceptorConfig.getSimulatedAnnealingStartingTemperature(). "
191+ . formatted ( AcceptorType . SIMULATED_ANNEALING ) );
187192 }
188193 acceptor .setStartingTemperature (
189194 configPolicy .getScoreDefinition ().parseScore (acceptorConfig .getSimulatedAnnealingStartingTemperature ()));
@@ -221,19 +226,20 @@ private Optional<GreatDelugeAcceptor<Solution_>> buildGreatDelugeAcceptor(Heuris
221226 var acceptor = new GreatDelugeAcceptor <Solution_ >();
222227 if (acceptorConfig .getGreatDelugeWaterLevelIncrementScore () != null ) {
223228 if (acceptorConfig .getGreatDelugeWaterLevelIncrementRatio () != null ) {
224- throw new IllegalArgumentException ("The acceptor cannot have both a "
225- + " acceptorConfig.getGreatDelugeWaterLevelIncrementScore() ("
226- + acceptorConfig .getGreatDelugeWaterLevelIncrementScore ()
227- + ") and a acceptorConfig.getGreatDelugeWaterLevelIncrementRatio() ("
228- + acceptorConfig .getGreatDelugeWaterLevelIncrementRatio () + ")." );
229+ throw new IllegalArgumentException ("" "
230+ The acceptor cannot have both acceptorConfig.getGreatDelugeWaterLevelIncrementScore() (%s) \
231+ and acceptorConfig.getGreatDelugeWaterLevelIncrementRatio() (%s)."""
232+ . formatted ( acceptorConfig .getGreatDelugeWaterLevelIncrementScore (),
233+ acceptorConfig .getGreatDelugeWaterLevelIncrementRatio ()) );
229234 }
230235 acceptor .setWaterLevelIncrementScore (
231236 configPolicy .getScoreDefinition ().parseScore (acceptorConfig .getGreatDelugeWaterLevelIncrementScore ()));
232237 } else if (acceptorConfig .getGreatDelugeWaterLevelIncrementRatio () != null ) {
233238 if (acceptorConfig .getGreatDelugeWaterLevelIncrementRatio () <= 0.0 ) {
234- throw new IllegalArgumentException ("The acceptorConfig.getGreatDelugeWaterLevelIncrementRatio() ("
235- + acceptorConfig .getGreatDelugeWaterLevelIncrementRatio ()
236- + ") must be positive because the water level should increase." );
239+ throw new IllegalArgumentException ("""
240+ The acceptorConfig.getGreatDelugeWaterLevelIncrementRatio() (%s) must be positive \
241+ because the water level should increase."""
242+ .formatted (acceptorConfig .getGreatDelugeWaterLevelIncrementRatio ()));
237243 }
238244 acceptor .setWaterLevelIncrementRatio (acceptorConfig .getGreatDelugeWaterLevelIncrementRatio ());
239245 } else {
0 commit comments