1 | from geniusweb.bidspace.BidsWithUtility import BidsWithUtility
|
---|
2 | from geniusweb.bidspace.Interval import Interval
|
---|
3 | from geniusweb.bidspace.IssueInfo import IssueInfo
|
---|
4 | from geniusweb.issuevalue.Bid import Bid
|
---|
5 | from geniusweb.issuevalue.Value import Value
|
---|
6 | from geniusweb.profile.utilityspace.LinearAdditive import LinearAdditive
|
---|
7 | from tudelft.utilities.immutablelist.ImmutableList import ImmutableList
|
---|
8 | from decimal import Decimal
|
---|
9 | from typing import List
|
---|
10 |
|
---|
11 |
|
---|
12 | class ExtendedUtilSpace:
|
---|
13 | """
|
---|
14 | Inner class for TimeDependentParty, made public for testing purposes. This
|
---|
15 | class may change in the future, use at your own risk.
|
---|
16 | """
|
---|
17 |
|
---|
18 | def __init__(self, space: LinearAdditive):
|
---|
19 | self._utilspace = space
|
---|
20 | self._bidutils = BidsWithUtility.create(self._utilspace)
|
---|
21 | self._computeMinMax()
|
---|
22 | self._tolerance = self._computeTolerance()
|
---|
23 |
|
---|
24 | def _computeMinMax(self):
|
---|
25 | """
|
---|
26 | Computes the fields minutil and maxUtil.
|
---|
27 | <p>
|
---|
28 | TODO this is simplistic, very expensive method and may cause us to run
|
---|
29 | out of time on large domains.
|
---|
30 | <p>
|
---|
31 | Assumes that utilspace and bidutils have been set properly.
|
---|
32 | """
|
---|
33 | range = self._bidutils.getRange()
|
---|
34 | self._minUtil = Decimal("0.7")*range.getMax()
|
---|
35 | self._maxUtil = range.getMax()
|
---|
36 |
|
---|
37 | rvbid = self._utilspace.getReservationBid()
|
---|
38 | if rvbid != None:
|
---|
39 | rv = self._utilspace.getUtility(rvbid)
|
---|
40 | if rv > self._minUtil:
|
---|
41 | self._minUtil = rv
|
---|
42 |
|
---|
43 | def _computeTolerance(self) -> Decimal:
|
---|
44 | """
|
---|
45 | Tolerance is the Interval we need when searching bids. When we are close
|
---|
46 | to the maximum utility, this value has to be the distance between the
|
---|
47 | best and one-but-best utility.
|
---|
48 |
|
---|
49 | @return the minimum tolerance required, which is the minimum difference
|
---|
50 | between the weighted utility of the best and one-but-best issue
|
---|
51 | value.
|
---|
52 | """
|
---|
53 | tolerance = Decimal(1)
|
---|
54 | for iss in self._bidutils.getInfo():
|
---|
55 | if iss.getValues().size() > 1:
|
---|
56 | # we have at least 2 values.
|
---|
57 | values: List[Decimal] = []
|
---|
58 | for val in iss.getValues():
|
---|
59 | values.append(iss.getWeightedUtil(val))
|
---|
60 | values.sort()
|
---|
61 | values.reverse()
|
---|
62 | tolerance = min(tolerance, values[0] - values[1])
|
---|
63 | return tolerance
|
---|
64 |
|
---|
65 | def getMin(self) -> Decimal:
|
---|
66 | return self._minUtil
|
---|
67 |
|
---|
68 | def getMax(self) -> Decimal:
|
---|
69 | return self._maxUtil
|
---|
70 |
|
---|
71 | def getBids(self, utilityGoal: Decimal) -> ImmutableList[Bid]:
|
---|
72 | """
|
---|
73 | @param utilityGoal the requested utility
|
---|
74 | @return bids with utility inside [utilitygoal-{@link #tolerance},
|
---|
75 | utilitygoal]
|
---|
76 | """
|
---|
77 | return self._bidutils.getBids(
|
---|
78 | Interval(utilityGoal - self._tolerance, utilityGoal)
|
---|
79 | )
|
---|