From afab4a803c467df4206fcf8e5888804745fb537f Mon Sep 17 00:00:00 2001 From: Rinde van Lon Date: Wed, 16 Nov 2016 13:36:30 +0100 Subject: [PATCH] added AuctionTimeStatsLogger, some refactoring --- pom.xml | 2 +- .../mas/comm/AuctionTimeStatsLogger.java | 118 ++++++++++++++++++ .../pdptw/mas/comm/RtSolverBidder.java | 33 ++++- .../optaplanner/OptaplannerSolvers.java | 74 +---------- 4 files changed, 152 insertions(+), 75 deletions(-) create mode 100644 src/main/java/com/github/rinde/logistics/pdptw/mas/comm/AuctionTimeStatsLogger.java diff --git a/pom.xml b/pom.xml index 52d2d64..bd39b2f 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 4.2.0 + 4.3.0-SNAPSHOT java 1.0.0 diff --git a/src/main/java/com/github/rinde/logistics/pdptw/mas/comm/AuctionTimeStatsLogger.java b/src/main/java/com/github/rinde/logistics/pdptw/mas/comm/AuctionTimeStatsLogger.java new file mode 100644 index 0000000..0d886f9 --- /dev/null +++ b/src/main/java/com/github/rinde/logistics/pdptw/mas/comm/AuctionTimeStatsLogger.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2011-2016 Rinde van Lon, iMinds-DistriNet, KU Leuven + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.rinde.logistics.pdptw.mas.comm; + +import java.util.ArrayList; +import java.util.List; + +import com.github.rinde.logistics.pdptw.mas.comm.AuctionCommModel.AuctionEvent; +import com.github.rinde.rinsim.central.Measurable; +import com.github.rinde.rinsim.central.SolverTimeMeasurement; +import com.github.rinde.rinsim.core.model.DependencyProvider; +import com.github.rinde.rinsim.core.model.Model.AbstractModel; +import com.github.rinde.rinsim.core.model.ModelBuilder.AbstractModelBuilder; +import com.github.rinde.rinsim.event.Event; +import com.github.rinde.rinsim.event.Listener; +import com.google.auto.value.AutoValue; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableListMultimap; +import com.google.common.collect.ListMultimap; + +/** + * Utility for keeping track of auction related statistics. To use it, simply + * add {@link #builder()} to a simulation configuration. The statistics that are + * tracked are all finished {@link AuctionEvent}s and using + * {@link #getTimeMeasurements()} all time measurements can be collected. + * @author Rinde van Lon + */ +public class AuctionTimeStatsLogger extends AbstractModel> { + final List finishEvents; + private final List> bidders; + + AuctionTimeStatsLogger(AuctionCommModel model) { + finishEvents = new ArrayList<>(); + bidders = new ArrayList<>(); + + model.getEventAPI().addListener(new Listener() { + @Override + public void handleEvent(Event e) { + finishEvents.add((AuctionEvent) e); + } + }, AuctionCommModel.EventType.FINISH_AUCTION); + } + + /** + * @return A multimap of {@link Bidder}s to {@link SolverTimeMeasurement}s. + */ + public ImmutableListMultimap, SolverTimeMeasurement> getTimeMeasurements() { + final ListMultimap, SolverTimeMeasurement> map = + ArrayListMultimap.create(); + for (final Bidder b : bidders) { + if (b instanceof Measurable) { + map.putAll(b, ((Measurable) b).getTimeMeasurements()); + } + } + return ImmutableListMultimap.copyOf(map); + } + + /** + * @return All auction finish events that have occured so far. + */ + public ImmutableList getAuctionFinishEvents() { + return ImmutableList.copyOf(finishEvents); + } + + @Override + public boolean register(Bidder element) { + bidders.add(element); + return true; + } + + @Override + public boolean unregister(Bidder element) { + return false; + } + + /** + * @return {@link Builder} for {@link AuctionTimeStatsLogger}. + */ + public static Builder builder() { + return new AutoValue_AuctionTimeStatsLogger_Builder(); + } + + /** + * Builder for {@link AuctionTimeStatsLogger}. + * @author Rinde van Lon + */ + @AutoValue + public abstract static class Builder + extends AbstractModelBuilder> { + + private static final long serialVersionUID = 5417079781123182630L; + + Builder() { + setDependencies(AuctionCommModel.class); + } + + @Override + public AuctionTimeStatsLogger build(DependencyProvider dependencyProvider) { + return new AuctionTimeStatsLogger( + dependencyProvider.get(AuctionCommModel.class)); + } + } + +} diff --git a/src/main/java/com/github/rinde/logistics/pdptw/mas/comm/RtSolverBidder.java b/src/main/java/com/github/rinde/logistics/pdptw/mas/comm/RtSolverBidder.java index d54222d..761f0dd 100644 --- a/src/main/java/com/github/rinde/logistics/pdptw/mas/comm/RtSolverBidder.java +++ b/src/main/java/com/github/rinde/logistics/pdptw/mas/comm/RtSolverBidder.java @@ -30,12 +30,15 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import javax.annotation.CheckReturnValue; import javax.annotation.Nullable; import com.github.rinde.logistics.pdptw.mas.Truck; import com.github.rinde.rinsim.central.GlobalStateObject; +import com.github.rinde.rinsim.central.Measurable; import com.github.rinde.rinsim.central.SimSolverBuilder; import com.github.rinde.rinsim.central.Solver; +import com.github.rinde.rinsim.central.SolverTimeMeasurement; import com.github.rinde.rinsim.central.SolverUser; import com.github.rinde.rinsim.central.Solvers; import com.github.rinde.rinsim.central.Solvers.SolveArgs; @@ -70,7 +73,7 @@ */ public class RtSolverBidder extends AbstractBidder - implements RtSolverUser, TickListener { + implements RtSolverUser, TickListener, Measurable { // 5 minutes private static final long MAX_LOSING_TIME = 5 * 60 * 1000; @@ -420,6 +423,15 @@ public void setSolverProvider(RtSimSolverBuilder builder) { .build(solver)); } + @Override + public List getTimeMeasurements() { + if (getSolver() instanceof Measurable) { + return ((Measurable) getSolver()).getTimeMeasurements(); + } + throw new IllegalStateException( + "Solver " + getSolver() + " is not measurable."); + } + public static Builder realtimeBuilder(ObjectiveFunction objFunc, StochasticSupplier solverSupplier) { return Builder.createRt(solverSupplier, objFunc); @@ -484,7 +496,7 @@ static CallForBids create(Auctioneer auctioneer, Parcel parcel, public abstract static class Builder implements StochasticSupplier> { static final BidFunction DEFAULT_BID_FUNCTION = BidFunctions.PLAIN; - static final long DEFAULT_COOLDOWN_VALUE = -1L; + static final long DEFAULT_COOLDOWN_VALUE = 0L; Builder() {} @@ -502,6 +514,7 @@ public abstract static class Builder @Nullable abstract StochasticSupplier getStSolverSupplier(); + @CheckReturnValue public Builder withBidFunction(BidFunction bidFunction) { return create( getObjectiveFunction(), @@ -511,7 +524,21 @@ public Builder withBidFunction(BidFunction bidFunction) { getStSolverSupplier()); } + /** + * Set the reauction cooldown period. An unsuccessful reauction is defined + * as the event where a bidder wins its own reauction, meaning that the + * parcel allocation remains unchanged. The reauction cooldown period is + * defined as the time that a bidder is not allowed to start a new reauction + * for a parcel that was previously reauctioned unsuccessful. This is to + * avoid bidders to flood the system with reauctions that are doomed to + * fail. + * @param periodMs The cooldown period in milliseconds, cannot be negative. + * @return A new {@link Builder} instance with the new period. + */ + @CheckReturnValue public Builder withReauctionCooldownPeriod(long periodMs) { + checkArgument(periodMs >= 0L, + "A negative cooldown period is not allowed."); return create( getObjectiveFunction(), getBidFunction(), @@ -520,6 +547,7 @@ public Builder withReauctionCooldownPeriod(long periodMs) { getStSolverSupplier()); } + @SuppressWarnings("null") @Override public Bidder get(long seed) { if (getRtSolverSupplier() != null) { @@ -604,4 +632,5 @@ public String toString() { + "}"; } } + } diff --git a/src/main/java/com/github/rinde/logistics/pdptw/solver/optaplanner/OptaplannerSolvers.java b/src/main/java/com/github/rinde/logistics/pdptw/solver/optaplanner/OptaplannerSolvers.java index cdeab24..7586118 100644 --- a/src/main/java/com/github/rinde/logistics/pdptw/solver/optaplanner/OptaplannerSolvers.java +++ b/src/main/java/com/github/rinde/logistics/pdptw/solver/optaplanner/OptaplannerSolvers.java @@ -68,11 +68,11 @@ import com.github.rinde.logistics.pdptw.solver.optaplanner.ParcelVisit.VisitType; import com.github.rinde.rinsim.central.GlobalStateObject; import com.github.rinde.rinsim.central.GlobalStateObject.VehicleStateObject; +import com.github.rinde.rinsim.central.MeasureableSolver; import com.github.rinde.rinsim.central.Solver; +import com.github.rinde.rinsim.central.SolverTimeMeasurement; import com.github.rinde.rinsim.central.SolverValidator; import com.github.rinde.rinsim.central.Solvers; -import com.github.rinde.rinsim.central.Solvers.MeasureableSolver; -import com.github.rinde.rinsim.central.Solvers.SolverTimeMeasurement; import com.github.rinde.rinsim.central.rt.MeasurableRealtimeSolver; import com.github.rinde.rinsim.central.rt.RealtimeSolver; import com.github.rinde.rinsim.central.rt.Scheduler; @@ -551,76 +551,6 @@ static String resourceToString(String resourcePath) { } } - // FIXME factory should be merged with builder as they are conceptually very - // similar (but not exactly the same). - /** - * Factory for instantiating Optaplanner solvers. See - * {@link OptaplannerSolvers#getFactoryFromBenchmark(String)} for obtaining an - * instance. - * @author Rinde van Lon - */ - - // public interface OptaplannerFactory { - /** - * Create an OptaPlanner solver. - * @param unimprovedMs Maximum interval of time (in ms) the solver will run - * without finding an improving solution. - * @param nm The name of the solver. - * @return A supplier that will construct the specified solver. - * @throws IllegalArgumentException if a solver with the specified name does - * not exist in the factory. - */ - // StochasticSupplier createRT(long unimprovedMs, String nm); - // - // StochasticSupplier create(long unimprovedMs, String nm); - // - // StochasticSupplier createWithMaxCount(int unimprovedCount, - // String nm); - // - // // ImmutableSet getAvailableSolvers(); - // } - - // static class OptaplannerSolversFactory implements OptaplannerFactory { - // private final String xmlResource; - // - // OptaplannerSolversFactory(String xmlLocation) { - // xmlResource = xmlLocation; - // } - // - // @Override - // public StochasticSupplier createRT(long ms, String nm) { - // return builderHelper(ms, nm).buildRealtimeSolverSupplier(); - // } - // - // @Override - // public StochasticSupplier create(long unimprovedMs, String nm) { - // return builderHelper(unimprovedMs, nm).buildSolverSupplier(); - // } - // - // @Override - // public StochasticSupplier createWithMaxCount(int unimprovedCount, - // String nm) { - // return builder() - // .withUnimprovedStepCountLimit(unimprovedCount) - // .withSolverFromBenchmark(xmlResource, nm) - // .withName(nm) - // .buildSolverSupplier(); - // } - // - // Builder builderHelper(long ms, String nm) { - // return builder() - // .withUnimprovedMsLimit(ms) - // .withSolverFromBenchmark(xmlResource, nm) - // .withName(nm); - // } - // - // // @Override - // // public ImmutableSet getAvailableSolvers() { - // // return builder().withSolverFromBenchmark(benchmarkXmlResource, - // solverKey) - // // } - // } - static class OptaplannerSolver implements MeasureableSolver { @Nullable PDPSolution lastSolution;