/*
* Copyright 2010 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.drools.planner.core.localsearch.decider.deciderscorecomparator;
import java.util.Comparator;
import org.drools.planner.core.localsearch.LocalSearchSolverScope;
import org.drools.planner.core.localsearch.LocalSearchStepScope;
import org.drools.planner.core.score.HardAndSoftScore;
import org.drools.planner.core.score.Score;
import org.drools.planner.core.score.comparator.NaturalScoreComparator;
/**
* Implementation of {@link HardAndSoftScore}.
* Compares by
* @see DeciderScoreComparatorFactory
*/
public class ShiftingHardPenaltyDeciderScoreComparatorFactory extends AbstractDeciderScoreComparatorFactory {
private int hardScoreActivationThreshold = 0;
private int successiveNoHardChangeMinimum = 2;
private int successiveNoHardChangeMaximum = 20;
private double successiveNoHardChangeRepetitionMultiplicand = 20.0;
private double hardWeightSurvivalRatio = 0.8;
private int startingHardWeight = 1000; // TODO determine dynamically
private int successiveNoHardScoreChange;
private boolean shiftingPenaltyActive;
private int hardWeight;
private Comparator<Score> naturalDeciderScoreComparator = new NaturalScoreComparator();
public void setHardScoreActivationThreshold(int hardScoreActivationThreshold) {
this.hardScoreActivationThreshold = hardScoreActivationThreshold;
}
public void setSuccessiveNoHardChangeMinimum(int successiveNoHardChangeMinimum) {
this.successiveNoHardChangeMinimum = successiveNoHardChangeMinimum;
}
public void setSuccessiveNoHardChangeMaximum(int successiveNoHardChangeMaximum) {
this.successiveNoHardChangeMaximum = successiveNoHardChangeMaximum;
}
public void setSuccessiveNoHardChangeRepetitionMultiplicand(double successiveNoHardChangeRepetitionMultiplicand) {
this.successiveNoHardChangeRepetitionMultiplicand = successiveNoHardChangeRepetitionMultiplicand;
}
public void setHardWeightSurvivalRatio(double hardWeightSurvivalRatio) {
this.hardWeightSurvivalRatio = hardWeightSurvivalRatio;
}
public void setStartingHardWeight(int startingHardWeight) {
this.startingHardWeight = startingHardWeight;
}
// ************************************************************************
// Worker methods
// ************************************************************************
@Override
public void solvingStarted(LocalSearchSolverScope localSearchSolverScope) {
successiveNoHardScoreChange = 0;
shiftingPenaltyActive = false;
}
@Override
public void stepTaken(LocalSearchStepScope localSearchStepScope) {
if (localSearchStepScope.getStepIndex() == localSearchStepScope.getLocalSearchSolverScope().getBestSolutionStepIndex()) {
successiveNoHardScoreChange = 0;
shiftingPenaltyActive = false;
} else {
HardAndSoftScore lastStepScore = (HardAndSoftScore) localSearchStepScope.getLocalSearchSolverScope()
.getLastCompletedLocalSearchStepScope().getScore();
HardAndSoftScore stepScore = (HardAndSoftScore) localSearchStepScope.getScore();
if (stepScore.getHardScore() >= hardScoreActivationThreshold
&& lastStepScore.getHardScore() == stepScore.getHardScore()) {
successiveNoHardScoreChange++;
} else {
successiveNoHardScoreChange--;
if (successiveNoHardScoreChange < 0) {
successiveNoHardScoreChange = 0;
}
}
int min = successiveNoHardChangeMinimum;
int max = successiveNoHardChangeMaximum;
while (true) {
if (successiveNoHardScoreChange < min) {
shiftingPenaltyActive = false;
break;
} else if (successiveNoHardScoreChange <= max) {
shiftingPenaltyActive = true;
if (successiveNoHardScoreChange == min) {
hardWeight = startingHardWeight;
} else {
hardWeight = (int) Math.round(((double) hardWeight) * hardWeightSurvivalRatio);
}
break;
}
min = (int) Math.round(((double) min) * successiveNoHardChangeRepetitionMultiplicand);
max = (int) Math.round(((double) max) * successiveNoHardChangeRepetitionMultiplicand);
}
}
}
public Comparator<Score> createDeciderScoreComparator() {
if (shiftingPenaltyActive) {
return new HardPenaltyDeciderScoreComparator(hardWeight);
} else {
return naturalDeciderScoreComparator;
}
}
}