package geniusweb.exampleparties.simpleshaop; import java.io.IOException; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.logging.Level; import javax.websocket.DeploymentException; import geniusweb.actions.Accept; import geniusweb.actions.Action; import geniusweb.actions.Comparison; import geniusweb.actions.ElicitComparison; import geniusweb.actions.EndNegotiation; import geniusweb.actions.Offer; import geniusweb.actions.PartyId; import geniusweb.bidspace.AllBidsList; import geniusweb.inform.ActionDone; import geniusweb.inform.Finished; import geniusweb.inform.Inform; import geniusweb.inform.Settings; import geniusweb.inform.YourTurn; import geniusweb.issuevalue.Bid; import geniusweb.issuevalue.Domain; import geniusweb.party.Capabilities; import geniusweb.party.DefaultParty; import geniusweb.profile.Profile; import geniusweb.profileconnection.ProfileConnectionFactory; import geniusweb.profileconnection.ProfileInterface; import geniusweb.progress.Progress; import geniusweb.progress.ProgressRounds; import tudelft.utilities.logging.Reporter; /** * This Agent work on partial preference and use the GravityAgent ( ANAC 2019 * competition ) user model to model user and use Frequency method to model our * opponent. * * @author Arash Ebrahinezhad * * Arash.ebrah@gmail.com arash.ebrah@nit.ac.ir */ public class ShaopParty extends DefaultParty { private Random rand = new Random(); private int numberOfSameConsecutiveBidInMyBids = 0; private double eCost; // Elicitation Cost private double rValue; // Reservation Value private FrequencyModel opModel; // Opponent Model private boolean myConcessionEnough = false; private GravityEs myModel2; // User Model private Bid receivedBid = null; // Last Received bid ArrayList oppBids = new ArrayList(); // All Bids that received from Opponent ArrayList myBids = new ArrayList(); // All Bids that we sent to opponent private List bidOrder; private int allBidSize; private List expectedValue; // توزیع احتمالاتی بیدهای در بین بیدهای مرتب شده // Time depending bidding strategy : boulware or conceder private double e = 0.8; private static final double k = 0; private int afterRank = 2; // How many rank after our estimation bid rank must be checked private int beforeRank = 1; // How many rank before our estimation bid rank must be checked private double agreementSimilarityThreshold; // threshold of similarity for acceptance Strategy private double opponentConcesionRate = 0.08; // our expected opponent concession rate private int howManyRankMustBeChecked = 5; // threshold of bid rank which we mast to check if Estimation rank satisfy // the condition double Pagreement; // the threshold of bid agreement by opponent we must to select ( control our // concession strategy ) //////////////////////////////////////////////////////////////////////////////////////////// private Bid reservationBid; private PartyId me; protected ProfileInterface profileint; private Progress progress; private USpace utilitySpace; private Profile profile; private Domain domain; private AllBidsList allBids; private double totalBother = 0; private SimpleLinearOrdering estimatedProfile = null; //////////////////////////////////////////////////////////////////////////////////////////// public ShaopParty() { } public ShaopParty(Reporter reporter) { super(reporter); // for debugging } private void init(Settings info) throws IOException, DeploymentException { Settings settings = info; this.profileint = ProfileConnectionFactory.create(settings.getProfile().getURI(), getReporter()); this.me = settings.getID(); this.progress = settings.getProgress(); this.profile = profileint.getProfile(); this.domain = this.profile.getDomain(); utilitySpace = new USpace(this.domain); allBids = new AllBidsList(profileint.getProfile().getDomain()); if (reservationBid != null) // if the reservation bid does not exist so we accept opponent bid with more // probability agreementSimilarityThreshold = 0.85; else agreementSimilarityThreshold = 0.7; estimatedProfile = new SimpleLinearOrdering(profile); List bOr = new ArrayList(); if (estimatedProfile.getBids().size() == 2) { // if ordered bids size equal 2, add reservation value or random // Bid bOr.add(estimatedProfile.getBids().get(0)); if (reservationBid != null && !reservationBid.equals(estimatedProfile.getBids().get(0)) && !reservationBid.equals(estimatedProfile.getBids().get(1))) bOr.add(reservationBid); else while (true) { long i = rand.nextInt(allBids.size().intValue()); Bid randBid = allBids.get(BigInteger.valueOf(i)); if (!randBid.equals(estimatedProfile.getBids().get(0)) && !randBid.equals(estimatedProfile.getBids().get(1))) { bOr.add(randBid); break; } } bOr.add(estimatedProfile.getBids().get(1)); estimatedProfile = new SimpleLinearOrdering(domain, bOr); } bidOrder = estimatedProfile.getBids(); try { // if elicitation cost is set, catch it, else set it 0.1 eCost = (double) settings.getParameters().get("elicitationcost"); } catch (Exception e) { eCost = 0.1; // if elicitation cost is not set, we set it to 0.1 } try { // if reservation Bid is set, catch it, else set it null reservationBid = profile.getReservationBid(); } catch (Exception e) { reservationBid = null; } opModel = new FrequencyModel(utilitySpace); allBidSize = allBids.size().intValue(); expectedValue = new ArrayList(); initExpectedValue(); myModel2 = new GravityEs(domain, bidOrder); // myModel = new WinkyA2(domain, bidOrder, profileint); if (reservationBid != null) // if reservation bid is set, set the reservation value to utility of it rValue = myModel2.getUtilityForBid(reservationBid); // این قسمت شاید تغییر کند else rValue = 0; } public void initExpectedValue() { for (int i = 0; i < bidOrder.size() - 1; i++) expectedValue.add(1.0 / (bidOrder.size() - 1)); } private void updateExpectedUtility() { expectedValue.clear(); for (int i = 0; i < bidOrder.size() - 1; i++) expectedValue.add(1.0 / (bidOrder.size() - 1)); } @Override public void notifyChange(Inform info) { try { if (info instanceof Settings) { init((Settings) info); } else if (info instanceof ActionDone) { Action otheract = ((ActionDone) info).getAction(); if (otheract instanceof Offer) { receivedBid = ((Offer) otheract).getBid(); opModel.updateLearner(receivedBid); } else if (otheract instanceof Comparison) { totalBother += eCost; // شاید این قسمت تغییر کند estimatedProfile = estimatedProfile.with(((Comparison) otheract).getBid(), ((Comparison) otheract).getWorse()); bidOrder = estimatedProfile.getBids(); // After each elicitation update bidOrder updateExpectedUtility(); myModel2 = myModel2.updateGravityModel(bidOrder); // After each elicitation update User Model if (reservationBid != null) rValue = myModel2.getUtilityForBid(reservationBid); // After each elicitation update reservation // value myTurn(true); } } else if (info instanceof YourTurn) { myTurn(false); } else if (info instanceof Finished) { getReporter().log(Level.INFO, "Final ourcome:" + info); } } catch (Exception e) { throw new RuntimeException("Failed to handle info", e); } } @Override public Capabilities getCapabilities() { return new Capabilities(new HashSet<>(Arrays.asList("SHAOP")), Collections.singleton(Profile.class)); } @Override public String getDescription() { return "Azar Agent ANAC 2020"; } /** * Called when it's (still) our turn and we should take some action. Also * Updates the progress if necessary. */ void myTurn(boolean elicitation) throws IOException { Action action = null; if (!elicitation && !myConcessionEnough) { double t = progress.get(System.currentTimeMillis()); Pagreement = getPagreement(t); } // Elicitation Strategy and Bidding Strategy // log2("--------------------------------------------------------------------"+Pagreement); MyBidDetails bidDetail = null; if (totalBother < 0.6 /* 1-rValue */ ) { // تا زمانی که به مقدار رزرویشن نرسیدیم، الیسیتیشن رو ادامه بده bidDetail = getBestBidInKnownSet(Pagreement, elicitation); MyBidDetails bidDetailPrim = getBestBidInUnKnownSet(Pagreement); // Only for log!!! // String s = " Is this ("+bidDetailPrim.getEu()+" - "+eCost+" > // "+bidDetail.getEu() + ") True?"; // s +=( (bidDetailPrim.getEu() - eCost > bidDetail.getEu()) ) ? " True => // Elicit" : " False => not Elicit"; // log2( s ); if (bidDetailPrim.getEu() - eCost > bidDetail.getEu()) action = new ElicitComparison(me, bidDetailPrim.getBid(), estimatedProfile.getBids()); } else { // log2("Elicitation total bother is more than 0.6 !!!"); } // log2("----------------------------------------------------------------------\n\n"); if (bidDetail == null) { if (reservationBid != null) bidDetail = new MyBidDetails(reservationBid, 0.5); else if (bidOrder.size() > 10) bidDetail = new MyBidDetails(bidOrder.get(bidOrder.size() / 2), 1.0); else bidDetail = new MyBidDetails(bidOrder.get(bidOrder.size() - 1), 1.0); } if (action == null && receivedBid != null) { if (isGood(receivedBid, bidDetail.getBid())) action = new Accept(me, receivedBid); if (progress instanceof ProgressRounds) progress = ((ProgressRounds) progress).advance(); } if (action == null) { Bid myBid = bidDetail.getBid(); if (myModel2.getUtilityForBid(myBid) > rValue) { if (myBids.isEmpty()) myBids.add(myBid); if (!myBids.contains(myBid)) myBids.add(myBid); if (myBids.size() > 1) if (myBids.get(myBids.size() - 1).equals(myBids.get(myBids.size() - 2))) numberOfSameConsecutiveBidInMyBids++; else numberOfSameConsecutiveBidInMyBids = 0; action = new Offer(me, myBid); } else action = new EndNegotiation(me); } getConnection().send(action); } // *************************************************************************************** /** * Acceptance Strategy * * @param reBid the last received bid from opponent * * @param nextBid the next bid that we prepare to send to opponent * * @return true if we must accept opponent offer and false vice versa */ private boolean isGood(Bid reBid, Bid nextBid) { if (oppBids.isEmpty() || !oppBids.contains(reBid)) // اگر این بید را قبلا دریافت نکرده باشیم اضافه کن oppBids.add(reBid); if (myModel2.getUtilityForBid(reBid) < rValue) return false; if (reBid.equals(nextBid)) return true; if (myBids.contains(reBid)) return true; if (myModel2.getUtilityForBid(reBid) >= myModel2.getUtilityForBid(nextBid)) return true; for (Bid b : myBids) if (myModel2.getUtilityForBid(reBid) >= myModel2.getUtilityForBid(b) + 0.07) return true; double currentAgreementSimilarityThreshold = ((1 - Pagreement) > agreementSimilarityThreshold) ? (1 - Pagreement) : agreementSimilarityThreshold; return (getAcceptanceProbability(reBid, nextBid) > currentAgreementSimilarityThreshold ? true : false) && myModel2.getUtilityForBid(reBid) > rValue; } /** * * @param reBid Last Received Bid From Opponent * @param nextBid the next bid that we prepare send to opponent * * @return double value that determine maximum similarity (1-distance) value of * received bid from opponent to our sent bids */ private double getAcceptanceProbability(Bid reBid, Bid nextBid) { double t = Double.MAX_VALUE; double reBidU = myModel2.getUtilityForBid(reBid); // for ( Bid b : oppBids ) { for (Bid b : myBids) { double temp = 1 - Math.abs(myModel2.getUtilityForBid(b) - reBidU); if (temp < t) { t = temp; } } double nextBidU = myModel2.getUtilityForBid(nextBid); if ((1 - Math.abs(nextBidU - reBidU)) < t) return (1 - Math.abs(nextBidU - reBidU)); return t; } /** * * @param the Agreement probability of the bid that we want decide about its * elicitation must be more than it. * * @return the best bid and its utility (MyBidDetails object) in the set of bids * which we know about its order. */ private MyBidDetails getBestBidInKnownSet(double Pagreement1, boolean elicitation) { for (int i = bidOrder.size() - 1; i > 0; i--) { double Pat = getAgreementProbability(bidOrder.get(i)); if (Pat >= Pagreement1 && myModel2.getUtilityForBid(bidOrder.get(i)) > myModel2.getUtilityForBid(bidOrder.get(i)) / 2) { if (myBids.size() > 1) if (myModel2.getUtilityForBid(myBids.get(myBids.size() - 1)) - myModel2.getUtilityForBid(bidOrder.get(i)) > 0.3) if (myModel2.getUtilityForBid(bidOrder.get(i)) - 0.3 > 0) return new MyBidDetails(bidOrder.get(i), myModel2.getUtilityForBid(bidOrder.get(i)) - 0.3); else return new MyBidDetails(null, 0.0); return new MyBidDetails(bidOrder.get(i), myModel2.getUtilityForBid(bidOrder.get(i))); } } return new MyBidDetails(null, 0.0); /* * if ( myBids.size() > 0 ) { * * if( myModel2.getUtilityForBid( myBids.get( myBids.size()-1 * ))-(numberOfSameConsecutiveBidInMyBids*0.1) > 0 ) return new * MyBidDetails(myBids.get( myBids.size()-1 ), myModel2.getUtilityForBid( * myBids.get( myBids.size()-1 ))-(numberOfSameConsecutiveBidInMyBids*0.1) ); * else return new MyBidDetails(myBids.get( myBids.size()-1 ), 0.0 ); * * } else return new MyBidDetails(bidOrder.get( bidOrder.size()-1 ), * myModel2.getUtilityForBid( bidOrder.get( bidOrder.size()-1 )) ); */ } /** * * @param Pagreement2 the Agreement probability of the bid that we want decide * about its elicitation must be more than it. * * @return the best bid in the bids set that we don't know about their orders * respect to if we would elicit it. */ private MyBidDetails getBestBidInUnKnownSet(double Pagreement2) { /* * for decrease the size of variety Check the probabilities we check only bids * with high estimation rank and high utility */ int estimateBidRank = 0; double EEu = 0; Bid bestBid = null; for (Bid bid : allBids) { if (!bidOrder.contains(bid)) { double Pat = getAgreementProbability(bid); if (Pat > Pagreement2 /* && myModel2.getUtilityForBid(bid) > bidThreshold */ ) { estimateBidRank = getEstimateBidRank(bid); if (estimateBidRank >= (bidOrder.size() - 1) - howManyRankMustBeChecked) { double tempEu = getNewEu(estimateBidRank, bid); double tempEEu = tempEu/* Pat */; if (tempEEu > EEu) { EEu = tempEEu; bestBid = bid; } } } } } if (bestBid != null) return new MyBidDetails(bestBid, EEu); else return new MyBidDetails(null, 0.0); } /** * * @param bid the bid we want estimate about its bid rank with our current * knowledge * @return estimated bid rank */ private int getEstimateBidRank(Bid bid) { double tempU = myModel2.getUtilityForBid(bid); int rank = 0; for (Bid b : bidOrder) { double bU = myModel2.getUtilityForBid(b); if (tempU <= bU) { break; } else rank++; } if (rank == 0) rank = 1; return rank; } /** * * @param rank the rank of the bid that we estimate with current knowledge * @param bid the bid which we want estimate its utility if it is elicited * @return the our expected utility of bid that if we would elicite it */ private double getNewEu(int rank, Bid bid) { expectedValue.clear(); expectedValue = getNewExpectedValue(rank); double newEU = 0; int bidOrderSize2 = bidOrder.size(); if (rank == bidOrderSize2 - 1) return myModel2.getUtilityForBid(bid); int aJ = 0; for (int j = rank; j <= Integer.min(rank + afterRank, bidOrderSize2 - 1); j++) { // ما بعد List bidOrderProbability2 = new ArrayList(); for (Bid b : bidOrder) bidOrderProbability2.add(b); double probabilityBelong = expectedValue.get(j - 1);// *bidOrderSize2; bidOrderProbability2.add(j, bid); GravityEs modelProbability2 = new GravityEs(domain, bidOrderProbability2); newEU += probabilityBelong * (modelProbability2.getUtilityForBid(bid)); aJ++; } if (rank > 1) { for (int j = rank - 1; j > Integer.min(Integer.max(0, aJ - 1), Integer.max(0, rank - beforeRank)); j--) { // ما // قبل List bidOrderProbability1 = new ArrayList(); for (Bid b : bidOrder) bidOrderProbability1.add(b); double probabilityBelong = expectedValue.get(j - 1);// *bidOrderSize2; bidOrderProbability1.add(j, bid); GravityEs modelProbability1 = new GravityEs(domain, bidOrderProbability1); newEU += probabilityBelong * (modelProbability1.getUtilityForBid(bid)); } } return newEU; } /** * * @param rank the rank of the bid that we estimate with current knowledge * @return probability distribution of bid in variety ranks, that we want decide * about its elicitation */ private List getNewExpectedValue(int rank) { double certainty = (double) bidOrder.size() / allBidSize; List expectedValue = new ArrayList(); for (int i = 0; i < bidOrder.size(); i++) expectedValue.add(1.0 / (bidOrder.size() - 1)); double temp1 = expectedValue.size(); for (int i = rank; i > 0; i--) { double ttemp = expectedValue.get(i - 1); expectedValue.remove(i - 1); expectedValue.add(i - 1, (temp1 * certainty) + ttemp); temp1--; } double temp2 = expectedValue.size() - 1; for (int i = rank + 1; i <= expectedValue.size(); i++) { double ttemp = expectedValue.get(i - 1); expectedValue.remove(i - 1); expectedValue.add(i - 1, (temp2 * certainty) + ttemp); temp2--; } double n = 0; for (double t : expectedValue) n += t; for (int i = 0; i < expectedValue.size(); i++) { double tTemp = expectedValue.get(i); expectedValue.remove(i); expectedValue.add(i, tTemp / n); } return expectedValue; } private double f(double t) { if (e == 0) return k; double ft = k + (1 - k) * Math.pow(t, 1 / e); return ft; } /** * * @param t Time (if we want use time for compute concession rate) * @return double value that the agent must be found a bid that has Agreement * Probability more than it. */ private double getPagreement(double t) { // if ( reservationBid != null || t <= 0.7 ) return Pagreement + 0.01; // else // return Pagreement+0.01; // 0.02 // return 1 - ( myEstimateMin + (myEstimateMax - myEstimateMin) * (1 - f(t)) ); } /** * * Opponent Model * * @param bid the bid want to know its agreement probability with opponent * * @return double value which determine opponent agreement probability of the * bid * */ private double getAgreementProbability(Bid bid) { if (oppBids.isEmpty()) { // if we don't got any bid from opponent return 1.0; } if (myBids.contains(bid)) { // if we sent this bid before return opponentConcesionRate * progress.get(System.currentTimeMillis()); } if (oppBids.contains(bid)) { // if this bid is one of previous bids that we got from opponent return 1.0; } double t = Double.MAX_VALUE; for (Bid b : oppBids) { double temp = 1 - Math.abs(opModel.getOpponentUtilitySpace().getUtility(b) - opModel.getOpponentUtilitySpace().getUtility(bid)); if (temp < t) { t = temp; } } return t; } // ********************************************************** // ********************************************************** // ********************************************************** // *********************** Test ************************* // ********************************************************** // ********************************************************** // ********************************************************** private void log(Object o) { System.err.println(o); } private void log2(Object o) { System.out.println(o); } }