source: opponentmodel/src/test/java/geniusweb/opponentmodel/bayesian/BayesianOppModelTest.java@ 52

Last change on this file since 52 was 52, checked in by ruud, 14 months ago

Fixed small issues in domaineditor.

File size: 11.4 KB
Line 
1package geniusweb.opponentmodel.bayesian;
2
3import static org.junit.Assert.assertEquals;
4import static org.junit.Assert.assertNotNull;
5import static org.junit.Assert.assertTrue;
6import static org.mockito.Mockito.mock;
7
8import java.io.IOException;
9import java.math.BigDecimal;
10import java.nio.charset.StandardCharsets;
11import java.nio.file.Files;
12import java.nio.file.Paths;
13import java.util.ArrayList;
14import java.util.Arrays;
15import java.util.Collection;
16import java.util.Collections;
17import java.util.HashMap;
18import java.util.LinkedList;
19import java.util.List;
20import java.util.Map;
21import java.util.Random;
22import java.util.TreeMap;
23import java.util.stream.Collectors;
24
25import org.junit.Ignore;
26import org.junit.Test;
27
28import com.fasterxml.jackson.databind.ObjectMapper;
29
30import geniusweb.actions.Offer;
31import geniusweb.actions.PartyId;
32import geniusweb.issuevalue.Bid;
33import geniusweb.issuevalue.DiscreteValue;
34import geniusweb.issuevalue.DiscreteValueSet;
35import geniusweb.issuevalue.Domain;
36import geniusweb.issuevalue.NumberValue;
37import geniusweb.issuevalue.NumberValueSet;
38import geniusweb.issuevalue.Value;
39import geniusweb.issuevalue.ValueSet;
40import geniusweb.profile.utilityspace.UtilitySpace;
41import geniusweb.progress.Progress;
42import tudelft.utilities.immutablelist.ImmutableList;
43import tudelft.utilities.immutablelist.Outer;
44import tudelft.utilities.junit.GeneralTests;
45
46public class BayesianOppModelTest extends GeneralTests<BayesianOpponentModel> {
47 private final static String ISS1 = "issue1";
48 private final static String ISS2 = "issue2";
49 private static final DiscreteValue I1V1 = new DiscreteValue("i1v1");
50 private static final DiscreteValue I1V2 = new DiscreteValue("i1v2");
51 private static final DiscreteValue I2V1 = new DiscreteValue("i2v1");
52 private static final DiscreteValue I2V2 = new DiscreteValue("i2v2");
53 private static final DiscreteValue I1V2b = new DiscreteValue("i1v2b");
54 private static final Progress progress = mock(Progress.class);
55 private static final PartyId other = new PartyId("other");
56 private static final Random rnd = new Random();
57
58 private static Domain domain, domain2, domain3;
59 private static BayesianOpponentModel oppModel1, oppModel1b, oppModel2,
60 oppModel3;
61
62 private final static List<List<Bid>> list = new LinkedList<>();
63
64 private final static Bid bid1, bid2, bid3;
65 private static final BigDecimal HALF = new BigDecimal("0.5");
66
67 static {
68 Map<String, ValueSet> issues = new HashMap<>();
69 Collection<DiscreteValue> discretevalues1 = new LinkedList<>();
70 discretevalues1.add(I1V1);
71 discretevalues1.add(I1V2);
72 DiscreteValueSet values1 = new DiscreteValueSet(discretevalues1);
73 issues.put(ISS1, values1);
74 NumberValueSet values2 = new NumberValueSet(BigDecimal.ZERO,
75 BigDecimal.TEN, new BigDecimal("0.3"));
76 issues.put(ISS2, values2);
77 domain = new Domain("test", issues);
78 domain2 = new Domain("test2", issues);
79
80 // slightly different issue1
81 issues = new HashMap<>();
82 discretevalues1 = new LinkedList<>();
83 discretevalues1.add(I1V1);
84 discretevalues1.add(I1V2b);
85 values1 = new DiscreteValueSet(discretevalues1);
86 issues.put(ISS1, values1);
87 values2 = new NumberValueSet(BigDecimal.ZERO, BigDecimal.TEN,
88 new BigDecimal("0.3"));
89 issues.put(ISS2, values2);
90 domain3 = new Domain("test", issues);
91
92 // all bids are for domain
93 Map<String, Value> issuevalues = new HashMap<>();
94 issuevalues.put(ISS1, I1V1);
95 issuevalues.put(ISS2, new NumberValue(new BigDecimal("1.2")));
96 bid1 = new Bid(issuevalues);
97
98 issuevalues.put(ISS1, I1V1);
99 issuevalues.put(ISS2, new NumberValue(new BigDecimal("1.5")));
100 bid2 = new Bid(issuevalues);
101
102 issuevalues.put(ISS1, I1V2);
103 issuevalues.put(ISS2, new NumberValue(new BigDecimal("1.5")));
104 bid3 = new Bid(issuevalues);
105
106 oppModel1 = new BayesianOpponentModel(domain);
107 oppModel1b = new BayesianOpponentModel(domain);
108 oppModel2 = new BayesianOpponentModel(domain)
109 .with(new Offer(other, bid1), progress);
110 oppModel3 = new BayesianOpponentModel(domain)
111 .with(new Offer(other, bid2), progress);
112
113 }
114
115 private ObjectMapper jackson = new ObjectMapper();
116
117 @Override
118 public List<List<BayesianOpponentModel>> getGeneralTestData() {
119 return Arrays.asList(Arrays.asList(oppModel1, oppModel1b),
120 Arrays.asList(oppModel2), Arrays.asList(oppModel3));
121 }
122
123 @Override
124 public List<String> getGeneralTestStrings() {
125 // not much we can test. The internals are too detailed and situation
126 // specific
127 return Arrays.asList("BayesianOpponentModel.*",
128 "BayesianOpponentModel.*", "BayesianOpponentModel.*");
129 }
130
131 @Test(expected = NullPointerException.class)
132 public void smokeTestNull() {
133 new BayesianOpponentModel().with((Domain) null, null);
134 }
135
136 @Test
137 public void testNormalization() {
138 System.out.println(oppModel1.getWeights());
139 }
140
141 @SuppressWarnings("unused")
142 @Test
143 public void smokeTest() {
144 new BayesianOpponentModel(domain);
145 }
146
147 @Test
148 public void testEmptyModel() {
149 BayesianOpponentModel oppModel = new BayesianOpponentModel()
150 .with(domain, null);
151 // somewhere 0.4-0.6 should be fine.
152 // exact value varies with the exact hypotheses
153 assertEquals(0.5, oppModel.getUtility(bid1).doubleValue(), 0.1);
154 assertEquals(0.5, oppModel.getUtility(bid2).doubleValue(), 0.1);
155 }
156
157 @Test
158 public void testEmptyBid() {
159 Bid bid = new Bid(Collections.emptyMap());
160 assertEquals(0d, oppModel1.getUtility(bid).doubleValue(), 0.000001);
161 }
162
163 @Test
164 public void testUpdate() {
165
166 BayesianOpponentModel newOppModel = oppModel1
167 .with(new Offer(other, bid1), progress);
168 assertTrue(oppModel1.getUtility(bid1).doubleValue() < newOppModel
169 .getUtility(bid1).doubleValue());
170 assertTrue(newOppModel.getBidHistory().size() == 1);
171
172 // and if we continue with next bid, the first should still hold
173 // and the next bid should also improve
174 BayesianOpponentModel newOppModel2 = newOppModel
175 .with(new Offer(other, bid2), progress);
176 assertTrue(oppModel1.getUtility(bid1).doubleValue() < newOppModel2
177 .getUtility(bid1).doubleValue());
178 assertTrue(oppModel1.getUtility(bid2).doubleValue() < newOppModel2
179 .getUtility(bid2).doubleValue());
180
181 assertTrue(newOppModel2.getBidHistory().size() == 2);
182
183 // bid1= (i1v1, 1.2), bid2= (i1v1, 1.5)
184 // so bidding keeps ISS1 but changes ISS2.
185 // check that ISS1 increases weight and ISS2 decreases
186 assertTrue(oppModel1.getWeights().get(ISS1).doubleValue() < newOppModel2
187 .getWeights().get(ISS1).doubleValue());
188
189 // it may not work like this, due to renormalization steps.
190// assertTrue(oppModel1.getWeights().get(ISS2).doubleValue() < newOppModel2
191// .getWeights().get(ISS2).doubleValue());
192
193 }
194
195 @Test
196 public void testPartialBidUpdate() {
197 BayesianOpponentModel oppModel = oppModel1.with(new Offer(other, bid1),
198 progress);
199 Bid partialbid = new Bid(ISS1, I1V1);
200 oppModel.with(new Offer(other, partialbid), progress);
201 }
202
203 @Test
204 public void testStableName() {
205 String name = oppModel1.getName();
206 assertNotNull(name);
207 assertEquals(name, oppModel1.getName());
208 }
209
210 @Test
211 public void testWeightsNormalized() {
212 assertEquals(1d, oppModel1.getWeights().values().stream()
213 .mapToDouble(f -> f).sum(), 0.000001);
214 }
215
216 /**
217 * duration/stress test with random bids
218 */
219 @Test
220 public void testRepeatedRandomBidding() throws IOException {
221 // use japantrip as it has numbervalue as well
222 String profile = new String(
223 Files.readAllBytes(
224 Paths.get("src/test/resources/japantrip.json")),
225 StandardCharsets.UTF_8);
226 Domain dom = jackson.readValue(profile, Domain.class);
227 BayesianOpponentModel model = new BayesianOpponentModel(dom);
228
229 for (int time = 1; time < 100; time++) {
230 Bid bid = getRandomBid(dom, null, null);
231 double util = model.getUtility(bid).doubleValue();
232 System.out.println(util);
233 assertTrue(util > 0d && util < 1d);
234 model = model.with(new Offer(other, bid), null);
235 }
236 }
237
238 /**
239 * duration/stress test with similar bids
240 */
241
242 @Test
243 public void testRepeateSimilarBidding() throws IOException {
244 // use japantrip as it has numbervalue as well
245 String profile = new String(
246 Files.readAllBytes(
247 Paths.get("src/test/resources/japantrip.json")),
248 StandardCharsets.UTF_8);
249 Domain dom = jackson.readValue(profile, Domain.class);
250 BayesianOpponentModel model = new BayesianOpponentModel(dom);
251
252 for (int time = 1; time < 100; time++) {
253 Bid bid = getRandomBid(dom, "purpose",
254 new DiscreteValue("sightseeing"));
255 double util = model.getUtility(bid).doubleValue();
256 // System.out.println(util);
257 assertTrue(util > 0d && util < 1d);
258 model = model.with(new Offer(other, bid), null);
259 }
260 }
261
262 /**
263 *
264 * @param dom the {@link Domain}
265 * @param specialissue an issue name. If not null, value is used for this
266 * issue.
267 * @param value the value to use for specialissue.
268 *
269 * @return random bid from domain. Notice that bidspace depends on profile
270 * so we should not be using bidspace. This makes this a bit clumsy
271 */
272 private Bid getRandomBid(Domain dom, String specialissue, Value value) {
273 Map<String, Value> map = new HashMap<>();
274 for (String issue : dom.getIssues()) {
275 Value val = value;
276 if (!issue.equals(specialissue)) {
277 ValueSet values = dom.getValues(issue);
278 val = values.get(rnd.nextInt(values.size().intValue()));
279 }
280 map.put(issue, val);
281 }
282 return new Bid(map);
283 }
284
285 /**
286 * Generate all bids from a space, sort to order, and pump them in that
287 * order into Bayesian model. In the end the model should "match" with the
288 * original space.
289 *
290 * @return
291 * @throws IOException
292 */
293 @Ignore
294 @Test
295 public void testPumpBidsInOrder() throws IOException {
296 String profile = new String(
297 Files.readAllBytes(
298 Paths.get("src/test/resources/japantrip1.json")),
299 StandardCharsets.UTF_8);
300 UtilitySpace japantrip = jackson.readValue(profile, UtilitySpace.class);
301 BayesianOpponentModel model = new BayesianOpponentModel(
302 japantrip.getDomain());
303
304 Map<Double, Bid> sorted = getAllBids(japantrip);
305 for (Double val : sorted.keySet()) {
306 model = model.with(new Offer(other, sorted.get(val)), null);
307 }
308 System.out.println(model);
309
310 Map<String, Double> weights = model.getWeights();
311 System.out.println(weights);
312
313 // you would expect this result but in practice it doesn't
314 assertEquals(weights.get("place").doubleValue(), 0.57, 0.1);
315 assertEquals(weights.get("budget").doubleValue(), 0.09, 0.1);
316 assertEquals(weights.get("days").doubleValue(), 0.17, 0.1);
317 assertEquals(weights.get("purpose").doubleValue(), 0.17, 0.1);
318
319 }
320
321 /**
322 *
323 * @param utllspace the {@link UtilitySpace} to be compiled
324 * @return all bids, sorted from high to low utility. Notice, normally you
325 * would use AllBidsList but we can not import that module here.
326 * Warning, enumerating and sorting all bids in a space this way is
327 * too expensive for use in real time negotiation.
328 */
329 private Map<Double, Bid> getAllBids(UtilitySpace utllspace) {
330 Domain dom = utllspace.getDomain();
331 List<String> issues = new ArrayList<String>(
332 utllspace.getDomain().getIssues());
333 List<ImmutableList<Value>> values = issues.stream()
334 .map(issue -> dom.getValues(issue))
335 .collect(Collectors.toList());
336
337 Outer<Value> allBidValues = new Outer<Value>(values);
338 Map<Double, Bid> bidmap = new TreeMap<>(Collections.reverseOrder());
339 for (ImmutableList<Value> bidvals : allBidValues) {
340 Map<String, Value> vals = new HashMap<>();
341 for (int n = 0; n < issues.size(); n++) {
342 vals.put(issues.get(n), bidvals.get(n));
343 }
344 Bid bid = new Bid(vals);
345 bidmap.put(utllspace.getUtility(bid).doubleValue(), bid);
346 }
347
348 return bidmap;
349 }
350}
Note: See TracBrowser for help on using the repository browser.