Changeset 4 for bidspace/src/main


Ignore:
Timestamp:
09/18/19 10:00:22 (5 years ago)
Author:
bart
Message:

Faster example parties

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  
    33import java.math.BigDecimal;
    44import java.math.BigInteger;
    5 import java.util.ArrayList;
    6 import java.util.LinkedList;
     5import java.util.Collections;
     6import java.util.HashMap;
    77import java.util.List;
     8import java.util.Map;
     9import java.util.stream.Collectors;
    810
    911import geniusweb.issuevalue.Bid;
     12import geniusweb.issuevalue.Domain;
     13import geniusweb.issuevalue.Value;
    1014import geniusweb.profile.utilityspace.LinearAdditiveUtilitySpace;
    1115import tudelft.utilities.immutablelist.AbstractImmutableList;
     16import tudelft.utilities.immutablelist.FixedList;
     17import tudelft.utilities.immutablelist.ImmutableList;
     18import tudelft.utilities.immutablelist.JoinedList;
     19import tudelft.utilities.immutablelist.MapList;
     20import tudelft.utilities.immutablelist.Tuple;
    1221
    1322/**
    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.
    1527 */
    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;
     28public 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 */
     202class 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));
    48216        }
    49217
    50218        @Override
    51219        public Bid get(BigInteger index) {
    52                 return collectedbids.get(index.intValue());
     220                return new Bid(info.getName(),
     221                                info.subset(interval).get(index.intValue()));
    53222        }
    54223
    55224        @Override
    56225        public BigInteger size() {
    57                 return BigInteger.valueOf(collectedbids.size());
     226                return size;
    58227        }
    59228
Note: See TracChangeset for help on using the changeset viewer.