/* * Copyright 2012 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.benchmark.impl.measurement; import java.io.Serializable; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; import org.apache.commons.lang3.LocaleUtils; import org.optaplanner.core.api.score.Score; import org.optaplanner.core.impl.score.ScoreUtils; public class ScoreDifferencePercentage implements Serializable { public static <Score_ extends Score<Score_>> ScoreDifferencePercentage calculateScoreDifferencePercentage( Score_ baseScore, Score_ valueScore) { double[] baseLevels = ScoreUtils.extractLevelDoubles(baseScore); double[] valueLevels = ScoreUtils.extractLevelDoubles(valueScore); if (baseLevels.length != valueLevels.length) { throw new IllegalStateException("The baseScore (" + baseScore + ")'s levelsLength (" + baseLevels.length + ") is different from the valueScore (" + valueScore + ")'s levelsLength (" + valueLevels.length + ")."); } double[] percentageLevels = new double[baseLevels.length]; for (int i = 0; i < baseLevels.length; i++) { percentageLevels[i] = calculateDifferencePercentage(baseLevels[i], valueLevels[i]); } return new ScoreDifferencePercentage(percentageLevels); } public static double calculateDifferencePercentage(double base, double value) { double difference = value - base; if (base < 0.0) { return difference / - base; } else if (base == 0.0) { if (difference == 0.0) { return 0.0; } else { // percentageLevel will return Infinity or -Infinity return difference / base; } } else { return difference / base; } } private final double[] percentageLevels; public ScoreDifferencePercentage(double[] percentageLevels) { this.percentageLevels = percentageLevels; } public double[] getPercentageLevels() { return percentageLevels; } // ************************************************************************ // Worker methods // ************************************************************************ public ScoreDifferencePercentage add(ScoreDifferencePercentage augment) { if (percentageLevels.length != augment.getPercentageLevels().length) { throw new IllegalStateException("The augment (" + augment + ")'s levelsLength (" + augment.getPercentageLevels().length + ") is different from the base (" + this + ")'s levelsLength (" + percentageLevels.length + ")."); } double[] newPercentageLevels = new double[percentageLevels.length]; for (int i = 0; i < percentageLevels.length; i++) { newPercentageLevels[i] = percentageLevels[i] + augment.percentageLevels[i]; } return new ScoreDifferencePercentage(newPercentageLevels); } public ScoreDifferencePercentage subtract(ScoreDifferencePercentage subtrahend) { if (percentageLevels.length != subtrahend.getPercentageLevels().length) { throw new IllegalStateException("The subtrahend (" + subtrahend + ")'s levelsLength (" + subtrahend.getPercentageLevels().length + ") is different from the base (" + this + ")'s levelsLength (" + percentageLevels.length + ")."); } double[] newPercentageLevels = new double[percentageLevels.length]; for (int i = 0; i < percentageLevels.length; i++) { newPercentageLevels[i] = percentageLevels[i] - subtrahend.percentageLevels[i]; } return new ScoreDifferencePercentage(newPercentageLevels); } public ScoreDifferencePercentage multiply(double multiplicand) { double[] newPercentageLevels = new double[percentageLevels.length]; for (int i = 0; i < percentageLevels.length; i++) { newPercentageLevels[i] = percentageLevels[i] * multiplicand; } return new ScoreDifferencePercentage(newPercentageLevels); } public ScoreDifferencePercentage divide(double divisor) { double[] newPercentageLevels = new double[percentageLevels.length]; for (int i = 0; i < percentageLevels.length; i++) { newPercentageLevels[i] = percentageLevels[i] / divisor; } return new ScoreDifferencePercentage(newPercentageLevels); } @Override public String toString() { return toString(Locale.US); } public String toString(String locale) { return toString(LocaleUtils.toLocale(locale)); } public String toString(Locale locale) { StringBuilder s = new StringBuilder(percentageLevels.length * 8); DecimalFormat decimalFormat = new DecimalFormat("0.00%", DecimalFormatSymbols.getInstance(locale)); for (int i = 0; i < percentageLevels.length; i++) { if (i > 0) { s.append("/"); } s.append(decimalFormat.format(percentageLevels[i])); } return s.toString(); } }