package geniusweb.bidspace;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import geniusweb.issuevalue.Value;
import geniusweb.issuevalue.ValueSet;
import geniusweb.profile.utilityspace.ValueSetUtilities;
/**
* Tool class to collect all relevant info about one issue (from LinearAdditive)
* in one class. Used for internally grouping data for more efficient
* processing. This class may change in the future, not recommended for direct
* use.
*
* immutable
*/
public class IssueInfo {
private final String name;
private final ValueSet values;
private final Interval interval;
private final Map weightedUtils;
/**
*
* @param name the issue name
* @param values the {@link ValueSet} of the issue
* @param utils the {@link ValueSetUtilities} of the issue profile
* @param weight the weight of the {@link ValueSetUtilities}
* @param precision the precision to compute with. Basically the number of
* decimal places used for the computations.
*
*/
public IssueInfo(String name, ValueSet values, ValueSetUtilities utils,
BigDecimal weight, int precision) {
this.name = name;
this.values = values;
this.weightedUtils = computeWeightedUtils(utils, weight, precision);
this.interval = getRange();
}
public ValueSet getValues() {
return values;
}
public String getName() {
return name;
}
/**
*
* @return weighted minimum and maximum utility achievable with this issue,
* rounded to the requested precision.
*/
public Interval getInterval() {
return interval;
}
/**
*
* @param isMax if true the max {@link Value} is returned, else the min is
* returned.
* @return the extreme value, either the minimum if isMax=false or maximum
* if isMax=true
*/
public Value getExtreme(boolean isMax) {
BigDecimal extremeutil = null;
Value extremeval = null;
for (Value val : values) {
BigDecimal util = weightedUtils.get(val);
if (extremeval == null) {
extremeutil = weightedUtils.get(val);
extremeval = val;
} else {
if (isMax) {
if (util.compareTo(extremeutil) > 0) {
extremeutil = util;
extremeval = val;
}
} else {
if (util.compareTo(extremeutil) < 0) {
extremeutil = util;
extremeval = val;
}
}
}
}
return extremeval;
}
/**
* @param val the issue value to be evaluated
* @return weighted utility of given value, rounded to nearest value with
* the requested precision number of digits.
*/
public BigDecimal getWeightedUtil(Value val) {
return weightedUtils.get(val);
}
/**
*
* @param interval an {@link Interval} of utility values.
* @return all values that are inside the interval.
*/
protected List subset(Interval interval) {
List selection = new ArrayList<>();
for (Value value : values) {
if (interval.contains(getWeightedUtil(value)))
selection.add(value);
}
return selection;
}
/**
* Faster way to determine subset size, it does not create a list
*
* @param interval an {@link Interval} of utility values.
* @return size of the subset that you will get from calling subset
*/
protected int subsetSize(Interval interval) {
int n = 0;
for (Value value : values)
if (interval.contains(getWeightedUtil(value)))
n = n + 1;
return n;
}
/**
* @return the {@link Interval} (minimum and maximum) of the utility of the
* weighted utility of this issue, properly rounded to the
* {@link #precision}/
*
*/
private Interval getRange() {
BigDecimal min = BigDecimal.ONE;
BigDecimal max = BigDecimal.ZERO;
for (Value value : values) {
BigDecimal util = getWeightedUtil(value);
if (util.compareTo(min) < 0)
min = util;
if (util.compareTo(max) > 0)
max = util;
}
return new Interval(min, max);
}
private Map computeWeightedUtils(
ValueSetUtilities utilities, BigDecimal w, int prec) {
Map map = new HashMap<>();
for (Value val : values) {
map.put(val, utilities.getUtility(val).multiply(w).setScale(prec,
RoundingMode.HALF_UP));
}
return map;
}
}