/* * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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.optaplanner.core.api.score.buildin.bendablebigdecimal; import java.math.BigDecimal; import java.util.Arrays; import org.kie.api.runtime.rule.RuleContext; import org.optaplanner.core.api.score.Score; import org.optaplanner.core.api.score.holder.AbstractScoreHolder; /** * @see BendableBigDecimalScore */ public class BendableBigDecimalScoreHolder extends AbstractScoreHolder { private BigDecimal[] hardScores; private BigDecimal[] softScores; public BendableBigDecimalScoreHolder(boolean constraintMatchEnabled, int hardLevelsSize, int softLevelsSize) { super(constraintMatchEnabled, BendableBigDecimalScore.zero(hardLevelsSize, softLevelsSize)); hardScores = new BigDecimal[hardLevelsSize]; Arrays.fill(hardScores, BigDecimal.ZERO); softScores = new BigDecimal[softLevelsSize]; Arrays.fill(softScores, BigDecimal.ZERO); } public int getHardLevelsSize() { return hardScores.length; } public BigDecimal getHardScore(int hardLevel) { return hardScores[hardLevel]; } public int getSoftLevelsSize() { return softScores.length; } public BigDecimal getSoftScore(int softLevel) { return softScores[softLevel]; } // ************************************************************************ // Worker methods // ************************************************************************ /** * @param kcontext never null, the magic variable in DRL * @param hardLevel {@code 0 <= hardLevel <} {@link #getHardLevelsSize()}. * The {@code scoreLevel} is {@code hardLevel} for hard levels and {@code softLevel + hardLevelSize} for soft levels. * @param weight never null, higher is better, negative for a penalty, positive for a reward */ public void addHardConstraintMatch(RuleContext kcontext, int hardLevel, BigDecimal weight) { hardScores[hardLevel] = hardScores[hardLevel].add(weight); registerConstraintMatch(kcontext, () -> hardScores[hardLevel] = hardScores[hardLevel].subtract(weight), () -> { BigDecimal[] newHardScores = new BigDecimal[hardScores.length]; Arrays.fill(newHardScores, BigDecimal.ZERO); BigDecimal[] newSoftScores = new BigDecimal[softScores.length]; Arrays.fill(newSoftScores, BigDecimal.ZERO); newHardScores[hardLevel] = weight; return BendableBigDecimalScore.valueOf(newHardScores, newSoftScores); }); } /** * @param kcontext never null, the magic variable in DRL * @param softLevel {@code 0 <= softLevel <} {@link #getSoftLevelsSize()}. * The {@code scoreLevel} is {@code hardLevel} for hard levels and {@code softLevel + hardLevelSize} for soft levels. * @param weight never null, higher is better, negative for a penalty, positive for a reward */ public void addSoftConstraintMatch(RuleContext kcontext, int softLevel, BigDecimal weight) { softScores[softLevel] = softScores[softLevel].add(weight); registerConstraintMatch(kcontext, () -> softScores[softLevel] = softScores[softLevel].subtract(weight), () -> { BigDecimal[] newHardScores = new BigDecimal[hardScores.length]; Arrays.fill(newHardScores, BigDecimal.ZERO); BigDecimal[] newSoftScores = new BigDecimal[softScores.length]; Arrays.fill(newSoftScores, BigDecimal.ZERO); newSoftScores[softLevel] = weight; return BendableBigDecimalScore.valueOf(newHardScores, newSoftScores); }); } /** * @param kcontext never null, the magic variable in DRL * @param hardWeights never null, array of length {@link #getHardLevelsSize()}, does not contain any nulls * @param softWeights never null, array of length {@link #getSoftLevelsSize()}, does not contain any nulls */ public void addMultiConstraintMatch(RuleContext kcontext, BigDecimal[] hardWeights, BigDecimal[] softWeights) { if (hardScores.length != hardWeights.length) { throw new IllegalArgumentException("The hardScores length (" + hardScores.length + ") is different than the hardWeights length (" + hardWeights.length + ")."); } for (int i = 0; i < hardScores.length; i++) { hardScores[i] = hardScores[i].add(hardWeights[i]); } if (softScores.length != softWeights.length) { throw new IllegalArgumentException("The softScores length (" + softScores.length + ") is different than the softWeights length (" + softWeights.length + ")."); } for (int i = 0; i < softScores.length; i++) { softScores[i] = softScores[i].add(softWeights[i]); } registerConstraintMatch(kcontext, () -> { for (int i = 0; i < hardScores.length; i++) { hardScores[i] = hardScores[i].subtract(hardWeights[i]); } for (int i = 0; i < softScores.length; i++) { softScores[i] = softScores[i].subtract(softWeights[i]); } }, () -> BendableBigDecimalScore.valueOf(hardWeights, softWeights)); } @Override public Score extractScore(int initScore) { return new BendableBigDecimalScore(initScore, Arrays.copyOf(hardScores, hardScores.length), Arrays.copyOf(softScores, softScores.length)); } }