Changeset 4 for bidspace/src/main/java
- Timestamp:
- 09/18/19 10:00:22 (5 years ago)
- Location:
- bidspace/src/main/java/geniusweb/bidspace
- Files:
-
- 2 added
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
bidspace/src/main/java/geniusweb/bidspace/BidsWithUtility.java
r2 r4 3 3 import java.math.BigDecimal; 4 4 import java.math.BigInteger; 5 import java.util. ArrayList;6 import java.util. LinkedList;5 import java.util.Collections; 6 import java.util.HashMap; 7 7 import java.util.List; 8 import java.util.Map; 9 import java.util.stream.Collectors; 8 10 9 11 import geniusweb.issuevalue.Bid; 12 import geniusweb.issuevalue.Domain; 13 import geniusweb.issuevalue.Value; 10 14 import geniusweb.profile.utilityspace.LinearAdditiveUtilitySpace; 11 15 import tudelft.utilities.immutablelist.AbstractImmutableList; 16 import tudelft.utilities.immutablelist.FixedList; 17 import tudelft.utilities.immutablelist.ImmutableList; 18 import tudelft.utilities.immutablelist.JoinedList; 19 import tudelft.utilities.immutablelist.MapList; 20 import tudelft.utilities.immutablelist.Tuple; 12 21 13 22 /** 14 * Object containing a subset of all bids, that have utility within given range. 23 * Tool class containing functions dealing with utilities of all bids in a given 24 * {@link LinearAdditiveUtilitySpace}. This class caches previously computed 25 * values to accelerate the calls and subsequent calls. Re-use the object to 26 * keep/reuse the cache. 15 27 */ 16 public class BidsWithUtility extends AbstractImmutableList<Bid> { 17 18 private final List<Bid> collectedbids; 19 20 /** 21 * Create Bids with utility within given bounds. 22 * 23 * @param space the {@link LinearAdditiveUtilitySpace} to search 24 * @param min the minimum required utility 25 * @param max the maximum required utility 26 */ 27 public BidsWithUtility(LinearAdditiveUtilitySpace space, BigDecimal min, BigDecimal max) { 28 this.collectedbids = new ArrayList<Bid>(getBids(space, min, max)); 29 } 30 31 /** 32 * Brute force hack for this time. Maybe we can construct this in a lazy way. 33 * 34 * @param space 35 * @param min 36 * @param max 37 * @return 38 */ 39 private List<Bid> getBids(LinearAdditiveUtilitySpace space, BigDecimal min, BigDecimal max) { 40 List<Bid> goodbids = new LinkedList<Bid>(); 41 for (Bid bid : new AllBidsList(space.getDomain())) { 42 BigDecimal util = space.getUtility(bid); 43 if (util.compareTo(min) >= 0 && util.compareTo(max) <= 0) { 44 goodbids.add(bid); 45 } 46 } 47 return goodbids; 28 public class BidsWithUtility { 29 30 private final List<IssueInfo> issueInfo; 31 private final int precision; // #digits used for Intervals 32 33 /** 34 * cache. Key = call arguments for {@link #get(int, Interval)}. Value=return 35 * value of that call. 36 */ 37 private final Map<Tuple<Integer, Interval>, ImmutableList<Bid>> cache = new HashMap<>(); 38 39 /** 40 * Default constructor, uses default precision 6. This value seems practical 41 * for the common range of issues, utilities and weights. See 42 * {@link #BidsWithUtil(LinearAdditiveUtilitySpace, int)} for more details 43 * on the precision. 44 * 45 * @param space the {@link LinearAdditiveUtilitySpace} to analyze 46 */ 47 public BidsWithUtility(LinearAdditiveUtilitySpace space) { 48 this(space, 6); 49 } 50 51 /** 52 * 53 * @param space the {@link LinearAdditiveUtilitySpace} to analyze 54 * @param precision the number of digits to use for computations. This value 55 * should match the max number of (digits used in the 56 * weight of an issue + number of digits used in the issue 57 * utility). Usually you also look at the step size, and 58 * the range of interest. For instance if your utility 59 * function has values 1/3 and 2/3, then these have an 60 * 'infinite' number of relevant digits. But if we want to 61 * search bids between utility 0.1 and 0.2, then computing 62 * in 2 digits might already be sufficient. This algorithm 63 * has memory and space complexity O( |nissues| 64 * 10^precision ). For spaces up to 7 issues, 7 digits 65 * should be feasible; for 9 issues, 6 digits may be the 66 * maximum. 67 */ 68 public BidsWithUtility(LinearAdditiveUtilitySpace space, int precision) { 69 this(getInfo(space, precision), precision); 70 } 71 72 /** 73 * 74 * @param issuesInfo List of the relevant issues (in order of relevance) and 75 * all info of each issue. 76 * @param precision the number of digits used in Intervals. 77 */ 78 public BidsWithUtility(List<IssueInfo> issuesInfo, int precision) { 79 if (issuesInfo == null || issuesInfo.isEmpty()) { 80 throw new IllegalArgumentException( 81 "sortedissues list must contain at least 1 element"); 82 } 83 84 this.issueInfo = issuesInfo; 85 this.precision = precision; 86 87 } 88 89 /** 90 * @return the utility {@link Interval} of this space: minimum and maximum 91 * achievable utility. 92 */ 93 public Interval getRange() { 94 return getRange(issueInfo.size() - 1); 95 } 96 97 /** 98 * 99 * @param range the minimum and maximum utility required of the bids. to be 100 * included (both ends inclusive). 101 * @return a list with bids that have utility inside range. possibly empty. 102 * With decreasing precision, more bids may drop out due to rounding 103 * errors. 104 */ 105 public ImmutableList<Bid> getBids(Interval range) { 106 return get(issueInfo.size() - 1, range.round(precision)); 107 } 108 109 public List<IssueInfo> getInfo() { 110 return Collections.unmodifiableList(issueInfo); 111 } 112 113 /** 114 * Create partial BidsWithUtil list considering only issues 0..n, with 115 * utilities in given range. 116 * 117 * @param n the number of {@link #issueRanges} to consider, we consider 118 * 0..n here. The recursion decreases n until n=0 119 * @param goal the minimum and maximum utility required of the bids. to be 120 * included (both ends inclusive) 121 * @return BidsWithUtil list, possibly empty. 122 */ 123 protected ImmutableList<Bid> get(int n, Interval goal) { 124 if (goal == null) { 125 throw new NullPointerException("Interval=null"); 126 } 127 128 // clamp goal into what is reachable. Avoid caching empty 129 goal = goal.intersect(getRange(n)); 130 if (goal.isEmpty()) { 131 return new FixedList<>(); 132 } 133 134 Tuple<Integer, Interval> cachetuple = new Tuple<>(n, goal); 135 ImmutableList<Bid> cached = cache.get(cachetuple); 136 if (cached != null) { 137 // hits++; 138 return cached; 139 } 140 141 ImmutableList<Bid> result = checkedGet(n, goal); 142 cache.put(cachetuple, result); 143 return result; 144 } 145 146 private static List<IssueInfo> getInfo(LinearAdditiveUtilitySpace space2, 147 int precision) { 148 Domain dom = space2.getDomain(); 149 return space2.getDomain().getIssues().stream() 150 .map(issue -> new IssueInfo(issue, dom.getValues(issue), 151 space2.getUtilities().get(issue), 152 space2.getWeight(issue), precision)) 153 .collect(Collectors.toList()); 154 } 155 156 private ImmutableList<Bid> checkedGet(int n, Interval goal) { 157 IssueInfo info = issueInfo.get(n); 158 // issue is the first issuesWithRange. 159 String issue = issueInfo.get(n).getName(); 160 161 if (n == 0) 162 return new OneIssueSubset(info, goal); 163 164 // make new list, joining all sub-lists 165 ImmutableList<Bid> fulllist = new FixedList<>(); 166 for (Value val : info.getValues()) { 167 BigDecimal weightedutil = info.getWeightedUtil(val); 168 Interval subgoal = goal.subtract(weightedutil); 169 // recurse: get list of bids for the subspace 170 ImmutableList<Bid> partialbids = get(n - 1, subgoal); 171 172 Bid bid = new Bid(issue, val); 173 ImmutableList<Bid> fullbids = new MapList<Bid, Bid>( 174 pbid -> pbid.merge(bid), partialbids); 175 if (!fullbids.size().equals(BigInteger.ZERO)) 176 fulllist = new JoinedList<Bid>(fullbids, fulllist); 177 } 178 return fulllist; 179 } 180 181 /** 182 * @param n the maximum issuevalue utility to include. Use n=index of last 183 * issue s= (#issues in the domain - 1) for the full range of this 184 * domain. 185 * @return Interval (min, max) of the total weighted utility Interval of 186 * issues 0..n. All weighted utilities have been rounded to the set 187 * {@link #precision} 188 */ 189 private Interval getRange(int n) { 190 Interval value = Interval.ZERO; 191 for (int i = 0; i <= n; i++) { 192 value = value.add(issueInfo.get(i).getInterval()); 193 } 194 return value; 195 } 196 197 } 198 199 /** 200 * List of all one-issue bids that have utility inside given interval. 201 */ 202 class OneIssueSubset extends AbstractImmutableList<Bid> { 203 private final IssueInfo info; 204 private final Interval interval; 205 private BigInteger size; 206 207 /** 208 * 209 * @param info the {@link IssueInfo} 210 * @param interval a utility interval (weighted) 211 */ 212 OneIssueSubset(IssueInfo info, Interval interval) { 213 this.info = info; 214 this.interval = interval; 215 this.size = BigInteger.valueOf(info.subsetSize(interval)); 48 216 } 49 217 50 218 @Override 51 219 public Bid get(BigInteger index) { 52 return collectedbids.get(index.intValue()); 220 return new Bid(info.getName(), 221 info.subset(interval).get(index.intValue())); 53 222 } 54 223 55 224 @Override 56 225 public BigInteger size() { 57 return BigInteger.valueOf(collectedbids.size());226 return size; 58 227 } 59 228
Note:
See TracChangeset
for help on using the changeset viewer.