diff --git a/optaplanner-core/src/main/java/org/optaplanner/core/config/localsearch/decider/acceptor/AcceptorConfig.java b/optaplanner-core/src/main/java/org/optaplanner/core/config/localsearch/decider/acceptor/AcceptorConfig.java index 5e832a7679..4fb44ddff1 100644 --- a/optaplanner-core/src/main/java/org/optaplanner/core/config/localsearch/decider/acceptor/AcceptorConfig.java +++ b/optaplanner-core/src/main/java/org/optaplanner/core/config/localsearch/decider/acceptor/AcceptorConfig.java @@ -21,6 +21,7 @@ import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamImplicit; +import org.optaplanner.core.api.score.Score; import org.optaplanner.core.config.AbstractConfig; import org.optaplanner.core.config.heuristic.policy.HeuristicConfigPolicy; import org.optaplanner.core.config.localsearch.decider.acceptor.stepcountinghillclimbing.StepCountingHillClimbingType; @@ -76,8 +77,8 @@ public class AcceptorConfig extends AbstractConfig { protected StepCountingHillClimbingType stepCountingHillClimbingType = null; protected String greatDelugeStartingWaterLevel = null; - protected Double greatDelugeRainSpeed = null; protected Double greatDelugeRainSpeedRatio = null; + protected String greatDelugeRainSpeedScore = null; @Deprecated public List> getAcceptorClassList() { @@ -249,12 +250,12 @@ public void setGreatDelugeStartingWaterLevel(String greatDelugeStartingWaterLeve this.greatDelugeStartingWaterLevel = greatDelugeStartingWaterLevel; } - public Double getGreatDelugeRainSpeed() { - return greatDelugeRainSpeed; + public String getGreatDelugeRainSpeedScore() { + return greatDelugeRainSpeedScore; } - public void setGreatDelugeRainSpeed(Double greatDelugeRainSpeed) { - this.greatDelugeRainSpeed = greatDelugeRainSpeed; + public void setGreatDelugeRainSpeedScore(String greatDelugeRainSpeedScore) { + this.greatDelugeRainSpeedScore = greatDelugeRainSpeedScore; } public Double getGreatDelugeRainSpeedRatio() { @@ -525,26 +526,30 @@ public Acceptor buildAcceptor(HeuristicConfigPolicy configPolicy) { acceptorList.add(acceptor); } if ((acceptorTypeList!= null && acceptorTypeList.contains(AcceptorType.GREAT_DELUGE)) - || greatDelugeRainSpeed != null || greatDelugeRainSpeedRatio != null) { + || greatDelugeRainSpeedRatio != null || greatDelugeRainSpeedScore != null) { GreatDelugeAcceptor acceptor = new GreatDelugeAcceptor(); - if (greatDelugeRainSpeed != null && greatDelugeRainSpeedRatio != null) { - throw new IllegalArgumentException("You can use only rainSpeed or rainSpeedRatio at a time."); + if (greatDelugeRainSpeedScore != null && greatDelugeRainSpeedRatio != null) { + throw new IllegalArgumentException("The greatDelugeRainSpeedScore (" + greatDelugeRainSpeedScore + + ") and greatDelugeRainSpeedRatio (" + greatDelugeRainSpeedRatio + + ") cannot be both non null."); } - if (greatDelugeRainSpeed != null) { - acceptor.setRainSpeed(greatDelugeRainSpeed); - } if (greatDelugeRainSpeedRatio != null) { acceptor.setRainSpeedRatio(greatDelugeRainSpeedRatio); } + if (greatDelugeRainSpeedScore != null) { + acceptor.setRainSpeedScore(configPolicy.getScoreDefinition().parseScore(greatDelugeRainSpeedScore)); + } + if (greatDelugeStartingWaterLevel != null) { - acceptor.setInitialLevels(configPolicy.getScoreDefinition() + acceptor.setInitialWaterLevels(configPolicy.getScoreDefinition() .parseScore(greatDelugeStartingWaterLevel)); } acceptorList.add(acceptor); } + if (acceptorList.size() == 1) { return acceptorList.get(0); } else if (acceptorList.size() > 1) { @@ -606,10 +611,10 @@ public void inherit(AcceptorConfig inheritedConfig) { inheritedConfig.getStepCountingHillClimbingType()); greatDelugeStartingWaterLevel = ConfigUtils.inheritOverwritableProperty(greatDelugeStartingWaterLevel, inheritedConfig.getGreatDelugeStartingWaterLevel()); - greatDelugeRainSpeed = ConfigUtils.inheritOverwritableProperty(greatDelugeRainSpeed, - inheritedConfig.getGreatDelugeRainSpeed()); greatDelugeRainSpeedRatio = ConfigUtils.inheritOverwritableProperty(greatDelugeRainSpeedRatio, inheritedConfig.getGreatDelugeRainSpeedRatio()); + greatDelugeRainSpeedScore = ConfigUtils.inheritOverwritableProperty(greatDelugeRainSpeedScore, + inheritedConfig.getGreatDelugeRainSpeedScore()); } } diff --git a/optaplanner-core/src/main/java/org/optaplanner/core/impl/localsearch/decider/acceptor/greatdeluge/GreatDelugeAcceptor.java b/optaplanner-core/src/main/java/org/optaplanner/core/impl/localsearch/decider/acceptor/greatdeluge/GreatDelugeAcceptor.java index 5ec2c1f57c..8bfe598be2 100644 --- a/optaplanner-core/src/main/java/org/optaplanner/core/impl/localsearch/decider/acceptor/greatdeluge/GreatDelugeAcceptor.java +++ b/optaplanner-core/src/main/java/org/optaplanner/core/impl/localsearch/decider/acceptor/greatdeluge/GreatDelugeAcceptor.java @@ -9,110 +9,79 @@ public class GreatDelugeAcceptor extends AbstractAcceptor { - private Score initialLevel = null; + private Score initialWaterLevels = null; + private Score currentWaterLevel = null; - private Double rainSpeed = null; private Double rainSpeedRatio = DEFAULT_RAIN_SPEED_RATIO; - - private int levelsLength = -1; - private double[] initialLevelScoreLevels; - private double[] levelScoreLevels; - - private double levelMinimum = 0; - private static final double THRESHOLD = .0000001; + private Score rainSpeedScore = null; // Good value to come out from. Source: https://github.com/UniTime/cpsolver from Tomas Muller private static final double DEFAULT_RAIN_SPEED_RATIO = 0.99_999_995; - public void setInitialLevels(Score initialLevel) { this.initialLevel = initialLevel; } - public Score getInitialLevels() { return this.initialLevel; } + public Score getRainSpeedScore() { + return this.rainSpeedScore; + } - public void setRainSpeed(Double rainSpeed) { - this.rainSpeed = rainSpeed; + public void setRainSpeedScore(Score rainSpeedScore) { + this.rainSpeedScore = rainSpeedScore; this.rainSpeedRatio = null; } - public Double getRainSpeed() { return this.rainSpeed; } + public Score getInitialWaterLevels() { + return this.initialWaterLevels; + } - public void setRainSpeedRatio(Double rainSpeedRatio) {this.rainSpeedRatio = rainSpeedRatio; } + public void setInitialWaterLevels(Score initialLevel) { + this.initialWaterLevels = initialLevel; + } - public Double getRainSpeedRatio() { return this.rainSpeedRatio; } + public Double getRainSpeedRatio() { + return this.rainSpeedRatio; + } - public double[] getLevelScoreLevels() { return this.levelScoreLevels; } + public void setRainSpeedRatio(Double rainSpeedRatio) { + this.rainSpeedRatio = rainSpeedRatio; + } public void phaseStarted(LocalSearchPhaseScope phaseScope) { super.phaseStarted(phaseScope); - if (initialLevel != null) { - for (double initialLevelLevel : ScoreUtils.extractLevelDoubles(initialLevel)) { + if (initialWaterLevels != null) { + for (double initialLevelLevel : ScoreUtils.extractLevelDoubles(initialWaterLevels)) { if (initialLevelLevel < 0.0) { - throw new IllegalArgumentException("The initial level (" + initialLevel - + ") cannot have negative level (" + initialLevelLevel + ")."); + throw new IllegalArgumentException("The initial level (" + initialWaterLevels + + ") cannot have negative level (" + initialLevelLevel + ")."); } } - initialLevelScoreLevels = ScoreUtils.extractLevelDoubles(initialLevel); - levelScoreLevels = initialLevelScoreLevels; - } else { - double[] initialLevelScoreLevelsNegative; - initialLevelScoreLevelsNegative = ScoreUtils.extractLevelDoubles(phaseScope.getBestScore()); - levelScoreLevels = initialLevelScoreLevelsNegative; + currentWaterLevel = initialWaterLevels; - for (int i = 0; i < levelScoreLevels.length; i++) { - if (Math.abs(levelScoreLevels[i]) < THRESHOLD) { - continue; - } - levelScoreLevels[i] = -levelScoreLevels[i]; - } + } else { + currentWaterLevel = phaseScope.getBestScore().negate(); } - levelsLength = levelScoreLevels.length; } public void phaseEnded(LocalSearchPhaseScope phaseScope) { super.phaseEnded(phaseScope); - initialLevelScoreLevels = null; - levelScoreLevels = null; - levelsLength = -1; + initialWaterLevels = null; + rainSpeedRatio = DEFAULT_RAIN_SPEED_RATIO; + rainSpeedScore = null; } @Override public boolean isAccepted(LocalSearchMoveScope moveScope) { Score moveScore = moveScope.getScore(); - double[] moveScoreLevels = ScoreUtils.extractLevelDoubles(moveScore); - - for (int i = 0; i < levelsLength; i++) { - double moveScoreLevel = moveScoreLevels[i]; - double levelScoreLevel = levelScoreLevels[i]; - - double isZeroIfEqual = Math.abs(moveScoreLevel + levelScoreLevel); - - if (moveScoreLevel > -levelScoreLevel) { - // Checks if given score is better than water level, if so, move is accepted. - return true; - } else if (!(isZeroIfEqual < THRESHOLD)) { - // Returns false when above condition is not met and, new score and water level are not equal. - return false; - } else if (i == levelsLength - 1){ - // Returns true when new score and water level are equal and it is last iteration of cycle. - return true; - } - } - return true; + + return moveScore.compareTo(currentWaterLevel.negate()) >= 0; } - // change water level at the beginning of the step public void stepStarted(LocalSearchStepScope stepScope) { super.stepEnded(stepScope); - for (int i = 0; i < levelsLength; i++) { - if (rainSpeed != null) { - levelScoreLevels[i] = levelScoreLevels[i] - rainSpeed; - } else if (rainSpeedRatio != null) { - levelScoreLevels[i] = levelScoreLevels[i] * rainSpeedRatio; - } - if (levelScoreLevels[i] < levelMinimum) { - levelScoreLevels[i] = levelMinimum; - } + if (rainSpeedScore != null) { + currentWaterLevel = currentWaterLevel.subtract(rainSpeedScore); + } else { + currentWaterLevel = currentWaterLevel.multiply(rainSpeedRatio); } } } diff --git a/optaplanner-core/src/test/java/org/optaplanner/core/impl/localsearch/decider/acceptor/greatdeluge/GreatDelugeAcceptorTest.java b/optaplanner-core/src/test/java/org/optaplanner/core/impl/localsearch/decider/acceptor/greatdeluge/GreatDelugeAcceptorTest.java index f942dd108f..3265d34ea6 100644 --- a/optaplanner-core/src/test/java/org/optaplanner/core/impl/localsearch/decider/acceptor/greatdeluge/GreatDelugeAcceptorTest.java +++ b/optaplanner-core/src/test/java/org/optaplanner/core/impl/localsearch/decider/acceptor/greatdeluge/GreatDelugeAcceptorTest.java @@ -11,10 +11,7 @@ import org.optaplanner.core.impl.solver.scope.DefaultSolverScope; import org.optaplanner.core.impl.testdata.domain.TestdataSolution; -import java.util.Arrays; - import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; @@ -24,8 +21,8 @@ public class GreatDelugeAcceptorTest extends AbstractAcceptorTest { public void isAcceptedPositiveLevelSingleScoreRainSpeed() { GreatDelugeAcceptor acceptor = new GreatDelugeAcceptor(); - acceptor.setInitialLevels(SimpleScore.of(1100)); - acceptor.setRainSpeed(100.0); + acceptor.setInitialWaterLevels(SimpleScore.of(1100)); + acceptor.setRainSpeedScore(SimpleScore.of(100)); DefaultSolverScope solverScope = new DefaultSolverScope<>(); solverScope.setBestScore(SimpleScore.of(-1000)); @@ -99,8 +96,8 @@ public void isAcceptedPositiveLevelSingleScoreRainSpeed() { public void isAcceptedPositiveLevelMultipleScoreRainSpeed() { GreatDelugeAcceptor acceptor = new GreatDelugeAcceptor(); - acceptor.setInitialLevels(HardMediumSoftScore.of(0, 200, 500)); - acceptor.setRainSpeed(100.0); + acceptor.setInitialWaterLevels(HardMediumSoftScore.of(0, 200, 500)); + acceptor.setRainSpeedScore(HardMediumSoftScore.of(0,100,100)); DefaultSolverScope solverScope = new DefaultSolverScope<>(); solverScope.setBestScore(HardMediumSoftScore.of(0, -200, -1000)); @@ -145,7 +142,7 @@ public void isAcceptedPositiveLevelMultipleScoreRainSpeed() { public void isAcceptedPositiveLevelMultipleScoreRainSpeedRatio() { GreatDelugeAcceptor acceptor = new GreatDelugeAcceptor(); - acceptor.setInitialLevels(HardMediumSoftScore.of(0, 200, 500)); + acceptor.setInitialWaterLevels(HardMediumSoftScore.of(0, 200, 500)); acceptor.setRainSpeedRatio(0.9); DefaultSolverScope solverScope = new DefaultSolverScope<>(); @@ -191,11 +188,11 @@ public void isAcceptedPositiveLevelMultipleScoreRainSpeedRatio() { public void negativeWaterLevelSingleScore() { GreatDelugeAcceptor acceptor = new GreatDelugeAcceptor(); - acceptor.setInitialLevels(SimpleScore.of(-100)); + acceptor.setInitialWaterLevels(SimpleScore.of(-100)); try { acceptor.phaseStarted(null); } catch (IllegalArgumentException e) { - assertEquals("The initial level (" + acceptor.getInitialLevels() + assertEquals("The initial level (" + acceptor.getInitialWaterLevels() + ") cannot have negative level (" + "-100.0" + ").", e.getMessage()); } } @@ -203,70 +200,12 @@ public void negativeWaterLevelSingleScore() { public void negativeWaterLevelMultipleScore() { GreatDelugeAcceptor acceptor = new GreatDelugeAcceptor(); - acceptor.setInitialLevels(HardMediumSoftScore.parseScore("1hard/-1medium/2soft")); + acceptor.setInitialWaterLevels(HardMediumSoftScore.parseScore("1hard/-1medium/2soft")); try { acceptor.phaseStarted(null); } catch (IllegalArgumentException e) { - assertEquals("The initial level (" + acceptor.getInitialLevels() + assertEquals("The initial level (" + acceptor.getInitialWaterLevels() + ") cannot have negative level (" + "-1.0" + ").", e.getMessage()); } } - - @Test - public void parsingLevelScoreLevelsFromInitialLevelSingleScore() { - - GreatDelugeAcceptor acceptor = new GreatDelugeAcceptor(); - acceptor.setInitialLevels(SimpleScore.of(150)); - double[] actualScore = {150}; - acceptor.phaseStarted(null); - - assertTrue(Arrays.equals(actualScore, acceptor.getLevelScoreLevels())); - } - - @Test - public void parsingLevelScoreLevelsFromInitialLevelMultipleScore() { - - GreatDelugeAcceptor acceptor = new GreatDelugeAcceptor(); - acceptor.setInitialLevels(HardMediumSoftScore.parseScore("1hard/15medium/24soft")); - double[] actualScore = {1, 15, 24}; - acceptor.phaseStarted(null); - - assertTrue(Arrays.equals(actualScore, acceptor.getLevelScoreLevels())); - } - - @Test - public void parsingLevelScoreLevelsFromPhaseBestScoreSingleScore() { - - GreatDelugeAcceptor acceptor = new GreatDelugeAcceptor(); - acceptor.setRainSpeedRatio(0.9995); - - DefaultSolverScope solverScope = new DefaultSolverScope<>(); - solverScope.setBestScore(SimpleScore.of(-66)); - LocalSearchPhaseScope phaseScope = new LocalSearchPhaseScope<>(solverScope); - LocalSearchStepScope lastCompletedStepScope = new LocalSearchStepScope<>(phaseScope, -1); - lastCompletedStepScope.setScore(SimpleScore.of(-66)); - phaseScope.setLastCompletedStepScope(lastCompletedStepScope); - acceptor.phaseStarted(phaseScope); - double[] actualScore = {66}; - - assertTrue(Arrays.equals(actualScore, acceptor.getLevelScoreLevels())); - } - - @Test - public void parsingLevelScoreLevelsFromPhaseBestScoreMultipleScore() { - - GreatDelugeAcceptor acceptor = new GreatDelugeAcceptor(); - acceptor.setRainSpeedRatio(0.959595); - - DefaultSolverScope solverScope = new DefaultSolverScope<>(); - solverScope.setBestScore(HardMediumSoftScore.of(-5, 0, -24)); - LocalSearchPhaseScope phaseScope = new LocalSearchPhaseScope<>(solverScope); - LocalSearchStepScope lastCompletedStepScope = new LocalSearchStepScope<>(phaseScope, -1); - lastCompletedStepScope.setScore(HardMediumSoftScore.of(-5, 0, -24)); - phaseScope.setLastCompletedStepScope(lastCompletedStepScope); - acceptor.phaseStarted(phaseScope); - double[] actualScore = {5, 0, 24}; - - assertTrue(Arrays.equals(actualScore, acceptor.getLevelScoreLevels())); - } -} \ No newline at end of file + } \ No newline at end of file