/* * SimpleAgent.java * * Created on November 6, 2006, 9:55 AM * */ package agents; import java.util.HashMap; import java.util.List; import genius.core.Agent; import genius.core.Bid; import genius.core.SupportedNegotiationSetting; import genius.core.actions.Accept; import genius.core.actions.Action; import genius.core.actions.EndNegotiation; import genius.core.actions.Offer; import genius.core.issue.ISSUETYPE; import genius.core.issue.Issue; import genius.core.issue.IssueDiscrete; import genius.core.issue.Objective; import genius.core.issue.Value; import genius.core.issue.ValueDiscrete; import genius.core.issue.ValueReal; import genius.core.utility.AdditiveUtilitySpace; import genius.core.utility.EvaluatorDiscrete; import genius.core.utility.EvaluatorReal; /** * * @author Dmytro Tykhonov & Koen Hindriks */ public class ABMPAgent extends Agent { private Action messageOpponent; // private int nrOfIssues; private Bid myLastBid = null; private Action myLastAction = null; // private double[] fIssueWeight; private enum ACTIONTYPE { START, OFFER, ACCEPT, BREAKOFF }; // Paraters used in ABMP strategy // TODO: Include these parameters as agent parameters in agent's utility // template. // QUESTION: How to do that nicely, since these parameters are strategy // specific? private static final double NEGOTIATIONSPEED = 0.1; // TODO: Probably still // somewhere a bug. When // you set this too low // (e.g. 0.05), no deal // is reached and no // concession is done! private static final double CONCESSIONFACTOR = 1; private static final double CONFTOLERANCE = 0; private static final double UTIlITYGAPSIZE = 0.02; // Accept when utility // gap is <= // UTILITYGAPSIZE. // CHECK: Utility gap size needed since concession steps get VERY small when // opponent's last bid utility is // close to own last bid utility. // Code is independent from AMPO vs CITY case, but some specifics about // using this case as test are specified below. // **************************************************************************************************** // AMPO VS CITY: Outcome space has size of about 7 milion. // **************************************************************************************************** // ******************************************************** // ******************************************* // CHECK: ABMP gets stuck on the Car Example with a negotiation speed of // less than 0.05!! // ABMP "gets stuck" on AMPO vs CITY. The search through the space is not // effective in discrete outcome // spaces. Even with very high negotiation speed parameters (near 1) no bid // can be found with the target utility // at a certain point. In a discrete space, the evaluation distance between // two different values on an // issue need to be taken into account, which may differ from value to // value... In such spaces one strategy // would be to consider which combination of concessions on a set of issues // would provide // ******************************************************** // ******************************************* /** Creates a new instance of MyAgent */ public ABMPAgent() { super(); } public void init() { messageOpponent = null; myLastBid = null; myLastAction = null; } public void ReceiveMessage(Action opponentAction) { messageOpponent = opponentAction; } private Action proposeInitialBid() { Bid lBid = null; // Return (one of the) possible bid(s) with maximal utility. try { lBid = utilitySpace.getMaxUtilityBid(); } catch (Exception e) { e.printStackTrace(); } myLastBid = lBid; return new Offer(getAgentID(), lBid); } private Action proposeNextBid(Bid lOppntBid) throws Exception { Bid lBid = null; double lMyUtility, lOppntUtility, lTargetUtility; // Both parties have made an initial bid. Compute associated utilities // from my point of view. lMyUtility = utilitySpace.getUtility(myLastBid); lOppntUtility = utilitySpace.getUtility(lOppntBid); lTargetUtility = getTargetUtility(lMyUtility, lOppntUtility); lBid = getBidABMPsimple(lTargetUtility); myLastBid = lBid; return new Offer(getAgentID(), lBid); } public Action chooseAction() { Action lAction = null; ACTIONTYPE lActionType; Bid lOppntBid = null; lActionType = getActionType(messageOpponent); switch (lActionType) { case OFFER: // Offer received from opponent lOppntBid = ((Offer) messageOpponent).getBid(); if (myLastAction == null) // Other agent started, lets propose my initial bid. lAction = proposeInitialBid(); else { try { if (utilitySpace.getUtility(lOppntBid) >= (utilitySpace .getUtility(myLastBid)) - UTIlITYGAPSIZE) // Opponent bids equally, or outbids my previous bid, so // lets accept. lAction = new Accept(getAgentID(), lOppntBid); else // Propose counteroffer. Get next bid. try { lAction = proposeNextBid(lOppntBid); } catch (Exception e) { e.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); } } break; case ACCEPT: // Presumably, opponent accepted last bid, but let's // check... case BREAKOFF: // nothing left to do. Negotiation ended, which should be checked by // Negotiator... break; default: // I am starting, but not sure whether Negotiator checks this, so // lets check also myLastAction... if (myLastAction == null) lAction = proposeInitialBid(); else // simply repeat last action lAction = myLastAction; break; } myLastAction = lAction; return lAction; } private ACTIONTYPE getActionType(Action lAction) { ACTIONTYPE lActionType = ACTIONTYPE.START; if (lAction instanceof Offer) lActionType = ACTIONTYPE.OFFER; else if (lAction instanceof Accept) lActionType = ACTIONTYPE.ACCEPT; else if (lAction instanceof EndNegotiation) lActionType = ACTIONTYPE.BREAKOFF; return lActionType; } // ABMP Specific Code private Bid getBidABMPsimple(double targetUtility) throws Exception { // Value[] lIssueIndex = new Value[nrOfIssues]; HashMap lIssueIndex = new HashMap(); List issues = utilitySpace.getDomain().getIssues(); double[] lIssueAlpha = new double[issues.size()]; double[] lBE = new double[issues.size()]; double[] lBTE = new double[issues.size()]; double[] lTE = new double[issues.size()]; double lUtility = 0, lNF = 0, lAlpha, lUtilityGap, lTotalConcession = 0; // ASSUMPTION: Method computes a second bid. Method proposeInitialBid is // used to compute first bid. lUtilityGap = targetUtility - utilitySpace.getUtility(myLastBid); for (int i = 0; i < issues.size(); i++) { lBE[i] = (Double) (((AdditiveUtilitySpace) utilitySpace) .getEvaluator(issues.get(i).getNumber()).getEvaluation( ((AdditiveUtilitySpace) utilitySpace), myLastBid, issues .get(i).getNumber())); } // STEP 1: Retrieve issue value for last bid and compute concession on // each issue. int i = 0; for (Issue lIssue : issues) { lAlpha = (1 - ((AdditiveUtilitySpace) utilitySpace) .getWeight(lIssue.getNumber())) * lBE[i]; // CHECK: // (1 // - // lBE[i]); // This // factor // is // not // right?? lNF = lNF + ((AdditiveUtilitySpace) utilitySpace).getWeight(lIssue .getNumber()) * lAlpha; lIssueAlpha[i] = lAlpha; i++; } // Compute basic target evaluations per issue for (i = 0; i < issues.size(); i++) { lBTE[i] = lBE[i] + (lIssueAlpha[i] / lNF) * lUtilityGap; } // STEP 2: Add configuration tolerance for opponent's bid for (i = 0; i < issues.size(); i++) { lUtility = (Double) (((AdditiveUtilitySpace) utilitySpace) .getEvaluator(issues.get(i).getNumber()).getEvaluation( ((AdditiveUtilitySpace) utilitySpace), ((Offer) messageOpponent).getBid(), issues.get(i) .getNumber())); lTE[i] = (1 - CONFTOLERANCE) * lBTE[i] + CONFTOLERANCE * lUtility; } // STEP 3: Find bid in outcome space with issue target utilities // corresponding with those computed above. // ASSUMPTION: There is always a UNIQUE issue value with utility closest // to the target evaluation. // First determine new values for discrete-valued issues. double lEvalValue; int lNrOfRealIssues = 0; for (i = 0; i < issues.size(); i++) { lUtility = 1; // ASSUMPTION: Max utility = 1. Objective lIssue = issues.get(i); if (lIssue.getType() == ISSUETYPE.DISCRETE) { IssueDiscrete lIssueDiscrete = (IssueDiscrete) lIssue; for (int j = 0; j < lIssueDiscrete.getNumberOfValues(); j++) { lEvalValue = ((EvaluatorDiscrete) ((AdditiveUtilitySpace) utilitySpace) .getEvaluator(lIssue.getNumber())) .getEvaluation(lIssueDiscrete.getValue(j)); if (Math.abs(lTE[i] - lEvalValue) < lUtility) { // lIssueIndex[i] = lIssueDiscrete.getValue(j); lIssueIndex.put(new Integer(lIssue.getNumber()), lIssueDiscrete.getValue(j)); lUtility = Math.abs(lTE[i] - lEvalValue); }// if }// for lTotalConcession += ((AdditiveUtilitySpace) utilitySpace) .getWeight(lIssue.getNumber()) * (lBE[i] - ((EvaluatorDiscrete) ((AdditiveUtilitySpace) utilitySpace) .getEvaluator(lIssue.getNumber())) .getEvaluation((ValueDiscrete) (lIssueIndex .get(lIssue.getNumber())))); } else if (lIssue.getType() == ISSUETYPE.REAL) lNrOfRealIssues += 1; } // TODO: Still need to integrate integer-valued issues somewhere here. // Low priority. // STEP 4: RECOMPUTE size of remaining concession step // Reason: Issue value may not provide exact match with basic target // evaluation value. // NOTE: This recomputation also includes any concession due to // configuration tolerance parameter... // First compute difference between actual concession on issue and // target evaluation. // TODO: Think about how to (re)distribute remaining concession over // MULTIPLE real issues. In car example // not important. Low priority. double lRestUtitility = lUtilityGap + lTotalConcession; // Distribute remaining utility of real issues. Integers still to be // done. See above. for (i = 0; i < issues.size(); i++) { Objective lIssue = issues.get(i); if (lIssue.getType() == ISSUETYPE.REAL) { lTE[i] += lRestUtitility / lNrOfRealIssues; EvaluatorReal lRealEvaluator = (EvaluatorReal) (((AdditiveUtilitySpace) utilitySpace) .getEvaluator(lIssue.getNumber())); double r = lRealEvaluator.getValueByEvaluation(lTE[i]); // lIssueIndex[i] = new ValueReal(r); lIssueIndex.put(new Integer(lIssue.getNumber()), new ValueReal( r)); } } return new Bid(utilitySpace.getDomain(), lIssueIndex); } private double getTargetUtility(double myUtility, double oppntUtility) { return myUtility + getConcessionStep(myUtility, oppntUtility); } private double getNegotiationSpeed() { return NEGOTIATIONSPEED; } private double getConcessionFactor() { // The more the agent is willing to concess on its aspiration value, the // higher this factor. return CONCESSIONFACTOR; } private double getConcessionStep(double myUtility, double oppntUtility) { double lConcessionStep = 0, lMinUtility = 0, lUtilityGap = 0; // Compute concession step lMinUtility = 1 - getConcessionFactor(); lUtilityGap = (oppntUtility - myUtility); lConcessionStep = getNegotiationSpeed() * (1 - lMinUtility / myUtility) * lUtilityGap; System.out.println(lConcessionStep); return lConcessionStep; } @Override public SupportedNegotiationSetting getSupportedNegotiationSetting() { return SupportedNegotiationSetting.getLinearUtilitySpaceInstance(); } }