1 | package agents;
|
---|
2 |
|
---|
3 | import java.util.HashMap;
|
---|
4 | import java.util.List;
|
---|
5 |
|
---|
6 | import genius.core.Agent;
|
---|
7 | import genius.core.Bid;
|
---|
8 | import genius.core.SupportedNegotiationSetting;
|
---|
9 | import genius.core.actions.Accept;
|
---|
10 | import genius.core.actions.Action;
|
---|
11 | import genius.core.actions.EndNegotiation;
|
---|
12 | import genius.core.actions.Offer;
|
---|
13 | import genius.core.issue.ISSUETYPE;
|
---|
14 | import genius.core.issue.Issue;
|
---|
15 | import genius.core.issue.IssueDiscrete;
|
---|
16 | import genius.core.issue.Value;
|
---|
17 | import genius.core.issue.ValueDiscrete;
|
---|
18 | import genius.core.issue.ValueReal;
|
---|
19 | import genius.core.utility.AdditiveUtilitySpace;
|
---|
20 | import genius.core.utility.EvaluatorDiscrete;
|
---|
21 | import genius.core.utility.EvaluatorReal;
|
---|
22 |
|
---|
23 | /**
|
---|
24 | *
|
---|
25 | * @author Dmytro Tykhonov & Koen Hindriks
|
---|
26 | */
|
---|
27 |
|
---|
28 | public class ABMPAgent2 extends Agent {
|
---|
29 |
|
---|
30 | private Action messageOpponent;
|
---|
31 | // private int nrOfIssues;
|
---|
32 | private Bid myLastBid = null;
|
---|
33 | private Action myLastAction = null;
|
---|
34 |
|
---|
35 | // private double[] fIssueWeight;
|
---|
36 | private enum ACTIONTYPE {
|
---|
37 | START, OFFER, ACCEPT, BREAKOFF
|
---|
38 | };
|
---|
39 |
|
---|
40 | private double fOldTargetUtility;
|
---|
41 | // Paraters used in ABMP strategy
|
---|
42 | // TODO: Include these parameters as agent parameters in agent's utility
|
---|
43 | // template.
|
---|
44 | // QUESTION: How to do that nicely, since these parameters are strategy
|
---|
45 | // specific?
|
---|
46 | private static final double NEGOTIATIONSPEED = 0.1; // TODO: Probably still
|
---|
47 | // somewhere a bug. When
|
---|
48 | // you set this too low
|
---|
49 | // (e.g. 0.05), no deal
|
---|
50 | // is reached and no
|
---|
51 | // concession is done!
|
---|
52 | private static final double CONCESSIONFACTOR = 1;
|
---|
53 | private static final double CONFTOLERANCE = 0;
|
---|
54 | private static final double UTIlITYGAPSIZE = 0.02; // Accept when utility
|
---|
55 | // gap is <=
|
---|
56 | // UTILITYGAPSIZE.
|
---|
57 |
|
---|
58 | // CHECK: Utility gap size needed since concession steps get VERY small when
|
---|
59 | // opponent's last bid utility is
|
---|
60 | // close to own last bid utility.
|
---|
61 |
|
---|
62 | // Code is independent from AMPO vs CITY case, but some specifics about
|
---|
63 | // using this case as test are specified below.
|
---|
64 | // ****************************************************************************************************
|
---|
65 | // AMPO VS CITY: Outcome space has size of about 7 milion.
|
---|
66 | // ****************************************************************************************************
|
---|
67 | // ********************************************************
|
---|
68 | // *******************************************
|
---|
69 | // CHECK: ABMP gets stuck on the Car Example with a negotiation speed of
|
---|
70 | // less than 0.05!!
|
---|
71 | // ABMP "gets stuck" on AMPO vs CITY. The search through the space is not
|
---|
72 | // effective in discrete outcome
|
---|
73 | // spaces. Even with very high negotiation speed parameters (near 1) no bid
|
---|
74 | // can be found with the target utility
|
---|
75 | // at a certain point. In a discrete space, the evaluation distance between
|
---|
76 | // two different values on an
|
---|
77 | // issue need to be taken into account, which may differ from value to
|
---|
78 | // value... In such spaces one strategy
|
---|
79 | // would be to consider which combination of concessions on a set of issues
|
---|
80 | // would provide
|
---|
81 | // ********************************************************
|
---|
82 | // *******************************************
|
---|
83 |
|
---|
84 | /** Creates a new instance of MyAgent */
|
---|
85 |
|
---|
86 | public ABMPAgent2() {
|
---|
87 | super();
|
---|
88 | }
|
---|
89 |
|
---|
90 | @Override
|
---|
91 | public void init() {
|
---|
92 | super.init();
|
---|
93 | messageOpponent = null;
|
---|
94 | myLastBid = null;
|
---|
95 | myLastAction = null;
|
---|
96 | fOldTargetUtility = 1;
|
---|
97 |
|
---|
98 | }
|
---|
99 |
|
---|
100 | public void ReceiveMessage(Action opponentAction) {
|
---|
101 | messageOpponent = opponentAction;
|
---|
102 | }
|
---|
103 |
|
---|
104 | private Action proposeInitialBid() throws Exception {
|
---|
105 | Bid lBid;
|
---|
106 |
|
---|
107 | // Return (one of the) possible bid(s) with maximal utility.
|
---|
108 | lBid = utilitySpace.getMaxUtilityBid();
|
---|
109 | lBid = getBidRandomWalk(utilitySpace.getUtility(lBid) * 0.95,
|
---|
110 | utilitySpace.getUtility(lBid));
|
---|
111 | myLastBid = lBid;
|
---|
112 | return new Offer(this.getAgentID(), lBid);
|
---|
113 | }
|
---|
114 |
|
---|
115 | private Action proposeNextBid(Bid lOppntBid) {
|
---|
116 | Bid lBid = null;
|
---|
117 | double lMyUtility, lOppntUtility = 1, lTargetUtility;
|
---|
118 | // Both parties have made an initial bid. Compute associated utilities
|
---|
119 | // from my point of view.
|
---|
120 | lMyUtility = fOldTargetUtility;// utilitySpace.getUtility(myLastBid);
|
---|
121 | try {
|
---|
122 | lOppntUtility = utilitySpace.getUtility(lOppntBid);
|
---|
123 | } catch (Exception e) {
|
---|
124 | e.printStackTrace();
|
---|
125 | }
|
---|
126 | lTargetUtility = getTargetUtility(lMyUtility, lOppntUtility);
|
---|
127 | try {
|
---|
128 | lBid = getBidABMPsimple(lTargetUtility);
|
---|
129 | } catch (Exception e) {
|
---|
130 | e.printStackTrace();
|
---|
131 | }
|
---|
132 | myLastBid = lBid;
|
---|
133 | fOldTargetUtility = lTargetUtility;
|
---|
134 | return new Offer(this.getAgentID(), lBid);
|
---|
135 | }
|
---|
136 |
|
---|
137 | public Action chooseAction() {
|
---|
138 | Action lAction = null;
|
---|
139 | ACTIONTYPE lActionType;
|
---|
140 | Bid lOppntBid = null;
|
---|
141 |
|
---|
142 | lActionType = getActionType(messageOpponent);
|
---|
143 | switch (lActionType) {
|
---|
144 | case OFFER: // Offer received from opponent
|
---|
145 | try {
|
---|
146 | lOppntBid = ((Offer) messageOpponent).getBid();
|
---|
147 | if (myLastAction == null)
|
---|
148 | // Other agent started, lets propose my initial bid.
|
---|
149 | lAction = proposeInitialBid();
|
---|
150 | // DT Accept if utility gap is smaller than my target utility
|
---|
151 | // (instead of actual utility of my previous bid)
|
---|
152 | else if (utilitySpace.getUtility(lOppntBid) >= /*
|
---|
153 | * (utilitySpace.
|
---|
154 | * getUtility
|
---|
155 | * (myLastBid))
|
---|
156 | */fOldTargetUtility
|
---|
157 | - UTIlITYGAPSIZE)
|
---|
158 | // Opponent bids equally, or outbids my previous bid, so
|
---|
159 | // lets accept.
|
---|
160 | lAction = new Accept(getAgentID(), lOppntBid);
|
---|
161 | else
|
---|
162 | // Propose counteroffer. Get next bid.
|
---|
163 | lAction = proposeNextBid(lOppntBid);
|
---|
164 | } catch (Exception e) {
|
---|
165 | e.printStackTrace();
|
---|
166 | }
|
---|
167 | break;
|
---|
168 | case ACCEPT: // Presumably, opponent accepted last bid, but let's
|
---|
169 | // check...
|
---|
170 | /*
|
---|
171 | * lOppntBid = ((Accept) messageOpponent).getBid(); if
|
---|
172 | * (lOppntBid.equals(myLastBid)) lAction = new Accept(this,
|
---|
173 | * myLastBid); else lAction = new Offer(this, myLastBid); break;
|
---|
174 | */
|
---|
175 | case BREAKOFF:
|
---|
176 | // nothing left to do. Negotiation ended, which should be checked by
|
---|
177 | // Negotiator...
|
---|
178 | break;
|
---|
179 | default:
|
---|
180 | // I am starting, but not sure whether Negotiator checks this, so
|
---|
181 | // lets check also myLastAction...
|
---|
182 | if (myLastAction == null)
|
---|
183 | try {
|
---|
184 | lAction = proposeInitialBid();
|
---|
185 | } catch (Exception e) {
|
---|
186 | e.printStackTrace();
|
---|
187 | }
|
---|
188 | else
|
---|
189 | // simply repeat last action
|
---|
190 | lAction = myLastAction;
|
---|
191 | break;
|
---|
192 | }
|
---|
193 |
|
---|
194 | myLastAction = lAction;
|
---|
195 | return lAction;
|
---|
196 | }
|
---|
197 |
|
---|
198 | private ACTIONTYPE getActionType(Action lAction) {
|
---|
199 | ACTIONTYPE lActionType = ACTIONTYPE.START;
|
---|
200 |
|
---|
201 | if (lAction instanceof Offer)
|
---|
202 | lActionType = ACTIONTYPE.OFFER;
|
---|
203 | else if (lAction instanceof Accept)
|
---|
204 | lActionType = ACTIONTYPE.ACCEPT;
|
---|
205 | else if (lAction instanceof EndNegotiation)
|
---|
206 | lActionType = ACTIONTYPE.BREAKOFF;
|
---|
207 | return lActionType;
|
---|
208 | }
|
---|
209 |
|
---|
210 | /*
|
---|
211 | * public void loadUtilitySpace(String fileName) {
|
---|
212 | *
|
---|
213 | * utilitySpace = new
|
---|
214 | * SimpleUtilitySpace(getNegotiationTemplate().getDomain(), fileName);
|
---|
215 | *
|
---|
216 | * nrOfIssues = getNegotiationTemplate().getDomain().getNumberOfIssues();
|
---|
217 | * fIssueWeight = new double[nrOfIssues]; for (int i=0; i<nrOfIssues; i++) {
|
---|
218 | * fIssueWeight[i] = this.utilitySpace.getWeight(i); } }
|
---|
219 | */
|
---|
220 | // ABMP Specific Code
|
---|
221 |
|
---|
222 | private Bid getBidABMPsimple(double targetUtility) throws Exception {
|
---|
223 | int nrOfIssues = utilitySpace.getDomain().getIssues().size();
|
---|
224 | double[] lIssueWeight = new double[nrOfIssues];
|
---|
225 | int i = 0;
|
---|
226 | for (Issue lIssue : utilitySpace.getDomain().getIssues()) {
|
---|
227 | lIssueWeight[i] = ((AdditiveUtilitySpace) utilitySpace)
|
---|
228 | .getWeight(lIssue.getNumber());
|
---|
229 | i++;
|
---|
230 | }
|
---|
231 | List<Issue> lIssues = utilitySpace.getDomain().getIssues();
|
---|
232 | Value[] lIssueIndex = new Value[nrOfIssues];
|
---|
233 | double[] lIssueAlpha = new double[nrOfIssues];
|
---|
234 | double[] lBE = new double[nrOfIssues];
|
---|
235 | double[] lBTE = new double[nrOfIssues];
|
---|
236 | double[] lTE = new double[nrOfIssues];
|
---|
237 | double lUtility = 0, lNF = 0, lAlpha, lUtilityGap, lTotalConcession = 0;
|
---|
238 |
|
---|
239 | // ASSUMPTION: Method computes a second bid. Method proposeInitialBid is
|
---|
240 | // used to compute first bid.
|
---|
241 | lUtilityGap = targetUtility - utilitySpace.getUtility(myLastBid);
|
---|
242 | for (i = 0; i < nrOfIssues; i++) {
|
---|
243 | lBE[i] = (Double) (((AdditiveUtilitySpace) utilitySpace)
|
---|
244 | .getEvaluator(lIssues.get(i).getNumber()).getEvaluation(
|
---|
245 | ((AdditiveUtilitySpace) utilitySpace), myLastBid, lIssues
|
---|
246 | .get(i).getNumber()));
|
---|
247 | }
|
---|
248 |
|
---|
249 | // STEP 1: Retrieve issue value for last bid and compute concession on
|
---|
250 | // each issue.
|
---|
251 | for (i = 0; i < nrOfIssues; i++) {
|
---|
252 | lAlpha = (1 - lIssueWeight[i]) * lBE[i]; // CHECK: (1 - lBE[i]);
|
---|
253 | // This factor is not
|
---|
254 | // right??
|
---|
255 | lNF = lNF + lIssueWeight[i] * lAlpha;
|
---|
256 | lIssueAlpha[i] = lAlpha;
|
---|
257 | }
|
---|
258 |
|
---|
259 | // Compute basic target evaluations per issue
|
---|
260 | for (i = 0; i < nrOfIssues; i++) {
|
---|
261 | lBTE[i] = lBE[i] + (lIssueAlpha[i] / lNF) * lUtilityGap;
|
---|
262 | }
|
---|
263 |
|
---|
264 | // STEP 2: Add configuration tolerance for opponent's bid
|
---|
265 | for (i = 0; i < nrOfIssues; i++) {
|
---|
266 | lUtility = (Double) (((AdditiveUtilitySpace) utilitySpace)
|
---|
267 | .getEvaluator(lIssues.get(i).getNumber()).getEvaluation(
|
---|
268 | ((AdditiveUtilitySpace) utilitySpace),
|
---|
269 | ((Offer) messageOpponent).getBid(), lIssues.get(i)
|
---|
270 | .getNumber()));
|
---|
271 | lTE[i] = (1 - CONFTOLERANCE) * lBTE[i] + CONFTOLERANCE * lUtility;
|
---|
272 | }
|
---|
273 |
|
---|
274 | // STEP 3: Find bid in outcome space with issue target utilities
|
---|
275 | // corresponding with those computed above.
|
---|
276 | // ASSUMPTION: There is always a UNIQUE issue value with utility closest
|
---|
277 | // to the target evaluation.
|
---|
278 | // First determine new values for discrete-valued issues.
|
---|
279 | double lEvalValue;
|
---|
280 | int lNrOfRealIssues = 0;
|
---|
281 | for (i = 0; i < nrOfIssues; i++) {
|
---|
282 | lUtility = 1; // ASSUMPTION: Max utility = 1.
|
---|
283 | Issue lIssue = lIssues.get(i);// getNegotiationTemplate().getDomain().getIssue(i);
|
---|
284 | if (lIssue.getType() == ISSUETYPE.DISCRETE) {
|
---|
285 | IssueDiscrete lIssueDiscrete = (IssueDiscrete) lIssue;
|
---|
286 | for (int j = 0; j < lIssueDiscrete.getNumberOfValues(); j++) {
|
---|
287 | lEvalValue = ((EvaluatorDiscrete) ((AdditiveUtilitySpace) utilitySpace)
|
---|
288 | .getEvaluator(lIssues.get(i).getNumber()))
|
---|
289 | .getEvaluation(lIssueDiscrete.getValue(j));
|
---|
290 | if (Math.abs(lTE[i] - lEvalValue) < lUtility) {
|
---|
291 | lIssueIndex[i] = lIssueDiscrete.getValue(j);
|
---|
292 | lUtility = Math.abs(lTE[i] - lEvalValue);
|
---|
293 | }// if
|
---|
294 | }// for
|
---|
295 | lTotalConcession += lIssueWeight[i]
|
---|
296 | * (lBE[i] - ((EvaluatorDiscrete) ((AdditiveUtilitySpace) utilitySpace)
|
---|
297 | .getEvaluator(lIssues.get(i).getNumber()))
|
---|
298 | .getEvaluation((ValueDiscrete) lIssueIndex[i]));
|
---|
299 | } else if (lIssue.getType() == ISSUETYPE.REAL)
|
---|
300 | lNrOfRealIssues += 1;
|
---|
301 | }
|
---|
302 |
|
---|
303 | // TODO: Still need to integrate integer-valued issues somewhere here.
|
---|
304 | // Low priority.
|
---|
305 |
|
---|
306 | // STEP 4: RECOMPUTE size of remaining concession step
|
---|
307 | // Reason: Issue value may not provide exact match with basic target
|
---|
308 | // evaluation value.
|
---|
309 | // NOTE: This recomputation also includes any concession due to
|
---|
310 | // configuration tolerance parameter...
|
---|
311 | // First compute difference between actual concession on issue and
|
---|
312 | // target evaluation.
|
---|
313 | // TODO: Think about how to (re)distribute remaining concession over
|
---|
314 | // MULTIPLE real issues. In car example
|
---|
315 | // not important. Low priority.
|
---|
316 | double lRestUtitility = lUtilityGap + lTotalConcession;
|
---|
317 | // Distribute remaining utility of real issues. Integers still to be
|
---|
318 | // done. See above.
|
---|
319 | for (i = 0; i < nrOfIssues; i++) {
|
---|
320 | Issue lIssue = lIssues.get(i);// getNegotiationTemplate().getDomain().getIssue(i);
|
---|
321 | if (lIssue.getType() == ISSUETYPE.REAL) {
|
---|
322 | lTE[i] += lRestUtitility / lNrOfRealIssues;
|
---|
323 | EvaluatorReal lRealEvaluator = (EvaluatorReal) (((AdditiveUtilitySpace) utilitySpace)
|
---|
324 | .getEvaluator(lIssues.get(i).getNumber()));
|
---|
325 | double r = lRealEvaluator.getValueByEvaluation(lTE[i]);
|
---|
326 | lIssueIndex[i] = new ValueReal(r);
|
---|
327 | }
|
---|
328 | }
|
---|
329 | HashMap<Integer, Value> lValues = new HashMap<Integer, Value>();
|
---|
330 | for (i = 0; i < nrOfIssues; i++) {
|
---|
331 | lValues.put(lIssues.get(i).getNumber(), lIssueIndex[i]);
|
---|
332 | }
|
---|
333 | return new Bid(utilitySpace.getDomain(), lValues);
|
---|
334 | }
|
---|
335 |
|
---|
336 | private double getTargetUtility(double myUtility, double oppntUtility) {
|
---|
337 | return myUtility + getConcessionStep(myUtility, oppntUtility);
|
---|
338 | }
|
---|
339 |
|
---|
340 | private double getNegotiationSpeed() {
|
---|
341 | return NEGOTIATIONSPEED;
|
---|
342 | }
|
---|
343 |
|
---|
344 | private double getConcessionFactor() {
|
---|
345 | // The more the agent is willing to concess on its aspiration value, the
|
---|
346 | // higher this factor.
|
---|
347 | return CONCESSIONFACTOR;
|
---|
348 | }
|
---|
349 |
|
---|
350 | private double getConcessionStep(double myUtility, double oppntUtility) {
|
---|
351 | double lConcessionStep = 0, lMinUtility = 0, lUtilityGap = 0;
|
---|
352 |
|
---|
353 | // Compute concession step
|
---|
354 | lMinUtility = 1 - getConcessionFactor();
|
---|
355 | lUtilityGap = (oppntUtility - myUtility);
|
---|
356 | lConcessionStep = getNegotiationSpeed() * (1 - lMinUtility / myUtility)
|
---|
357 | * lUtilityGap;
|
---|
358 | System.out.println(lConcessionStep);
|
---|
359 | return lConcessionStep;
|
---|
360 | }
|
---|
361 |
|
---|
362 | private Bid getBidRandomWalk(double lowerBound, double upperBoud)
|
---|
363 | throws Exception {
|
---|
364 | Bid lBid = null, lBestBid = null;
|
---|
365 |
|
---|
366 | // Return bid that gets closest to target utility in a "random walk"
|
---|
367 | // search.
|
---|
368 | lBestBid = utilitySpace.getDomain().getRandomBid(null);
|
---|
369 | while (true) {
|
---|
370 | lBid = utilitySpace.getDomain().getRandomBid(null);
|
---|
371 | if ((utilitySpace.getUtility(lBid) > lowerBound)
|
---|
372 | && (utilitySpace.getUtility(lBestBid) < upperBoud)) {
|
---|
373 | lBestBid = lBid;
|
---|
374 | break;
|
---|
375 | }
|
---|
376 |
|
---|
377 | }
|
---|
378 | return lBestBid;
|
---|
379 | }
|
---|
380 |
|
---|
381 | @Override
|
---|
382 | public SupportedNegotiationSetting getSupportedNegotiationSetting() {
|
---|
383 | return SupportedNegotiationSetting.getLinearUtilitySpaceInstance();
|
---|
384 | }
|
---|
385 |
|
---|
386 | @Override
|
---|
387 | public String getVersion() {
|
---|
388 | return "1.0";
|
---|
389 | }
|
---|
390 | }
|
---|