[127] | 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 | }
|
---|