Package org.optaplanner.core.api.score.buildin.bendablebigdecimal

Source Code of org.optaplanner.core.api.score.buildin.bendablebigdecimal.BendableBigDecimalScore

/*
* Copyright 2013 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.optaplanner.core.api.score.buildin.bendablebigdecimal;

import java.math.BigDecimal;
import java.math.RoundingMode;

import org.optaplanner.core.api.score.AbstractScore;
import org.optaplanner.core.api.score.FeasibilityScore;
import org.optaplanner.core.api.score.Score;
import org.optaplanner.core.impl.score.buildin.bendable.BendableScoreDefinition;

/**
* This {@link Score} is based on n levels of {@link BigDecimal} constraints.
* The number of levels is bendable at configuration time.
* <p/>
* This class is immutable.
* <p/>
* The {@link #getHardLevelsSize()} and {@link #getSoftLevelsSize()} must be the same as in the
* {@link BendableScoreDefinition} used.
* @see Score
*/
public final class BendableBigDecimalScore extends AbstractScore<BendableBigDecimalScore>
        implements FeasibilityScore<BendableBigDecimalScore> {

    public static BendableBigDecimalScore parseScore(int hardLevelsSize, int softLevelsSize, String scoreString) {
        int levelsSize = hardLevelsSize + softLevelsSize;
        String[] levelStrings = parseLevelStrings(BendableBigDecimalScore.class, scoreString, levelsSize);
        BigDecimal[] hardScores = new BigDecimal[hardLevelsSize];
        BigDecimal[] softScores = new BigDecimal[softLevelsSize];
        for (int i = 0; i < hardScores.length; i++) {
            hardScores[i] = parseLevelAsBigDecimal(BendableBigDecimalScore.class, scoreString, levelStrings[i]);
        }
        for (int i = 0; i < softScores.length; i++) {
            softScores[i] = parseLevelAsBigDecimal(BendableBigDecimalScore.class, scoreString, levelStrings[hardScores.length + i]);
        }
        return valueOf(hardScores, softScores);
    }

    /**
     * Creates a new {@link BendableBigDecimalScore}.
     * @param hardScores never null, never change that array afterwards: it must be immutable
     * @param softScores never null, never change that array afterwards: it must be immutable
     * @return never null
     */
    public static BendableBigDecimalScore valueOf(BigDecimal[] hardScores, BigDecimal[] softScores) {
        return new BendableBigDecimalScore(hardScores, softScores);
    }

    // ************************************************************************
    // Fields
    // ************************************************************************

    private final BigDecimal[] hardScores;
    private final BigDecimal[] softScores;

    protected BendableBigDecimalScore(BigDecimal[] hardScores, BigDecimal[] softScores) {
        this.hardScores = hardScores;
        this.softScores = softScores;
    }

    // Intentionally no getters for the hardScores or softScores int arrays to guarantee that this class is immutable

    public int getHardLevelsSize() {
        return hardScores.length;
    }

    /**
     * @param index 0 <= index < {@link #getHardLevelsSize()}
     * @return higher is better
     */
    public BigDecimal getHardScore(int index) {
        return hardScores[index];
    }

    public int getSoftLevelsSize() {
        return softScores.length;
    }

    /**
     * @param index 0 <= index < {@link #getSoftLevelsSize()}
     * @return higher is better
     */
    public BigDecimal getSoftScore(int index) {
        return softScores[index];
    }

    // ************************************************************************
    // Worker methods
    // ************************************************************************

    public boolean isFeasible() {
        for (BigDecimal hardScore : hardScores) {
            int comparison = hardScore.compareTo(BigDecimal.ZERO);
            if (comparison > 0) {
                return true;
            } else if (comparison < 0) {
                return false;
            }
        }
        return true;
    }

    public BendableBigDecimalScore add(BendableBigDecimalScore augment) {
        validateCompatible(augment);
        BigDecimal[] newHardScores = new BigDecimal[hardScores.length];
        BigDecimal[] newSoftScores = new BigDecimal[softScores.length];
        for (int i = 0; i < newHardScores.length; i++) {
            newHardScores[i] = hardScores[i].add(augment.getHardScore(i));
        }
        for (int i = 0; i < newSoftScores.length; i++) {
            newSoftScores[i] = softScores[i].add(augment.getSoftScore(i));
        }
        return new BendableBigDecimalScore(newHardScores, newSoftScores);
    }

    public BendableBigDecimalScore subtract(BendableBigDecimalScore subtrahend) {
        validateCompatible(subtrahend);
        BigDecimal[] newHardScores = new BigDecimal[hardScores.length];
        BigDecimal[] newSoftScores = new BigDecimal[softScores.length];
        for (int i = 0; i < newHardScores.length; i++) {
            newHardScores[i] = hardScores[i].subtract(subtrahend.getHardScore(i));
        }
        for (int i = 0; i < newSoftScores.length; i++) {
            newSoftScores[i] = softScores[i].subtract(subtrahend.getSoftScore(i));
        }
        return new BendableBigDecimalScore(newHardScores, newSoftScores);
    }

    public BendableBigDecimalScore multiply(double multiplicand) {
        BigDecimal[] newHardScores = new BigDecimal[hardScores.length];
        BigDecimal[] newSoftScores = new BigDecimal[softScores.length];
        BigDecimal bigDecimalMultiplicand = BigDecimal.valueOf(multiplicand);
        for (int i = 0; i < newHardScores.length; i++) {
            newHardScores[i] = hardScores[i].multiply(bigDecimalMultiplicand);
        }
        for (int i = 0; i < newSoftScores.length; i++) {
            newSoftScores[i] = softScores[i].multiply(bigDecimalMultiplicand);
        }
        return new BendableBigDecimalScore(newHardScores, newSoftScores);
    }

    public BendableBigDecimalScore divide(double divisor) {
        BigDecimal[] newHardScores = new BigDecimal[hardScores.length];
        BigDecimal[] newSoftScores = new BigDecimal[softScores.length];
        BigDecimal bigDecimalDivisor = BigDecimal.valueOf(divisor);
        for (int i = 0; i < newHardScores.length; i++) {
            BigDecimal hardScore = hardScores[i];
            newHardScores[i] = hardScore.divide(bigDecimalDivisor, hardScore.scale(), RoundingMode.FLOOR);
        }
        for (int i = 0; i < newSoftScores.length; i++) {
            BigDecimal softScore = softScores[i];
            newSoftScores[i] = softScore.divide(bigDecimalDivisor, softScore.scale(), RoundingMode.FLOOR);
        }
        return new BendableBigDecimalScore(newHardScores, newSoftScores);
    }

    public BendableBigDecimalScore power(double exponent) {
        BigDecimal[] newHardScores = new BigDecimal[hardScores.length];
        BigDecimal[] newSoftScores = new BigDecimal[softScores.length];
        BigDecimal actualExponent = BigDecimal.valueOf(exponent);
        // The (unspecified) scale/precision of the exponent should have no impact on the returned scale/precision
        // TODO FIXME remove .intValue() so non-integer exponents produce correct results
        // None of the normal Java libraries support BigDecimal.pow(BigDecimal)
        for (int i = 0; i < newHardScores.length; i++) {
            BigDecimal hardScore = hardScores[i];
            newHardScores[i] = hardScore.pow(actualExponent.intValue()).setScale(hardScore.scale());
        }
        for (int i = 0; i < newSoftScores.length; i++) {
            BigDecimal softScore = softScores[i];
            newSoftScores[i] = softScore.pow(actualExponent.intValue()).setScale(softScore.scale());
        }
        return new BendableBigDecimalScore(newHardScores, newSoftScores);
    }

    public BendableBigDecimalScore negate() {
        BigDecimal[] newHardScores = new BigDecimal[hardScores.length];
        BigDecimal[] newSoftScores = new BigDecimal[softScores.length];
        for (int i = 0; i < newHardScores.length; i++) {
            newHardScores[i] = hardScores[i].negate();
        }
        for (int i = 0; i < newSoftScores.length; i++) {
            newSoftScores[i] = softScores[i].negate();
        }
        return new BendableBigDecimalScore(newHardScores, newSoftScores);
    }

    public Number[] toLevelNumbers() {
        Number[] levelNumbers = new Number[hardScores.length + softScores.length];
        for (int i = 0; i < hardScores.length; i++) {
            levelNumbers[i] = hardScores[i];
        }
        for (int i = 0; i < softScores.length; i++) {
            levelNumbers[hardScores.length + i] = softScores[i];
        }
        return levelNumbers;
    }

    public boolean equals(Object o) {
        // A direct implementation (instead of EqualsBuilder) to avoid dependencies
        if (this == o) {
            return true;
        } else if (o instanceof BendableBigDecimalScore) {
            BendableBigDecimalScore other = (BendableBigDecimalScore) o;
            if (getHardLevelsSize() != other.getHardLevelsSize()
                    || getSoftLevelsSize() != other.getSoftLevelsSize()) {
                return false;
            }
            for (int i = 0; i < hardScores.length; i++) {
                if (!hardScores[i].equals(other.getHardScore(i))) {
                    return false;
                }
            }
            for (int i = 0; i < softScores.length; i++) {
                if (!softScores[i].equals(other.getSoftScore(i))) {
                    return false;
                }
            }
            return true;
        } else {
            return false;
        }
    }

    public int hashCode() {
        // A direct implementation (instead of HashCodeBuilder) to avoid dependencies
        int hashCode = 17;
        for (BigDecimal hardScore : hardScores) {
            hashCode = hashCode * 37 + hardScore.hashCode();
        }
        for (BigDecimal softScore : softScores) {
            hashCode = hashCode * 37 + softScore.hashCode();
        }
        return hashCode;
    }

    public int compareTo(BendableBigDecimalScore other) {
        // A direct implementation (instead of CompareToBuilder) to avoid dependencies
        validateCompatible(other);
        for (int i = 0; i < hardScores.length; i++) {
            if (!hardScores[i].equals(other.getHardScore(i))) {
                if (hardScores[i].compareTo(other.getHardScore(i)) < 0) {
                    return -1;
                } else {
                    return 1;
                }
            }
        }
        for (int i = 0; i < softScores.length; i++) {
            if (!softScores[i].equals(other.getSoftScore(i))) {
                if (softScores[i].compareTo(other.getSoftScore(i)) < 0) {
                    return -1;
                } else {
                    return 1;
                }
            }
        }
        return 0;
    }

    public String toString() {
        StringBuilder s = new StringBuilder(((hardScores.length + softScores.length) * 4) + 1);
        boolean first = true;
        for (BigDecimal hardScore : hardScores) {
            if (first) {
                first = false;
            } else {
                s.append("/");
            }
            s.append(hardScore);
        }
        for (BigDecimal softScore : softScores) {
            if (first) {
                first = false;
            } else {
                s.append("/");
            }
            s.append(softScore);
        }
        return s.toString();
    }

    public void validateCompatible(BendableBigDecimalScore other) {
        if (getHardLevelsSize() != other.getHardLevelsSize()) {
            throw new IllegalArgumentException("The score (" + this
                    + ") with hardScoreSize (" + getHardLevelsSize()
                    + ") is not compatible with the other score (" + other
                    + ") with hardScoreSize (" + other.getHardLevelsSize() + ").");
        }
        if (getSoftLevelsSize() != other.getSoftLevelsSize()) {
            throw new IllegalArgumentException("The score (" + this
                    + ") with softScoreSize (" + getSoftLevelsSize()
                    + ") is not compatible with the other score (" + other
                    + ") with softScoreSize (" + other.getSoftLevelsSize() + ").");
        }
    }

    @Override
    public boolean isCompatibleArithmeticArgument(Score otherScore) {
        if (!(otherScore instanceof BendableBigDecimalScore)) {
            return false;
        }
        BendableBigDecimalScore otherBendableScore = (BendableBigDecimalScore) otherScore;
        return hardScores.length == otherBendableScore.hardScores.length
                && softScores.length == otherBendableScore.softScores.length;
    }

}
TOP

Related Classes of org.optaplanner.core.api.score.buildin.bendablebigdecimal.BendableBigDecimalScore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.