source: geniuswebcore/test/geniusweb/profile/utilityspace/LinearAdditiveTest.py@ 94

Last change on this file since 94 was 90, checked in by Bart Vastenhouw, 3 years ago

Refactor to help reusing partiesserver.

File size: 9.9 KB
Line 
1from collections import OrderedDict
2from decimal import Decimal
3import json
4from pathlib import Path
5from typing import List, Dict
6import unittest
7from unittest.mock import Mock
8
9from pyson.ObjectMapper import ObjectMapper
10from unitpy.GeneralTests import GeneralTests
11
12from geniusweb.issuevalue.Bid import Bid
13from geniusweb.issuevalue.DiscreteValue import DiscreteValue
14from geniusweb.issuevalue.DiscreteValueSet import DiscreteValueSet
15from geniusweb.issuevalue.Domain import Domain
16from geniusweb.issuevalue.NumberValue import NumberValue
17from geniusweb.issuevalue.Value import Value
18from geniusweb.issuevalue.ValueSet import ValueSet
19from geniusweb.profile.Profile import Profile
20from geniusweb.profile.utilityspace.DiscreteValueSetUtilities import DiscreteValueSetUtilities
21from geniusweb.profile.utilityspace.LinearAdditiveUtilitySpace import LinearAdditiveUtilitySpace
22from geniusweb.profile.utilityspace.UtilitySpace import UtilitySpace
23from geniusweb.profile.utilityspace.ValueSetUtilities import ValueSetUtilities
24
25
26class LinearAdditiveTest(unittest.TestCase, GeneralTests[LinearAdditiveUtilitySpace]):
27 NAME = "test"
28 I1V1UTIL = Decimal("0.3")
29 I1V2UTIL = Decimal("0.2")
30 I2V1UTIL = Decimal("0.6")
31 I2V2UTIL = Decimal("0.8")
32 WEIGHT1 = Decimal("0.4")
33 WEIGHT2 = Decimal("0.6")
34 ISS1 = "issue1"
35 ISS2 = "issue2"
36 ISS3 = "issue3"
37 i1v1 = DiscreteValue("issue1value1")
38 i1v2 = DiscreteValue("issue1value2")
39 i2v1 = DiscreteValue("issue2value1")
40 i2v2 = DiscreteValue("issue2value2")
41 i3v1 = DiscreteValue("issue3value1")
42 i3v2 = DiscreteValue("issue3value2")
43
44 pyson = ObjectMapper()
45
46 WEIGHT1a = Decimal("0.3")
47 WEIGHT2a = Decimal("0.7")
48
49 values:Dict[str, ValueSet] = OrderedDict()
50 values[ISS1]=DiscreteValueSet([i1v1, i1v2])
51 smalldomain = Domain(NAME, values)
52 values[ISS2]= DiscreteValueSet([i2v1, i2v2])
53 domain = Domain(NAME, values)
54
55 # build utilspace for string and equals testing.
56 utils:Dict[str, ValueSetUtilities] = OrderedDict()
57 valueUtils = OrderedDict()
58 valueUtils[i2v2]= I2V2UTIL
59 valueUtils[i2v1]= I2V1UTIL
60 value2Utils = DiscreteValueSetUtilities(valueUtils)
61 utils[ISS2]= value2Utils
62 valueUtils = OrderedDict()
63 valueUtils[i1v1]= I1V1UTIL
64 valueUtils[i1v2]= I1V2UTIL
65 value1Utils = DiscreteValueSetUtilities(valueUtils)
66 utils[ISS1]= value1Utils
67
68 # build utilspaceb, mix up the utilities a bit.
69 utilsb:Dict[str, ValueSetUtilities] = OrderedDict()
70 valueUtils = OrderedDict()
71 valueUtils[i2v2] =I1V2UTIL
72 valueUtils[i2v1]= I1V1UTIL
73 value2UtilsB = DiscreteValueSetUtilities(valueUtils)
74 utilsb[ISS2]= value2UtilsB
75 valueUtils = OrderedDict()
76 valueUtils[i1v1]= I2V1UTIL
77 valueUtils[i1v2]= I2V2UTIL
78 value1UtilsB = DiscreteValueSetUtilities(valueUtils)
79 utilsb[ISS1] =value1UtilsB
80
81 # weight map
82 weights = OrderedDict()
83 weights[ISS2]= WEIGHT2
84 weights[ISS1]= WEIGHT1
85
86 # weight map 2
87 weightsb = OrderedDict()
88 weightsb[ISS2]= WEIGHT2a
89 weightsb[ISS1]= WEIGHT1a
90
91 # bid with lowest utility
92 issuevalues:Dict[str, Value] = OrderedDict()
93 issuevalues[ISS2]= i2v1
94 issuevalues[ISS1]=i1v2
95 reservationBid = Bid(issuevalues)
96
97 issuevalues = OrderedDict()
98 issuevalues[ISS2]= i2v1
99 issuevalues[ISS1]= i1v1
100 reservationBid2 = Bid(issuevalues)
101
102 # make the utilspaces
103 utilspace1 = LinearAdditiveUtilitySpace(domain, NAME, utils,
104 weights, reservationBid)
105 utilspace1a = LinearAdditiveUtilitySpace(domain, NAME, utils,
106 weights, reservationBid);
107
108 utilspace2a = LinearAdditiveUtilitySpace(domain, NAME, utils,
109 weightsb, reservationBid);
110 utilspace2b = LinearAdditiveUtilitySpace(domain, NAME, utilsb,
111 weights, reservationBid);
112 utilspace3 = LinearAdditiveUtilitySpace(domain, NAME, utilsb,
113 weights, reservationBid2);
114
115
116 #Override
117 def getGeneralTestData(self)->List[List[LinearAdditiveUtilitySpace]] :
118 return [ [self.utilspace1, self.utilspace1a], [self.utilspace2a],
119 [self.utilspace2b], [self.utilspace3]]
120
121 #Override
122 def getGeneralTestStrings(self)-> List[str] :
123 return [
124 "LinearAdditive\\[\\{issue2=DiscreteValueSetUtilities\\{\"issue2value2\"=0.8, \"issue2value1\"=0.6\\}, issue1=DiscreteValueSetUtilities\\{\"issue1value1\"=0.3, \"issue1value2\"=0.2\\}\\},\\{issue2=0.6, issue1=0.4\\},Bid\\{issue2=\"issue2value1\", issue1=\"issue1value2\"\\}\\]",
125 "LinearAdditive\\[\\{issue2=DiscreteValueSetUtilities\\{\"issue2value2\"=0.8, \"issue2value1\"=0.6\\}, issue1=DiscreteValueSetUtilities\\{\"issue1value1\"=0.3, \"issue1value2\"=0.2\\}\\},\\{issue2=0.7, issue1=0.3\\},Bid\\{issue2=\"issue2value1\", issue1=\"issue1value2\"\\}\\]",
126 "LinearAdditive\\[\\{issue2=DiscreteValueSetUtilities\\{\"issue2value2\"=0.2, \"issue2value1\"=0.3\\}, issue1=DiscreteValueSetUtilities\\{\"issue1value1\"=0.6, \"issue1value2\"=0.8\\}\\},\\{issue2=0.6, issue1=0.4\\},Bid\\{issue2=\"issue2value1\", issue1=\"issue1value2\"\\}\\]",
127 "LinearAdditive\\[\\{issue2=DiscreteValueSetUtilities\\{\"issue2value2\"=0.2, \"issue2value1\"=0.3\\}, issue1=DiscreteValueSetUtilities\\{\"issue1value1\"=0.6, \"issue1value2\"=0.8\\}\\},\\{issue2=0.6, issue1=0.4\\},Bid\\{issue2=\"issue2value1\", issue1=\"issue1value1\"\\}\\]"
128 ]
129
130
131 def testConstructorNullIssues(self):
132 self.assertRaises(ValueError, lambda:LinearAdditiveUtilitySpace(self.domain, self.NAME, None, None,self.reservationBid))
133
134 def testConstructorNullDomain(self):
135 self.assertRaises(ValueError, lambda:LinearAdditiveUtilitySpace(None, self.NAME, self.utils, self.weights,
136 self.reservationBid))
137
138 # Empty profile is not allowed since the weights then don't sum up to 1
139 def testConstructorEmpty(self):
140 self.assertRaises(ValueError, lambda:LinearAdditiveUtilitySpace(self.domain, self.NAME, {}, self.weights,
141 self.reservationBid))
142
143 def testConstructorOneIssue(self):
144 utilset = {}
145 weightset = {}
146 utilset[self.ISS1]= self.value1Utils
147 weightset[self.ISS1]=Decimal(1)
148 LinearAdditiveUtilitySpace(self.smalldomain, self.NAME, utilset, weightset,
149 None)
150
151 # Empty profile is not allowed since the weights then don't sum up to 1
152 def testConstructoroneIssueWrongWeight(self):
153 utilset = {}
154 weightset = {}
155 utilset[self.ISS1]= self.value1Utils
156 weightset[self.ISS1]=self.WEIGHT1
157 self.assertRaises(ValueError, lambda:LinearAdditiveUtilitySpace(self.smalldomain, self.NAME, utilset, weightset,
158 self.reservationBid))
159
160 # Try creating a domain and check isFitting
161 #@Test
162 def testCheckCoversDomain(self):
163 utilset = {}
164 weightset = {}
165
166 utilset[self.ISS1]=self.value1Utils
167 weightset[self.ISS1]=Decimal(1)
168 space = LinearAdditiveUtilitySpace(
169 self.smalldomain, self.NAME, utilset, weightset, None)
170
171
172 # Try creating a domain and check isFitting but there is more issues in our
173 # map than in the actual domain
174 def testCheckCoversWrongDomain(self):
175 utilset = {}
176 weightset = {}
177
178 utilset[self.ISS1]=self.value1Utils
179 weightset[self.ISS1]= Decimal(1)
180 self.assertRaises(ValueError, lambda:LinearAdditiveUtilitySpace(
181 self.domain, self.NAME, utilset, weightset, self.reservationBid))
182
183 # Empty profile is not allowed since the weights then don't sum up to 1
184 def testUtility(self):
185 space = LinearAdditiveUtilitySpace(
186 self.domain, self.NAME, self.utils, self.weights, self.reservationBid)
187
188 bid = Mock()
189 issues = [self.ISS1]
190 bid.getIssues = Mock(return_value = issues)
191 bid.getValue = Mock(return_value = self.i1v1)
192 self.assertEqual(self.WEIGHT1 * self.I1V1UTIL, space.getUtility(bid))
193
194 def testPreferred(self) :
195 issuevalues = {}
196 issuevalues[self.ISS1]=self.i1v1
197 issuevalues[self.ISS2]=self.i2v2
198 bid1 = Bid(issuevalues)
199 issuevalues1 = {}
200 issuevalues1[self.ISS1]= self.i1v2
201 issuevalues1[self.ISS2]= self.i2v1
202 bid2 = Bid(issuevalues1)
203 self.assertTrue(self.utilspace1.isPreferredOrEqual(bid1, bid2))
204 self.assertTrue(self.utilspace1.isPreferredOrEqual(bid1, bid1))
205 self.assertTrue(self.utilspace1.isPreferredOrEqual(bid2, bid2))
206 self.assertFalse(self.utilspace1.isPreferredOrEqual(bid2, bid1))
207 self.assertFalse(self.utilspace1.isPreferredOrEqual(Bid({}), bid1))
208
209 def testPartialBidUtilityTest(self):
210 space = LinearAdditiveUtilitySpace(
211 self.domain, self.NAME, self.utils, self.weights, self.reservationBid)
212 issuevalues = {}
213 issuevalues[self.ISS1]= self.i1v1
214 bid = Bid(issuevalues)
215 self.assertEqual(self.WEIGHT1* self.I1V1UTIL, space.getUtility(bid))
216
217 def testLoadFullWithJson(self) :
218 serialized = Path("test/resources/party1.json").read_text("utf-8")
219 jsonobj=json.loads(serialized)
220 space = self.pyson.parse(jsonobj, Profile)
221
222 def testLoadFullWithJsonNumber(self) :
223 serialized = Path("test/resources/japantrip1.json").read_text("utf-8")
224 jsonobj=json.loads(serialized)
225 profile:Profile = self.pyson.parse(jsonobj, Profile)
226
227
228 def testResBidWithNonsenseIssue(self) :
229 resBid = Bid({"nonsense": self.i1v1})
230 self.assertRaises(ValueError,
231 lambda:LinearAdditiveUtilitySpace(self.domain, self.NAME, self.utils, self.weights, resBid))
232
233 def testResBidWithWrongValueType(self):
234 resBid = Bid({self.ISS1: NumberValue(Decimal(0))})
235 self.assertRaises(ValueError, lambda:LinearAdditiveUtilitySpace(self.domain, self.NAME, self.utils, self.weights, resBid))
236
237 def testResBidWithNonsenseValue(self):
238 resBid = Bid({self.ISS1: DiscreteValue("nonsense")})
239 self.assertRaises(ValueError, lambda:LinearAdditiveUtilitySpace(self.domain, self.NAME, self.utils, self.weights, resBid))
240
Note: See TracBrowser for help on using the repository browser.