Ignore:
Timestamp:
10/08/20 10:17:25 (4 years ago)
Author:
bart
Message:

MOPAC support for timedependentparty, boulware, conceder, hardliner, linear

Location:
exampleparties/timedependentparty/src
Files:
2 added
2 edited

Legend:

Unmodified
Added
Removed
  • exampleparties/timedependentparty/src/main/java/geniusweb/exampleparties/timedependentparty/TimeDependentParty.java

    r24 r25  
    44import java.math.BigDecimal;
    55import java.math.BigInteger;
     6import java.math.RoundingMode;
    67import java.util.Arrays;
    78import java.util.HashSet;
     9import java.util.List;
    810import java.util.Random;
    911import java.util.logging.Level;
     12import java.util.stream.Collectors;
    1013
    1114import geniusweb.actions.Accept;
     
    1316import geniusweb.actions.Offer;
    1417import geniusweb.actions.PartyId;
     18import geniusweb.actions.Vote;
     19import geniusweb.actions.Votes;
    1520import geniusweb.inform.ActionDone;
    1621import geniusweb.inform.Finished;
    1722import geniusweb.inform.Inform;
     23import geniusweb.inform.OptIn;
    1824import geniusweb.inform.Settings;
     25import geniusweb.inform.Voting;
    1926import geniusweb.inform.YourTurn;
    2027import geniusweb.issuevalue.Bid;
     
    2330import geniusweb.profile.Profile;
    2431import geniusweb.profile.utilityspace.LinearAdditive;
     32import geniusweb.profile.utilityspace.UtilitySpace;
    2533import geniusweb.profileconnection.ProfileConnectionFactory;
    2634import geniusweb.profileconnection.ProfileInterface;
     
    3543 * 2^31 (approx 1 billion bids). It may take excessive time and run out of time
    3644 * on bidspaces > 10000 bids. In special cases it may even run out of memory,
     45 *
     46 * <p>
     47 * Supports parameters as follows
     48 * <table summary="parameters">
     49 * <tr>
     50 * <td>e</td>
     51 * <td>e determines how fast the party makes concessions with time. Typically
     52 * around 1. 0 means no concession, 1 linear concession, &gt;1 faster than
     53 * linear concession.</td>
     54 * </tr>
     55 *
     56 * <tr>
     57 * <td>minPower</td>
     58 * <td>This value is used as minPower for placed {@link Vote}s. Default value is
     59 * 1.</td>
     60 * </tr>
     61 *
     62 * <tr>
     63 * <td>maxPower</td>
     64 * <td>This value is used as maxPower for placed {@link Vote}s. Default value is
     65 * infinity.</td>
     66 * </tr>
     67 *
     68 * </table>
     69 * <p>
     70 * TimeDependentParty requires a {@link UtilitySpace}
    3771 */
    3872public class TimeDependentParty extends DefaultParty {
    3973
    40         private static final BigDecimal DEC0001 = new BigDecimal("0.0001");
    41         private static final BigDecimal DEC100 = new BigDecimal("100");
    4274        private ProfileInterface profileint;
    4375        private LinearAdditive utilspace = null; // last received space
     
    4779        private ExtendedUtilSpace extendedspace;
    4880        private double e = 1.2;
     81        private Votes lastvotes;
     82        private Settings settings;
    4983
    5084        public TimeDependentParty() {
     
    5892        @Override
    5993        public Capabilities getCapabilities() {
    60                 return new Capabilities(new HashSet<>(Arrays.asList("SAOP")));
     94                return new Capabilities(new HashSet<>(Arrays.asList("SAOP", "MOPAC")));
    6195        }
    6296
     
    6599                try {
    66100                        if (info instanceof Settings) {
    67                                 Settings settings = (Settings) info;
     101                                settings = (Settings) info;
    68102                                this.profileint = ProfileConnectionFactory
    69103                                                .create(settings.getProfile().getURI(), getReporter());
     
    80114                                        }
    81115                                }
    82 
    83116                        } else if (info instanceof ActionDone) {
    84117                                Action otheract = ((ActionDone) info).getAction();
     
    88121                        } else if (info instanceof YourTurn) {
    89122                                myTurn();
    90                                 if (progress instanceof ProgressRounds) {
    91                                         progress = ((ProgressRounds) progress).advance();
    92                                 }
    93123                        } else if (info instanceof Finished) {
    94124                                getReporter().log(Level.INFO, "Final ourcome:" + info);
     125                        } else if (info instanceof Voting) {
     126                                lastvotes = vote((Voting) info);
     127                                getConnection().send(lastvotes);
     128                        } else if (info instanceof OptIn) {
     129                                getConnection().send(lastvotes);
    95130                        }
    96                 } catch (Exception e) {
    97                         getReporter().log(Level.SEVERE, "Failed to handle info", e);
    98                 }
     131                } catch (Exception ex) {
     132                        getReporter().log(Level.SEVERE, "Failed to handle info", ex);
     133                }
     134                updateRound(info);
    99135        }
    100136
     
    119155        }
    120156
     157        @Override
     158        public String getDescription() {
     159                return "Time-dependent conceder. Aims at utility u(t) = scale * t^(1/e) "
     160                                + "where t is the time (0=start, 1=end), e is the concession speed parameter (default 1.1), and scale such that u(0)=minimum and "
     161                                + "u(1) = maximum possible utility. Parameters minPower (default 1) and maxPower (default infinity) are used "
     162                                + "when voting";
     163        }
     164
    121165        /******************* private support funcs ************************/
     166
     167        /**
     168         * Update {@link #progress}, depending on the protocol and last received
     169         * {@link Inform}
     170         *
     171         * @param info the received info.
     172         */
     173        private void updateRound(Inform info) {
     174                if (settings == null) // not yet initialized
     175                        return;
     176                String protocol = settings.getProtocol().getURI().getPath();
     177
     178                switch (protocol) {
     179                case "SAOP":
     180                case "SHAOP":
     181                        if (!(info instanceof YourTurn))
     182                                return;
     183                        break;
     184                case "MOPAC":
     185                        if (!(info instanceof OptIn))
     186                                return;
     187                        break;
     188                default:
     189                        return;
     190                }
     191                // if we get here, round must be increased.
     192                if (progress instanceof ProgressRounds) {
     193                        progress = ((ProgressRounds) progress).advance();
     194                }
     195
     196        }
    122197
    123198        private void myTurn() throws IOException {
     
    153228        private Bid makeBid() {
    154229                double time = progress.get(System.currentTimeMillis());
    155                 BigDecimal utilityGoal = utilityGoal(time, getE());
     230
     231                BigDecimal utilityGoal = getUtilityGoal(time, getE(),
     232                                extendedspace.getMin(), extendedspace.getMax());
    156233                ImmutableList<Bid> options = extendedspace.getBids(utilityGoal);
    157234                if (options.size() == BigInteger.ZERO) {
     
    166243        /**
    167244         *
    168          * @param t the time in [0,1] where 0 means start of nego and 1 the end of
    169          *          nego (absolute time/round limit)
    170          * @param e the e value
     245         * @param t       the time in [0,1] where 0 means start of nego and 1 the
     246         *                end of nego (absolute time/round limit)
     247         * @param e       the e value that determinses how fast the party makes
     248         *                concessions with time. Typically around 1. 0 means no
     249         *                concession, 1 linear concession, &gt;1 faster than linear
     250         *                concession.
     251         * @param minUtil the minimum utility possible in our profile
     252         * @param maxUtil the maximum utility possible in our profile
    171253         * @return the utility goal for this time and e value
    172254         */
    173         private BigDecimal utilityGoal(double t, double e) {
    174                 BigDecimal minUtil = extendedspace.getMin();
    175                 BigDecimal maxUtil = extendedspace.getMax();
    176 
    177                 double ft = 0;
     255        protected BigDecimal getUtilityGoal(double t, double e, BigDecimal minUtil,
     256                        BigDecimal maxUtil) {
     257
     258                BigDecimal ft1 = BigDecimal.ONE;
    178259                if (e != 0)
    179                         ft = Math.pow(t, 1 / e);
    180                 // we subtract epsilon to correct possibly small round-up errors
    181                 return new BigDecimal(minUtil.doubleValue()
    182                                 + (maxUtil.doubleValue() - minUtil.doubleValue()) * (1 - ft))
    183                                                 .min(maxUtil).max(minUtil);
    184         }
    185 
    186         @Override
    187         public String getDescription() {
    188                 return "Time-dependent conceder. Aims at utility u(t) = scale * t^(1/e) "
    189                                 + "where t is the time (0=start, 1=end), e is a parameter (default 1.1), and scale such that u(0)=minimum and "
    190                                 + "u(1) = maximum possible utility. ";
     260                        ft1 = BigDecimal.valueOf(1 - Math.pow(t, 1 / e)).setScale(6,
     261                                        RoundingMode.HALF_UP);
     262                return minUtil.add((maxUtil.subtract(minUtil).multiply(ft1)))
     263                                .min(maxUtil).max(minUtil);
     264        }
     265
     266        /**
     267         * @param voting the {@link Voting} object containing the options
     268         *
     269         * @return our next Votes.
     270         */
     271        private Votes vote(Voting voting) throws IOException {
     272                Object val = settings.getParameters().get("minPower");
     273                // max utility requires smallest possible group/power
     274                Integer minpower = (val instanceof Integer) ? (Integer) val : 1;
     275                val = settings.getParameters().get("maxPower");
     276                Integer maxpower = (val instanceof Integer) ? (Integer) val
     277                                : Integer.MAX_VALUE;
     278
     279                List<Vote> votes = voting.getBids().stream().distinct()
     280                                .filter(bid -> isGood(bid))
     281                                .map(bid -> new Vote(me, bid, minpower, maxpower))
     282                                .collect(Collectors.toList());
     283                return new Votes(me, votes);
     284        }
     285
     286        /**
     287         * @param bid the bid to check
     288         * @return true iff bid is good for us.
     289         */
     290        private boolean isGood(Bid bid) {
     291                if (bid == null || profileint == null)
     292                        return false;
     293                Profile profile;
     294                try {
     295                        profile = profileint.getProfile();
     296                } catch (IOException ex) {
     297                        throw new IllegalStateException(ex);
     298                }
     299                // the profile MUST contain UtilitySpace
     300                double time = progress.get(System.currentTimeMillis());
     301                return ((UtilitySpace) profile).getUtility(bid)
     302                                .compareTo(getUtilityGoal(time, getE(), extendedspace.getMin(),
     303                                                extendedspace.getMax())) >= 0;
     304
    191305        }
    192306}
  • exampleparties/timedependentparty/src/test/java/geniusweb/exampleparties/timedependentparty/TimeDependentPartyTest.java

    r24 r25  
    1717import java.nio.file.Files;
    1818import java.nio.file.Paths;
    19 import java.util.LinkedList;
    20 import java.util.List;
    2119import java.util.logging.Level;
    2220
     
    2927
    3028import geniusweb.actions.Accept;
    31 import geniusweb.actions.Action;
    3229import geniusweb.actions.EndNegotiation;
    3330import geniusweb.actions.Offer;
    3431import geniusweb.actions.PartyId;
    3532import geniusweb.bidspace.AllBidsList;
    36 import geniusweb.connection.ConnectionEnd;
    3733import geniusweb.inform.ActionDone;
    3834import geniusweb.inform.Agreements;
    3935import geniusweb.inform.Finished;
    40 import geniusweb.inform.Inform;
    4136import geniusweb.inform.Settings;
    4237import geniusweb.inform.YourTurn;
     
    4944import geniusweb.references.ProfileRef;
    5045import geniusweb.references.ProtocolRef;
    51 import geniusweb.references.Reference;
    52 import tudelft.utilities.listener.DefaultListenable;
    5346import tudelft.utilities.logging.Reporter;
    5447
     
    6255        private TimeDependentParty party;
    6356        private TestConnection connection = new TestConnection();
    64         private ProtocolRef protocol = mock(ProtocolRef.class);
     57        private ProtocolRef protocol = new ProtocolRef("SAOP");
    6558        private ProgressRounds progress = mock(ProgressRounds.class);
    6659        private Parameters parameters = new Parameters();
     
    113106        public void testInformConnection() {
    114107                party.connect(connection);
    115                 // agent should not start acting just after an inform
     108                // Party should not start acting just after an inform
    116109                assertEquals(0, connection.getActions().size());
    117110        }
     
    143136
    144137        @Test
    145         public void testAgentHasFirstTurn() {
     138        public void testPartyHasFirstTurn() {
    146139                party.connect(connection);
    147140                party.notifyChange(settings);
     
    153146
    154147        @Test
    155         public void testAgentAccepts() {
     148        public void testPartyAccepts() {
    156149                party.connect(connection);
    157150                party.notifyChange(settings);
     
    166159
    167160        @Test
    168         public void testAgentLogsFinal() {
     161        public void testPartyLogsFinal() {
    169162                // this log output is optional, this is to show how to check log
    170163                Reporter reporter = mock(Reporter.class);
     
    193186
    194187        @Test
    195         public void testAgentsUpdatesProgress() {
     188        public void testPartysUpdatesProgress() {
    196189                party.connect(connection);
    197190                party.notifyChange(settings);
     
    204197        public void testGetCapabilities() {
    205198                assertTrue(party.getCapabilities().getBehaviours().contains(SAOP));
     199        }
     200
     201        @Test
     202        public void testUtilityTarget() {
     203                TimeDependentParty tdp = new TimeDependentParty();
     204                BigDecimal N02 = new BigDecimal("0.2");
     205                BigDecimal N043 = new BigDecimal("0.42521212");
     206                BigDecimal goal = tdp.getUtilityGoal(0.1, 1.2, N02, N043);
     207                assertTrue(goal.compareTo(N02) > 0);
     208                assertTrue(goal.compareTo(N043) < 0);
    206209        }
    207210
     
    220223
    221224}
    222 
    223 /**
    224  * A "real" connection object, because the party is going to subscribe etc, and
    225  * without a real connection we would have to do a lot of mocks that would make
    226  * the test very hard to read.
    227  *
    228  */
    229 class TestConnection extends DefaultListenable<Inform>
    230                 implements ConnectionEnd<Inform, Action> {
    231         private List<Action> actions = new LinkedList<>();
    232 
    233         @Override
    234         public void send(Action action) throws IOException {
    235                 actions.add(action);
    236         }
    237 
    238         @Override
    239         public Reference getReference() {
    240                 return null;
    241         }
    242 
    243         @Override
    244         public URI getRemoteURI() {
    245                 return null;
    246         }
    247 
    248         @Override
    249         public void close() {
    250 
    251         }
    252 
    253         @Override
    254         public Error getError() {
    255                 return null;
    256         }
    257 
    258         public List<Action> getActions() {
    259                 return actions;
    260         }
    261 
    262 }
Note: See TracChangeset for help on using the changeset viewer.