package agents.anac.y2017.geneking; import java.util.List; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.Set; import java.io.IOException; import genius.core.AgentID; import genius.core.Bid; 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.IssueInteger; import genius.core.issue.IssueReal; import genius.core.issue.Value; import genius.core.issue.ValueDiscrete; import genius.core.issue.ValueInteger; import genius.core.issue.ValueReal; import genius.core.list.Tuple; import genius.core.parties.AbstractNegotiationParty; import genius.core.parties.NegotiationInfo; import genius.core.persistent.StandardInfo; import genius.core.persistent.StandardInfoList; import genius.core.utility.EvaluatorDiscrete; /** * @author W.Pasman Some improvements over the standard SimpleAgent. * * Random Walker, Zero Intelligence Agent */ class IssueFreqRank {// ある論点中の頻度等 private HashMap frequenceS;// 各提案内容の頻度 private int sum;// 全頻度の合計 private int maxFreq;// 最大頻度 private double average;// 頻度の平均 private double variance;// 頻度の分散 private double pseudoWeight;// 疑似重み IssueFreqRank(List valueS, ValueDiscrete aSelected) { frequenceS = new HashMap(); for (ValueDiscrete valueD : valueS) { frequenceS.put(valueD.getValue(), 0); } sum = 0; maxFreq = 0; average = 0; variance = 0; pseudoWeight = 0; addFreq(aSelected.getValue()); } public HashMap getFrequenceS() { return (frequenceS); } public int getSum() { return (sum); } public int getMaxFreq() { return (maxFreq); } public double getAverage() { return (average); } public double getVariance() { return (variance); } public double pseudoWeight() { return (pseudoWeight); } public void addFreq(String aSelected) { int current = frequenceS.get(aSelected); frequenceS.put(aSelected, current + 1); sum += 1; average = sum / frequenceS.size(); double vSum = 0; for (HashMap.Entry entry : frequenceS.entrySet()) {// 全ての値を調べる if (maxFreq < entry.getValue()) { maxFreq = entry.getValue();// 最大頻度を更新 } double diff = entry.getValue() - average; vSum += (diff * diff); } variance = Math.sqrt(vSum); } } public class GeneKing extends AbstractNegotiationParty {// Agent private Bid lastPartnerBid; private static double MINIMUM_BID_UTILITY = 0.3; // private StandardInfoList history; // private AbstractUtilitySpace utilitySpace; ArrayList geneS = new ArrayList();// 遺伝子(入札内容) ArrayList foreignS = new ArrayList();// 外来遺伝子(相手からの入札内容) ArrayList tailForeignS = new ArrayList(); ArrayList eliteS = new ArrayList();// 優秀な個体(効用値の高い入札) Bid offeredBid = null; Bid myLastBid = null; long initNum = 2000;// 初期個体数 int crossNum = 5;// 交叉回数 int limitForeignSNum = 500; int maxForeignSNum = 200; int maxNum = 300; int MaxChangeNum = 100; double acceptableUtility = 0.0; double tgtUtility = 1.0; final double VALIANCE = 0.05; Random randomnr = new Random(); EvaluatorDiscrete evaluator = new EvaluatorDiscrete(); // HashMap>> discreteRankS = new // HashMap>>(); HashMap> dValueRankS = new HashMap>(); HashMap> dFreqRankS2 = new HashMap>(); double utilWaight = 3.0, simWaight = 1.0; double getSimilarity2(Bid aBid1, Bid aBid2) { double sim = 0; List IssueS1 = aBid1.getIssues(); int index = 0; int len = IssueS1.size(); while (index < len) { Issue issue1 = IssueS1.get(index); switch (issue1.getType()) { case DISCRETE: { ValueDiscrete valueDiscrete1 = (ValueDiscrete) aBid1 .getValue(issue1.getNumber()); ValueDiscrete valueDiscrete2 = (ValueDiscrete) aBid2 .getValue(issue1.getNumber()); HashMap drank = dValueRankS .get(issue1.getName()); String fName = valueDiscrete1.getValue(), mName = valueDiscrete2.getValue(); double bigger = drank.get(fName), smaller = drank.get(mName); if (bigger < smaller) { double temp = bigger; bigger = smaller; smaller = temp; } double diff = bigger - smaller; if (diff < 0) { diff *= -1; } double finalDiff = (1 - diff / drank.size()) / len; if (finalDiff < 0) { finalDiff = 0; } // System.out.println("fr="+bigger+" fn="+fName+" mr="+smaller+" // mn="+mName+" diff="+diff+" size="+drank.size()); sim += finalDiff; break; } case INTEGER: { ValueInteger valueInt1 = (ValueInteger) aBid1 .getValue(issue1.getNumber()); ValueInteger valueInt2 = (ValueInteger) aBid2 .getValue(issue1.getNumber()); double diff = (double) valueInt1.getValue() - (double) valueInt2.getValue(); // System.out.println("Idiff="+diff); if (diff < 0) { diff *= -1.0; } IssueInteger issueInt = (IssueInteger) IssueS1.get(index); double finalDiff = (1 - diff / (issueInt.getUpperBound() - issueInt.getLowerBound())) / len; if (finalDiff < 0) { finalDiff = 0; } sim += finalDiff; break; } default: { break; } } ++index; } return (sim); } double getAveSim(Bid aAlpha, List aBetaS) { double sim = 0; for (Offer beta : aBetaS) { sim += getSimilarity2(aAlpha, beta.getBid()); // System.out.print(" sim="+sim); } sim /= aBetaS.size(); // System.out.println(" total="+sim); return (sim); } double getExUtility2(Bid aBid, HashMap aFreqRankS) { double util = 0; List issueS = utilitySpace.getDomain().getIssues(); for (Issue issue : issueS) { switch (issue.getType()) { case DISCRETE: { IssueFreqRank freqRank = aFreqRankS.get(issue.getName());// 順位 int freqValue = freqRank.getFrequenceS() .get(aBid.getValue(issue.getNumber())); if (freqValue == 0) { freqValue += 1; } double nFreqValue = (double) freqValue / (double) freqRank.getMaxFreq(); util += nFreqValue / issueS.size(); break; } case INTEGER: { util += ((ValueInteger) (aBid.getValue(issue.getNumber()))) .getValue(); break; } } } return (util); } double getMyEvaluation(Bid aBid, List aMotherS) { Set set = dFreqRankS2.keySet(); double exUtil1 = 0, exUtil2 = 0, count = 0; for (AgentID id : set) { if (count == 0) { // exUtil1 = getExUtility(aBid,dFreqRankS.get(id)); exUtil1 = getExUtility2(aBid, dFreqRankS2.get(id)); } else { // exUtil2 = getExUtility(aBid,dFreqRankS.get(id)); exUtil2 = getExUtility2(aBid, dFreqRankS2.get(id)); } ++count; } double diff = (exUtil1 - exUtil2) * 2; if (diff < 0) { diff *= -1; } double util = utilitySpace.getUtility(aBid), sim = getAveSim(aBid, aMotherS); double newEval = util * utilWaight + sim * simWaight + exUtil1 + exUtil2 - diff; // System.out.println("(u,s,e1,e2,d)="+"("+util+","+sim+","+exUtil1+","+exUtil2+","+diff+")"); return (newEval); } ArrayList chooseEliteS3(ArrayList aGeneS, List aMotherS) { eliteS = new ArrayList(); Bid best = new Bid(aGeneS.get(0)); double util = utilitySpace.getUtility(best); double sim = getAveSim(best, aMotherS); double bestEval = 0; // System.out.println(" (u,s)=("+util+","+sim+")"); ArrayList newGeneS = new ArrayList(aGeneS); int index, count; while (eliteS.size() < maxNum) { index = 0; count = 0; bestEval = -10; for (Bid gene : newGeneS) { double eval = getMyEvaluation(gene, aMotherS); if (eval > bestEval) { best = gene; bestEval = eval; index = count; } ++count; } eliteS.add(best); newGeneS.remove(index);// 加えた入札を消す if (newGeneS.size() == 0) { break; } } util = utilitySpace.getUtility(best); sim = getAveSim(best, aMotherS); // System.out.println(" (u,s)2=("+util+","+sim+")"); return (eliteS); } Bid chooseBest(ArrayList aGeneS) { Bid best = new Bid(aGeneS.get(0)); double bestEval = getMyEvaluation(best, tailForeignS); for (Bid gene : aGeneS) { double eval = getMyEvaluation(gene, tailForeignS); if (eval > bestEval) { best = gene; bestEval = eval; } } return (best); } private Bid getRandomBidGK() { HashMap values = new HashMap(); // pairs // List issues = utilitySpace.getDomain().getIssues(); Random randomnr = new Random(); Bid bid = null; do { for (Issue lIssue : issues) { switch (lIssue.getType()) { case DISCRETE: {// 文字列 IssueDiscrete lIssueDiscrete = (IssueDiscrete) lIssue; int optionIndex = randomnr .nextInt(lIssueDiscrete.getNumberOfValues()); values.put(lIssue.getNumber(), lIssueDiscrete.getValue(optionIndex)); break; } case REAL: {// IssueReal lIssueReal = (IssueReal) lIssue; int optionInd = randomnr.nextInt( lIssueReal.getNumberOfDiscretizationSteps() - 1); values.put(lIssueReal.getNumber(), new ValueReal(lIssueReal .getLowerBound() + (lIssueReal.getUpperBound() - lIssueReal.getLowerBound()) * (optionInd) / (lIssueReal .getNumberOfDiscretizationSteps()))); break; } case INTEGER: { IssueInteger lIssueInteger = (IssueInteger) lIssue; int optionIndex2 = lIssueInteger.getLowerBound() + randomnr.nextInt(lIssueInteger.getUpperBound() - lIssueInteger.getLowerBound()); values.put(lIssueInteger.getNumber(), new ValueInteger(optionIndex2)); break; } default: { System.out.println("issue type " + lIssue.getType() + " not supported by geneKing"); } } } bid = new Bid(utilitySpace.getDomain(), values); } while (utilitySpace.getUtility(bid) < MINIMUM_BID_UTILITY); return (bid); } private ArrayList getRandomBidS() { ArrayList initS = new ArrayList(); while (initS.size() < initNum) { Bid newBid = null; // do{ newBid = getRandomBidGK(); // }while(initS.contains(newBid)); initS.add(newBid); } return (initS); } Bid uniformCrossOver5(Bid aFather, Bid aMother, HashMap aFreqRankS) { Bid child = new Bid(aFather); List genome = child.getIssues(); for (Issue value : genome) { switch (value.getType()) { case DISCRETE: { IssueDiscrete lIssueDis = (IssueDiscrete) value; String fName = ((ValueDiscrete) aFather .getValue(value.getNumber())).getValue();// 父親の文字列 String mName = ((ValueDiscrete) aMother .getValue(value.getNumber())).getValue();// 母親の文字列 // System.out.println("f="+evaluator.getValue(((ValueDiscrete)aFather.getValue(value.getNumber()))) // +"m=" // +evaluator.getValue(((ValueDiscrete)aMother.getValue(value.getNumber())))); if (fName == mName) {// 互いに同じ提案だった場合 child.putValue(value.getNumber(), aFather.getValue(value.getNumber())); } else {// 提案が異なる場合 HashMap rank = dValueRankS .get(lIssueDis.getName()); HashMap aFreqRank = aFreqRankS .get(value.getName()).getFrequenceS(); double bigger = rank.get(fName) * aFreqRank.get(fName), smaller = rank.get(mName) * aFreqRank.get(mName); if (bigger < smaller) { double temp = bigger; bigger = smaller; smaller = temp; } ArrayList midS = new ArrayList(); for (HashMap.Entry entry : rank .entrySet()) {// 全ての値を調べる double newMid = entry.getValue() * aFreqRank.get(entry.getKey()); if (bigger >= newMid && smaller <= newMid) { midS.add(entry.getKey()); } } int newSeed = randomnr.nextInt(midS.size()); child.putValue(value.getNumber(), new ValueDiscrete(midS.get(newSeed))); } // else break; } case INTEGER: { IssueInteger lIssueInteger = (IssueInteger) value; int bigger = ((ValueInteger) aFather .getValue(value.getNumber())).getValue(); int smaller = ((ValueInteger) aMother .getValue(value.getNumber())).getValue(); if (bigger < smaller) { int temp = bigger; bigger = smaller; smaller = temp; } int optionIndex = smaller + randomnr.nextInt(bigger - smaller + 1); child.putValue(lIssueInteger.getNumber(), new ValueInteger(optionIndex)); break; } default: { System.out.println("issue type " + value.getType() + " not supported by geneKing"); } }// switch } // for return (child); } // 突然変異を起こす Bid mutation(Bid aOriginal) { Bid mutant = new Bid(aOriginal); List genome = mutant.getIssues(); for (Issue issue : genome) { int rot = randomnr.nextInt(70); if (rot == 0) {// 値が一致したときのみ変異させる switch (issue.getType()) { case DISCRETE: { IssueDiscrete lIssueDiscrete = (IssueDiscrete) issue; int optionIndex = randomnr .nextInt(lIssueDiscrete.getNumberOfValues()); mutant.putValue(issue.getNumber(), lIssueDiscrete.getValue(optionIndex)); break; } case INTEGER: { IssueInteger lIssueInteger = (IssueInteger) issue; int optionIndex = lIssueInteger.getLowerBound() + randomnr.nextInt(lIssueInteger.getUpperBound() - lIssueInteger.getLowerBound()); mutant.putValue(lIssueInteger.getNumber(), new ValueInteger(optionIndex)); break; } case REAL: { IssueReal lIssueReal = (IssueReal) issue; int optionInd = randomnr.nextInt( lIssueReal.getNumberOfDiscretizationSteps() - 1); mutant.putValue(lIssueReal.getNumber(), new ValueReal( lIssueReal.getLowerBound() + (lIssueReal .getUpperBound() - lIssueReal.getLowerBound()) * (optionInd) / (lIssueReal .getNumberOfDiscretizationSteps()))); break; } default: { System.out.println("issue type " + issue.getType() + " not supported by geneKing"); } }// switch } // if } // for return (mutant); } ArrayList makeNextG3(ArrayList aCurrentS, ArrayList aForeignS) { ArrayList nextGeneS = new ArrayList(); int tail = aForeignS.size(); int len = 8; int start = tail - len; if (start < 0) { start = 0; } tailForeignS = new ArrayList(aForeignS.subList(start, tail)); // System.out.println("0Len="+aCurrentS.size()+" // 1Len="+aForeignS.size()+" 2Len="+tailForeignS.size()+" // start="+start+" tail="+tail); Bid lastBid = null; for (Bid alpha : aCurrentS) { for (Offer beta : tailForeignS) { for (int i = 0; i < crossNum; ++i) { // Bid child = uniformCrossOver3(alpha,beta.getBid()); Bid child = uniformCrossOver5(alpha, beta.getBid(), dFreqRankS2.get(beta.getAgent())); child = mutation(child); double util = utilitySpace.getUtility(child); // System.out.print(util+ ""); if (util > 0 && !child.equals(lastBid)) { nextGeneS.add(child); lastBid = child; } } } } // System.out.println("NextG="+nextGeneS.size()); nextGeneS = chooseEliteS3(nextGeneS, tailForeignS); // System.out.println("NextG2="+nextGeneS.size()); return (nextGeneS); } void genelogy() { if (foreignS.size() == 0) { Bid newBid = chooseBest(geneS); myLastBid = newBid; System.out.println("No foreignS!"); return; } else { ArrayList nextS = makeNextG3(geneS, foreignS); // System.out.println("NextLen="+nextS.size()); Bid newBid = chooseBest(nextS); if (myLastBid != null) { // double newEval = // utilitySpace.getUtility(newBid)*utilWaight+getAveSim(newBid,foreignS)*simWaight; double newEval = getMyEvaluation(newBid, tailForeignS); double lastEval = getMyEvaluation(myLastBid, tailForeignS); if (newEval > lastEval) { myLastBid = newBid; // System.out.println("New Best!"); } } else { myLastBid = newBid; } geneS = new ArrayList(nextS);// 全入れ替え } } private boolean isAcceptableGK() { double offeredUtil = 0.0; if (offeredBid != null) { offeredUtil = utilitySpace.getUtility(offeredBid); } double myUtil = 1.0; if (myLastBid != null) { myUtil = utilitySpace.getUtility(myLastBid); } if (offeredUtil >= myUtil - VALIANCE) {// 自分の提案以上のものか、その近くであった場合 return (true); } return (false); } private HashMap makeRank2(IssueDiscrete aIssue) { HashMap rRank = new HashMap(); List valueS = aIssue.getValues(); for (ValueDiscrete valueD : valueS) { // Integer newEval = evaluator.getValue(valueD);//評価値に直す double newEval = (double) (evaluator.getValue(valueD)) / evaluator.getEvalMax(); System.out.println("newEval=" + newEval); // Integer newEval = // EvaluatorDiscrete.this.getEvaluationNotNormalized(valueD); rRank.put(valueD.getValue(), newEval); } return (rRank); } private void makeRankS(List aIssueS) { System.out.println("Make Rank Start!"); int count = 0; for (Issue issue : aIssueS) { if (issue.getType().equals(ISSUETYPE.DISCRETE)) { try { evaluator.loadFromXML( utilitySpace.toXML().getChildElementsAsList().get(0) .getChildElementsAsList().get(count)); // evaluator.loadFromXML(issue.toXML()); // evaluator.setXML(issue.toXML()); // System.out.println("evaluator="+((EvaluatorDiscrete)evaluator).getEvalMax()); } catch (IOException e) { } // discreteRankS.put(issue.getName(), // makeRank((IssueDiscrete)issue)); dValueRankS.put(issue.getName(), makeRank2((IssueDiscrete) issue)); System.out.println("issue-N Finish!"); } // if ++count; } // for } private void initInitNum() { long candidateNum = 1; candidateNum = utilitySpace.getDomain().getNumberOfPossibleBids(); if (initNum > candidateNum) { initNum = candidateNum; } } private void initGK() { history = (StandardInfoList) getData().get(); if (!history.isEmpty()) { // example of using the history. Compute for each party the maximum // utility of the bids in last session. Map maxutils = new HashMap(); StandardInfo lastinfo = history.get(history.size() - 1); for (Tuple offered : lastinfo.getUtilities()) { String party = offered.get1(); Double util = offered.get2(); maxutils.put(party, maxutils.containsKey(party) ? Math.max(maxutils.get(party), util) : util); } System.out.println(maxutils); // notice tournament suppresses all // output. } MINIMUM_BID_UTILITY = utilitySpace.getReservationValueUndiscounted(); if (MINIMUM_BID_UTILITY < utilitySpace .getReservationValueUndiscounted()) { MINIMUM_BID_UTILITY = utilitySpace .getReservationValueUndiscounted(); } acceptableUtility = MINIMUM_BID_UTILITY; System.out.println("get issueS!"); List issueS = utilitySpace.getDomain().getIssues(); System.out.println("got issueS!"); makeRankS(issueS); System.out.println("Made Rank"); initInitNum(); geneS = getRandomBidS(); double bestUtil = 0; for (StandardInfo stdInfo : history) { Tuple agreement = stdInfo.getAgreement(); if (agreement != null) { double newUtil = (double) agreement.get2(); if (newUtil > bestUtil && newUtil > 0.7) { bestUtil = newUtil; myLastBid = (Bid) agreement.get1(); } if (newUtil > 0.7) { geneS.add((Bid) agreement.get1()); } } // System.out.println("profile="+stdInfo.getAgentProfiles()); // System.out.println("stdInfo="+stdInfo.getUtilities()); // System.out.println("agree="+stdInfo.getAgreement()); } } private String getNameGK() { return ("GeneKing"); } private double getAverageUtility() { double average = 0; for (Offer foreign : tailForeignS) { average += utilitySpace.getUtility(foreign.getBid()); } average /= tailForeignS.size(); return (average); } private Action chooseActionGK() { double time = timeline.getTime(); if (time > 0.99) {// 締め切り間近の場合 double partnerUtil = getAverageUtility(); if (partnerUtil >= acceptableUtility) { acceptableUtility = partnerUtil; } if (getAverageUtility() < MINIMUM_BID_UTILITY) { System.out.println("End Negotiation!"); return (new EndNegotiation(getPartyId())); } else if (partnerUtil >= acceptableUtility) {// 最後の提案が良かった場合 return (new Accept(getPartyId(), lastPartnerBid)); } else { genelogy(); return (new Offer(getPartyId(), myLastBid)); } } else {// まだ余裕のある場合 if (isAcceptableGK()) { return (new Accept(getPartyId(), lastPartnerBid)); } else { genelogy(); return (new Offer(getPartyId(), myLastBid)); } } } private IssueFreqRank makeFreqRank2(IssueDiscrete aIssue, ValueDiscrete aSelected) { IssueFreqRank rRank = new IssueFreqRank(aIssue.getValues(), aSelected); return (rRank); } private HashMap makeFreqRankS2(Bid aBid) { HashMap rFreqRankS = new HashMap(); List issueS = utilitySpace.getDomain().getIssues(); for (Issue issue : issueS) { if (issue.getType().equals(ISSUETYPE.DISCRETE)) {// DISCRETE型だった場合 IssueDiscrete dIssue = (IssueDiscrete) issue; rFreqRankS.put(issue.getName(), makeFreqRank2(dIssue, (ValueDiscrete) (aBid.getValue(dIssue.getNumber())))); } } return (rFreqRankS); } private void updateFreqRank2(ValueDiscrete aSelected, IssueFreqRank aRank) { aRank.addFreq(aSelected.getValue()); } void updateFreqRankS2(Bid aBid, HashMap adFreqRankS) { List issueS = utilitySpace.getDomain().getIssues(); for (Issue issue : issueS) { if (issue.getType().equals(ISSUETYPE.DISCRETE)) {// DISCRETE型だった場合 updateFreqRank2( (ValueDiscrete) (aBid.getValue(issue.getNumber())), adFreqRankS.get(issue.getName())); } } } // Offerのリストの長さをチェックし、長すぎた場合は後方のみを残す ArrayList reduceList(ArrayList aList, int aMaxSize) { ArrayList rList = new ArrayList( aList.subList(aList.size() - aMaxSize, aList.size())); return (rList); } private void ReceiveMessageGK(Action aAction) { AgentID id = aAction.getAgent(); if (aAction instanceof Offer) { offeredBid = new Bid(((Offer) aAction).getBid()); // 提案された合意案候補 foreignS.add((Offer) aAction); if (dFreqRankS2.containsKey(id)) {// 登録されていた場合 updateFreqRankS2(offeredBid, dFreqRankS2.get(id)); } else {// まだ登録されていない場合 dFreqRankS2.put(id, makeFreqRankS2(offeredBid)); } lastPartnerBid = offeredBid; // System.out.println("aAction="+offeredBid+" // len="+foreignS.size()+" "+aAction.getAgent()); } else if (aAction instanceof Accept) {// 受け入れだった場合 Bid accepted = new Bid(((Accept) aAction).getBid()); Offer accOffer = new Offer(aAction.getAgent(), accepted); foreignS.add(accOffer); if (dFreqRankS2.containsKey(id)) {// 登録されていた場合 updateFreqRankS2(accepted, dFreqRankS2.get(id)); } else {// まだ登録されていない場合 dFreqRankS2.put(id, makeFreqRankS2(accepted)); } } if (foreignS.size() > limitForeignSNum) { foreignS = reduceList(foreignS, maxForeignSNum);// 数が増えすぎたら昔のものを減らす } } @Override public void init(NegotiationInfo info) { super.init(info); System.out.println("Discount Factor is " + getUtilitySpace().getDiscountFactor()); System.out.println("Reservation Value is " + getUtilitySpace().getReservationValueUndiscounted()); MINIMUM_BID_UTILITY = getUtilitySpace() .getReservationValueUndiscounted(); initGK(); } @Override public Action chooseAction(List> validActions) { return (chooseActionGK()); } @Override public void receiveMessage(AgentID sender, Action action) { super.receiveMessage(sender, action); ReceiveMessageGK(action); } @Override public String getDescription() { return "ANAC2017"; } }