package negotiator.parties; import static java.lang.Math.E; import static java.lang.Math.max; import static java.lang.Math.pow; import java.util.List; import genius.core.AgentID; import genius.core.DeadlineType; import genius.core.Vote; import genius.core.actions.Action; import genius.core.actions.InformVotingResult; import genius.core.actions.OfferForVoting; import genius.core.actions.VoteForOfferAcceptance; import genius.core.parties.AbstractNegotiationParty; import genius.core.parties.NegotiationInfo; import genius.core.parties.NegotiationParty; import genius.core.protocol.MultilateralProtocol; /** * Implementation of a party that uses simulated annealing strategy to get to an * agreement. *

* This party should be run with {@link genius.core.protocol.MediatorProtocol} * * @author David Festen * @author Reyhan */ public class Annealer extends AbstractNegotiationParty { /** * Holds the utility value for the most recently accepted offer. */ private double lastAcceptedBidUtility; /** * Holds the utility value for the most recently received offer. */ private double lastReceivedBidUtility; /** * Holds the vote that will be done when asked for voting. */ private Vote currentVote; /** * Holds the current round number (used for cooling down the annealing). */ private int currentRound; @Override public void init(NegotiationInfo info) { super.init(info); lastAcceptedBidUtility = 0; lastReceivedBidUtility = 0; currentVote = Vote.REJECT; currentRound = 0; } /** * When this class is called, it is expected that the Party chooses one of * the actions from the possible action list and returns an instance of the * chosen action. This class is only called if this {@link NegotiationParty} * is in the * {@link negotiator.protocol .DefaultProtocol#getRoundStructure(java.util.List, negotiator.session.Session)} * . * * @param possibleActions * List of all actions possible. * @return The chosen action */ @Override public Action chooseAction(List> possibleActions) { return new VoteForOfferAcceptance(getPartyId(), currentVote); } /** * This method is called when an observable action is performed. Observable * actions are defined in * {@link MultilateralProtocol#getActionListeners(java.util.List)} * * @param sender * The initiator of the action * @param arguments * The action performed */ @Override public void receiveMessage(AgentID sender, Action arguments) { if (arguments instanceof OfferForVoting) { lastReceivedBidUtility = getUtility(((OfferForVoting) arguments).getBid()); if (lastReceivedBidUtility >= lastAcceptedBidUtility) { currentVote = Vote.ACCEPT; } else { double temperature = getNormalizedRoundOrTimeValue(); double probability = pow(E, ((lastReceivedBidUtility - lastAcceptedBidUtility) / temperature)); currentVote = probability > rand.nextDouble() ? Vote.ACCEPT : Vote.REJECT; } } else if (arguments instanceof InformVotingResult) { if (((InformVotingResult) arguments).getVotingResult() == Vote.ACCEPT) { lastAcceptedBidUtility = lastReceivedBidUtility; } currentRound++; } } /** * returns the highest of normalized time and round values * * @return a value between 0.0 and 1.0 */ private double getNormalizedRoundOrTimeValue() { // return the most urgent value return max(getNormalizedRoundValue(), getNormalizedTimeValue()); } /** * Gets the normalized current round between 0.0 and 1.0 * * @return A value between 0.0 and 1.0 or 0.0 if no round deadline given */ private double getNormalizedRoundValue() { if (getDeadlines().getType() == DeadlineType.ROUND) { return ((double) currentRound / (double) getDeadlines().getValue()); } else { return 0d; } } /** * Gets the normalized current time, which runs from 0.0 to 1.0 * * @return A value between 0.0 and 1.0 which defaults to 0.0 if no time * deadline set */ private double getNormalizedTimeValue() { return timeline == null ? 0d : timeline.getTime(); } @Override public String getDescription() { return "Annealer Party"; } }