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