[74] | 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 = range.getMin()
|
---|
| 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 | )
|
---|