/** * */ package vroom.trsp.datamodel; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; import vroom.common.modelling.dataModel.Depot; import vroom.common.modelling.dataModel.attributes.ITimeWindow; import vroom.common.utilities.ExtendedReentrantLock; import vroom.common.utilities.Utilities; import vroom.common.utilities.optimization.IInstance; import vroom.optimization.online.jmsa.IActualRequest; import vroom.trsp.sim.TRSPSimulator; /** * <code>TRSPInstance</code> is a simplified representation of an instance, independent from the VroomModelling Library. * <p> * Creation date: Feb 23, 2011 - 11:19:53 AM * * @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a * href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a * href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a> * @version 1.0 */ public class TRSPInstance implements IInstance, vroom.optimization.online.jmsa.IInstance { /** The id of the main depot */ public static final int MAIN_DEPOT = 0; /** the name of this instance **/ private final String mName; /** * Getter for the name of this instance * * @return the name of this instance */ @Override public String getName() { return this.mName; } /** * Returns the group of instance (for TRSP instances) * * @return the group of instance (for TRSP instances) */ public String getGroup() { return getName().substring(0, (getName().contains("RC") ? 3 : 2)); } /** the technician fleet *. */ private final TechnicianFleet mFleet; /** * Getter for the technician fleet. * * @return the value of fleet */ public TechnicianFleet getFleet() { return this.mFleet; } /** * Returns the technician with the given id * * @param techId * the technician id * @return the technician with the given id */ public Technician getTechnician(int techId) { return getFleet().getVehicle(techId); } /** the depots array in this instance (including technician homes) *. */ private final Depot[] mDepots; /** * the number of depots in this instance, stored for performance */ private final int mDepotCount; /** * the number to be added to a depot id to obtain its duplicate id */ private final int mDepotsOffset; /** * Getter for the list of the depots in this instance (including technician homes). * * @return the list of depots in this instance */ public List<Depot> getDepots() { return Arrays.asList(Arrays.copyOf(mDepots, mDepots.length)); } /** * Gets the depot count. * * @return the depot count */ public int getDepotCount() { return this.mDepotCount; } /** * Get a depot form its id. * <p> * Please note that a depot and its duplicate share a reference to the same {@link Depot} object * </p> * * @param depotId * the id of the depot * @return the depot with id <code>depotId</code>, or <code>null</code> if <code>depotId</code> is not a valid depot * id */ public Depot getDepot(int depotId) { // if (!isDepot(depotId)) // return null; return mDepots[getOriginalId(depotId)]; } /** * Get the depot duplicate id * * @param depotId * the original depot * @return the id used for the duplicate */ public int getDepotDuplicate(int depotId) { if (!isDepot(depotId)) throw new IllegalArgumentException("The depot id does not seem to be valid " + depotId); return depotId + mDepotsOffset; } /** * Get the original id of a node * * @param nodeId * the id of the considered node * @return the id of the original node: <code>nodeId-depotOffset</code> if <code>nodeId</code> is the ID of a depot * duplicate, and <code>nodeId</code> otherwise */ protected int getOriginalId(int nodeId) { if (nodeId >= mDepotsOffset) return nodeId - mDepotsOffset; else return nodeId; } /** * Get the main depot * * @return the main depot in this instance */ public Depot getMainDepot() { return getDepot(0); } /** * Check if the given id is the id of a depot. * * @param id * the id to be checked * @return <code>true</code> if <code>id</code> corresponds to a depot */ public boolean isDepot(int id) { // return mDepots.containsK:ey(id); return id >= 0 && id < mDepotCount || id >= mDepotsOffset; } /** * Check if the given id is the id of a/the main depot * * @param id * the id to be checked * @return <code>true</code> if <code>id</code> corresponds to a depot */ public boolean isMainDepot(int id) { return id == 0; } /** A list of the requests in this instance. */ private final TRSPRequest[] mRequests; /** A view of the list of requests in this instance */ private final List<TRSPRequest> mRequestsView; /** A list of the requests that have already been released */ private List<TRSPRequest> mReleasedRequests; /** A list of the unserved requests that have already been released */ private List<TRSPRequest> mUnservedReleasedRequests; /** The number of requests in this instance, stored for performance */ private final int mRequestCount; /** * Returns all the requests in this instance (whether they are released or not). * <p> * Note that the returned list is an unmodifiable view of the internal request list. * </p> * * @return a list containing all the requests in this instance */ public List<TRSPRequest> getRequests() { return mRequestsView; } /** * Update the released requests list */ public void updateReleasedRequests() { if (mSimulator == null) { mReleasedRequests = getRequests(); mUnservedReleasedRequests = getRequests(); } else { mReleasedRequests = new ArrayList<TRSPRequest>(getRequestCount()); mUnservedReleasedRequests = new ArrayList<TRSPRequest>(getRequestCount()); for (TRSPRequest r : mRequests) { if (mSimulator.isReleased(r)) { mReleasedRequests.add(r); if (!isServed(r.getID())) mUnservedReleasedRequests.add(r); } } mReleasedRequests = Collections.unmodifiableList(mReleasedRequests); mUnservedReleasedRequests = Collections.unmodifiableList(mUnservedReleasedRequests); } } /** * Returns all the released requests in this instance (i.e. that have been made known to the system). * <p> * Note that the returned list is an unmodifiable view of the internal request list, and that method * {@link #updateReleasedRequests()} should be called before to ensure that the released request list is up to date. * </p> * * @return a list containing all the released requests in this instance * @see TRSPInstance#updateReleasedRequests() */ public List<TRSPRequest> getReleasedRequests() { return mReleasedRequests; } /** * Returns all the unserved released requests in this instance (i.e. that have been made known to the system). * <p> * Note that the returned list is an unmodifiable view of the internal request list, and that method * {@link #updateReleasedRequests()} should be called before to ensure that the released request list is up to date. * </p> * * @return a list containing all the unserved released requests in this instance * @see TRSPInstance#updateReleasedRequests() */ public List<TRSPRequest> getUnservedReleasedRequests() { return mUnservedReleasedRequests; } /** * Returns the total number of requests in this instance, ignoring their released state. * * @return the request count */ public int getRequestCount() { return mRequestCount; } /** * Gets a request from its id * * @param id * the id * @return the request with the given id */ public TRSPRequest getRequest(int id) { // if (!isRequest(id)) // throw new // IllegalArgumentException(String.format("%s is not a valid request id", // id)); return mRequests[id - mDepotCount]; } /** * Checks if is request. * * @param id * the id * @return true, if is request */ public boolean isRequest(int id) { // return mRequests.containsKey(id); return !isDepot(id); } /** * Size of the instance: total number of nodes including both depots and requests * * @return the total number of nodes in this instance */ public int size() { return getDepotCount() + getRequestCount(); } /** the cost delegate *. */ private final TRSPDistanceMatrix mCostDelegate; /** * Getter for the cost delegate. * * @return the cost delegate */ public TRSPDistanceMatrix getCostDelegate() { return this.mCostDelegate; } /** the delegate class that will generate solutions hash codes **/ private ITRSPSolutionHasher mSolutionHasher; /** * Getter for the delegate class that will generate solutions hash codes * * @return the solution hasher associated with this instance */ public ITRSPSolutionHasher getSolutionHasher() { return this.mSolutionHasher; } /** * Set for the delegate class that will generate solutions hash codes * * @param solutionHasher * the solution hasher associated with this instance */ public void setSolutionHasher(ITRSPSolutionHasher solutionHasher) { mSolutionHasher = solutionHasher; } /** the number of skills *. */ private final int mSkillCount; /** * Getter for the number of skills. * * @return the number of skills */ public int getSkillCount() { return this.mSkillCount; } /** the number of tools *. */ private final int mToolCount; /** * Getter for the number of tools. * * @return the number of tools */ public int getToolCount() { return this.mToolCount; } /** the number of spare parts *. */ private final int mSpareCount; /** * Getter for the number of spare parts. * * @return the number of spare parts */ public int getSpareCount() { return this.mSpareCount; } /** the highest id used for requests and depots **/ private final int mMaxId; /** * Getter for the highest id used for requests and depots * * @return the value of the highest id */ public int getMaxId() { return this.mMaxId; } /** * A matrix representing the existing edges in the reduced graph: <code>mTWGraph[i][j]=true</code> iif node * <code>j</code> can be visited after node <code>i</code> without violating time window constraints */ private final boolean[][] mTWGraph; /** * Feasibility of an arc regarding time windows * * @param pred * the first node * @param succ * the second node * @return <code>true</code> iif node <code>succ</code> can be visited after node <code>pred</code> without * violating time window constraints */ public boolean isArcTWFeasible(int pred, int succ) { if (pred == ITRSPTour.UNDEFINED || succ == ITRSPTour.UNDEFINED) return true; return mTWGraph[getOriginalId(pred)][getOriginalId(succ)]; } /** * A matrix representing the skill compatibility between technicians and requests for faster compatibility checks * <code>mTechSkillCompatibility[k][i]=true</code> if technician k has the required skills to serve request i */ private final boolean[][] mTechSkillCompatibility; /** * A matrix representing the tools compatibility between technicians and requests for faster compatibility checks * <code>mTechSkillCompatibility[k][i]=true</code> if technician k initially has the required tools to serve request * i */ private final boolean[][] mTechToolCompatibility; /** * A matrix representing the tools compatibility between technicians and requests for faster compatibility checks * <code>mTechSkillCompatibility[k][i]=true</code> if technician k initially has the required spare parts to serve * request i */ private final boolean[][] mTechSpareCompatibility; /** * A matrix representing the compatibilities between technicians and requests. * <code>mTechReqCompatibility[k][i]=true</code> if k has the required skills to serve i within its time window. In * other words, <code>mTechReqCompatibility[k][i]=true</code> iif there exist a feasible tour visiting i. */ private final boolean[][] mTechReqCompatibility; /** * A mapping between requests and technicians that have the required skills and can service the request with its * time window */ private final ArrayList<Set<Integer>> mCompatibleTech; /** * Returns <code>true</code> iif there exist a feasible tour associated with technician <code>req</code> servicing * request <code>req</code> (considering skills, tools, spare parts, and time windows) * * @param tech * the id of the considered technician * @param req * the id of the considered request * @return <code>true</code> iif there exist a feasible tour associated with technician <code>req</code> servicing * request <code>req</code> */ public boolean isCompatible(int tech, int req) { return mTechReqCompatibility[tech][req]; } /** * @param tech * the id of the considered technician * @param req * the id of the considered request * @return <code>true</code> iif technician <code>tech</code> has the required skills to serve request * <code>req</code> */ public boolean hasRequiredSkills(int tech, int req) { return mTechSkillCompatibility[tech][req]; } /** * @param tech * the id of the considered technician * @param req * the id of the considered request * @return <code>true</code> iif technician <code>tech</code> initially has the required tools to serve request * <code>req</code> */ public boolean hasRequiredTools(int tech, int req) { return mTechToolCompatibility[tech][req]; } /** * @param tech * the id of the considered technician * @param req * the id of the considered request * @return <code>true</code> iif technician <code>tech</code> initially has the required spare parts to serve * request <code>req</code> */ public boolean hasRequiredSpareParts(int tech, int req) { return mTechSpareCompatibility[tech][req]; } /** * Set of compatible technicians. * <p> * A technician is said to be compatible if it has the required skills * </p> * * @param req * the considered request * @return a set containing the technicians that can potentially service request <code>req</code> */ public Set<Integer> getCompatibleTechnicians(int req) { return mCompatibleTech.get(req); } /** the allow main depot trip flag **/ private boolean mMainDepotTripAllowed = true; /** * Getter for the allow main depot trip flag (default value is <code>true</code>) * * @return <code>true</code> if trips to the main depot are allowed */ public boolean isMainDepotTripAllowed() { return this.mMainDepotTripAllowed; } /** * Setter for the allow main depot trip flag (default value is <code>true</code>) * * @param allowTrip * <code>true</code> if trips to the main depot are allowed */ public void setMainDepotTripAllowed(boolean allowTrip) { this.mMainDepotTripAllowed = allowTrip; } /** the allow unserved request flag **/ private boolean mUnservedReqAllowed = false; /** * Getter for the allow unserved request flag (default value is <code>false</code>) * * @return <code>true</code> if some requests can be left unserved, <code>false</code> otherwise */ public boolean isUnservedReqAllowed() { return this.mUnservedReqAllowed; } /** * Setter for the allow unserved request flag (default value is <code>false</code>) * * @param allowUnserved * <code>true</code> if some requests can be left unserved, <code>false</code> otherwise */ public void setUnservedReqAllowed(boolean allowUnserved) { this.mUnservedReqAllowed = allowUnserved; } /** the simulator being used with this instance **/ private TRSPSimulator mSimulator; /** * Setter for the simulator being used with this instance * * @param simulator * the simulator being used with this instance * @throws IllegalStateException * if the simulator was set previously */ public void setSimulator(TRSPSimulator simulator) { // if (this.mSimulator != null) // throw new IllegalStateException("The simulator was set previously"); this.mSimulator = simulator; } /** * Getter for the simulator being used with this instance * * @return the simulator being used with this instance */ public TRSPSimulator getSimulator() { return this.mSimulator; } /** * Returns {@code true} iif the request has already been served * * @param reqId * @return {@code true} iif the request has already been served * @ßee {@link TRSPSimulator#isServedOrRejected(int)} */ public boolean isServed(int reqId) { return getSimulator() != null && getSimulator().isServedOrRejected(reqId); } /** {@code true} if this is a dynamic instance */ private boolean mDynamic; /** * Returns {@code true} if this is a dynamic instance * * @return {@code true} if this is a dynamic instance */ public boolean isDynamic() { return mDynamic; } /** * Set the dynamic flag * * @param dynamic * {@code true} if this is a dynamic instance */ public void setDynamic(boolean dynamic) { mDynamic = dynamic; } /** The state (started/stoped) of each technician */ private final boolean[] mTechState; /** * Creates a new <code>TRSPInstance</code>. * * @param name * the name of this instance * @param technicians * the fleet of technician * @param skillCount * the total number of skills * @param toolCount * the total number of tool types * @param spareCount * the total number of spare part types * @param depots * a list of the depot, including possible technician homes. The main depot is assumed to have id 0, all * other depots have ids 1 to <code>|depots|-1</code>. * @param requests * a list of the requests, with ids ranging from <code>|depots|</code> to * <code>|depots|+|requests|-1</code> */ public TRSPInstance(String name, Collection<Technician> technicians, int skillCount, int toolCount, int spareCount, List<Depot> depots, List<TRSPRequest> requests) { this(name, TechnicianFleet.newTechnicianFleet(technicians), skillCount, toolCount, spareCount, depots, requests); } /** * Creates a new <code>TRSPInstance</code>. * * @param name * the name of this instance * @param technicians * the fleet of technician * @param skillCount * the total number of skills * @param toolCount * the total number of tool types * @param spareCount * the total number of spare part types * @param depots * a list of the depot, including possible technician homes. The main depot is assumed to have id 0, all * other depots have ids 1 to <code>|depots|-1</code>. * @param requests * a list of the requests, with ids ranging from <code>|depots|</code> to * <code>|depots|+|requests|-1</code> */ public TRSPInstance(String name, TechnicianFleet technicians, int skillCount, int toolCount, int spareCount, List<Depot> depots, List<TRSPRequest> requests) { mDynamic = false; mSolutionHasher = new ITRSPSolutionHasher() { @Override public int hash(TRSPSolution solution) { return solution != null ? solution.hashCode() : 0; } @Override public int hash(ITRSPTour tour) { return tour != null ? tour.hashCode() : 0; } }; mDepotCount = depots.size(); mRequestCount = requests.size(); // Find the maximum id int max = 0; for (Depot d : depots) { if (d.getID() >= max) max = d.getID() + 1; if (d.getID() >= mDepotCount) throw new IllegalArgumentException("Illegal id for depot " + d); } int depotMaxId = max; int reqMaxId = 0; for (TRSPRequest d : requests) { if (d.getID() >= max) max = d.getID() + 1; if (d.getID() >= reqMaxId) reqMaxId = d.getID(); } mDepotsOffset = max; mMaxId = max + depotMaxId; mName = name; mFleet = technicians; mSkillCount = skillCount; mToolCount = toolCount; mSpareCount = spareCount; mTechState = new boolean[getFleet().size()]; mTechSkillCompatibility = new boolean[getFleet().size()][mMaxId]; mTechToolCompatibility = new boolean[getFleet().size()][mMaxId]; mTechSpareCompatibility = new boolean[getFleet().size()][mMaxId]; mTechReqCompatibility = new boolean[getFleet().size()][mMaxId]; // A list of all ids that were used mDepots = new Depot[mDepotCount]; for (Depot d : depots) { // Check id if (mDepots[d.getID()] != null) throw new IllegalArgumentException(String.format("Id %s is already used (%s)", d.getID(), mDepots[d.getID()])); mDepots[d.getID()] = d; } mRequests = new TRSPRequest[mRequestCount]; for (TRSPRequest r : requests) { // Check id if (mRequests[r.getID() - mDepotCount] != null) throw new IllegalArgumentException(String.format("Id %s is already used (%s)", r.getID(), mRequests[r.getID() - mDepotCount])); mRequests[r.getID() - mDepotCount] = r; } mRequestsView = Collections.unmodifiableList(Arrays.asList(mRequests)); updateReleasedRequests(); // mCostDelegate = new TRSPDistanceMatrix(this); mCostDelegate = new TRSPDistanceMatrixUnitSpeed(this); // Preprocess the instance and create the TW compatible graph mTWGraph = new boolean[getMaxId()][getMaxId()]; mCompatibleTech = new ArrayList<Set<Integer>>(getMaxId()); for (int i = 0; i < getMaxId(); i++) mCompatibleTech.add(null); preprocess(); } /** * Pre-process the instance for faster operations */ public void preprocess() { for (int i = 0; i < mTWGraph.length; i++) { // Prune infeasible arcs for (int j = 0; j < mTWGraph.length; j++) { if (i != j) mTWGraph[i][j] = getTimeWindow(j).isFeasible( getTimeWindow(i).startAsDouble() + getServiceTime(i) + getCostDelegate().getTravelTime(i, j, getFleet().getVehicle())); } // Store request - technician compatibilities boolean atLeastOneTech = false; if (isRequest(i)) mCompatibleTech.set(i, new HashSet<Integer>()); for (Technician t : getFleet()) { mTechReqCompatibility[t.getID()][MAIN_DEPOT] = true; mTechReqCompatibility[t.getID()][t.getHome().getID()] = true; if (!isRequest(i)) { // i is not a request, it is therefore compatible with the // technician mTechSkillCompatibility[t.getID()][i] = true; mTechToolCompatibility[t.getID()][i] = true; mTechSpareCompatibility[t.getID()][i] = true; atLeastOneTech = true; } else { // i is a request, store compatibilities mTechSkillCompatibility[t.getID()][i] = getRequest(i).getSkillSet().isCompatibleWith( t.getSkillSet()); mTechToolCompatibility[t.getID()][i] = getRequest(i).getToolSet().isCompatibleWith(t.getToolSet()); mTechSpareCompatibility[t.getID()][i] = Utilities.compare(getRequest(i).getSparePartRequirements(), t.getSpareParts()) <= 0; // Check compatibility if (mTechSkillCompatibility[t.getID()][i]) { double arrivalTime; double returnTime; if (mTechToolCompatibility[t.getID()][i] && mTechSpareCompatibility[t.getID()][i]) { // The technician can service the request directly arrivalTime = calculateArrivalTime(i, t.getHome().getID(), 0, t.getID()); } else { // The technician needs to visit first the main // depot arrivalTime = calculateArrivalTime(getMainDepot().getID(), t.getHome().getID(), 0, t.getID()); arrivalTime = calculateArrivalTime(i, getMainDepot().getID(), arrivalTime, t.getID()); } returnTime = calculateArrivalTime(t.getHome().getID(), i, arrivalTime, t.getID()); mTechReqCompatibility[t.getID()][i] = // getTimeWindow(i).isFeasible(arrivalTime) && getTimeWindow(t.getHome().getID()).isFeasible(returnTime); } else { mTechReqCompatibility[t.getID()][i] = false; } // Check if the request can be serviced by the technician if (mTechReqCompatibility[t.getID()][i]) { atLeastOneTech = true; mCompatibleTech.get(i).add(t.getID()); } } } if (!atLeastOneTech) throw new IllegalArgumentException("Request " + i + " cannot be served by any technician"); } } /** * Utility method to get the spare part demand associated with a node * * @param node * the considered node * @param type * the type of spare part considered * @return the spare part requirement of <code>node</code>, or <code>0</code> if <code>node</code> is a depot * @see TRSPInstance#getDepot(int) * @see TRSPInstance#getRequest(int) * @see TRSPRequest#getSparePartRequirement(int) */ public int getSparePartReq(int node, int type) { if (isDepot(node)) return 0; else return getRequest(node).getSparePartRequirement(type); } /** * Utility method to get the time window associated with a node * * @param node * the considered node * @return the time window of <code>node</code> * @see TRSPInstance#getDepot(int) * @see TRSPInstance#getRequest(int) * @see TRSPRequest#getTimeWindow() * @see Depot#getTimeWindow() */ public ITimeWindow getTimeWindow(int node) { if (isDepot(node)) return getDepot(node).getTimeWindow(); else return getRequest(node).getTimeWindow(); } /** * Utility method to get the service time associated with a node. * <p> * In this implementation depots are assumed to have a service time of <code>0</code>. * </p> * * @param node * the considered node * @return the service time of <code>node</code> * @see TRSPInstance#getRequest(int) * @see TRSPRequest#getServiceTime() */ public double getServiceTime(int node) { if (isDepot(node)) { // TODO add service time to depots? return 0; } else return getRequest(node).getServiceTime(); } /** * Utility method to evaluate the arrival time at a node depending on the arrival time at its predecessor * * @param node * the considered node * @param pred * the <code>node</code> predecessor * @param arrivalPred * the arrival time at <code>pred</code> * @param techId * the id of the considered technician * @return the arrival time at <code>node</code> */ public double calculateArrivalTime(int node, int pred, double arrivalPred, int techId) { return getTimeWindow(pred).getEarliestStartOfService(arrivalPred) + getServiceTime(pred) + getCostDelegate().getTravelTime(pred, node, getTechnician(techId)); } @Override public String toString() { return String.format("%s (crew:%s req:%s)", getName(), getFleet().size(), getRequestCount()); } // -------------------------------------------------------------------------------------------- // MSA IInstance implementation // -------------------------------------------------------------------------------------------- @Override public boolean addRequest(IActualRequest request) { if (!isRequest(request.getID())) throw new IllegalArgumentException("Unknown request: " + request); if (mReleasedRequests.contains(request)) throw new IllegalArgumentException("Request is already released: " + request); TRSPRequest r = (TRSPRequest) request; getSimulator().advanceTime(r.getReleaseDate()); updateReleasedRequests(); // mReleasedRequests.add(r); // if (!isServed(r.getID())) // mUnservedReleasedRequests.add(r); return true; } @Override public void setResourceStopped(int resourceId, Object param) { mTechState[resourceId] = false; } @Override public void setResourceStarted(int resourceId, Object param) { mTechState[resourceId] = true; } @Override public boolean isResourceStarted(int resourceId) { return mTechState[resourceId]; } @Override public boolean isResourceStopped(int resourceId) { return !mTechState[resourceId]; } @Override public IActualRequest getNodeVisit(int requestId) { return getRequest(requestId); } @Override public List<? extends IActualRequest> getServedRequests() { return toRequestList(getSimulator().getServedRequests()); } @Override public List<? extends IActualRequest> getServedRequests(int resourceId) { ArrayList<TRSPRequest> servedReq = new ArrayList<TRSPRequest>(getSimulator().getCurrentSolution() .getTour(resourceId).length()); for (Integer i : getSimulator().getCurrentSolution().getTour(resourceId)) { if (isRequest(i)) servedReq.add(getRequest(i)); } return servedReq; } @Override public List<? extends IActualRequest> getPendingRequests() { return toRequestList(getSimulator().getCurrentSolution().getUnservedRequests()); } @Override public boolean assignRequestToResource(IActualRequest request, int resourceId) { // TODO check if the implementation of assignRequestToResource is required throw new UnsupportedOperationException(); } @Override public boolean markRequestAsServed(IActualRequest request, int resourceId) { getSimulator().markAsServed(request.getID()); return true; } @Override public TRSPSolution getCurrentSolution() { return getSimulator().getCurrentSolution(); } /** * Returns a list containing the requests which ids are contained in {@code ids} * * @param ids * @return a list containing the requests which ids are contained in {@code ids} */ public List<TRSPRequest> toRequestList(Collection<Integer> ids) { ArrayList<TRSPRequest> list = new ArrayList<TRSPRequest>(ids.size()); for (Integer i : ids) { if (isRequest(i)) list.add(getRequest(i)); } return list; } // -------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------- // ILockable interface implementation // -------------------------------------------------------------------------------------------- /** A lock to be used by this instance */ private final ExtendedReentrantLock mLock = new ExtendedReentrantLock(); @Override public boolean tryLock(long timeout) { try { return getLockInstance().tryLock(timeout, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { return false; } } @Override public void acquireLock() { try { if (!getLockInstance().tryLock(TRY_LOCK_TIMOUT, TRY_LOCK_TIMOUT_UNIT)) { throw new IllegalStateException(String.format( "Unable to acquire lock on this instance of %s (%s) after %s %s, owner: %s", this.getClass() .getSimpleName(), hashCode(), TRY_LOCK_TIMOUT, TRY_LOCK_TIMOUT_UNIT, getLockInstance() .getOwnerName())); } } catch (InterruptedException e) { throw new IllegalStateException(String.format("Unable to acquire lock on this instance of %s (%s)", this .getClass().getSimpleName(), hashCode()), e); } ; } @Override public void releaseLock() { mLock.unlock(); } @Override public boolean isLockOwnedByCurrentThread() { return mLock.isHeldByCurrentThread(); } @Override public ExtendedReentrantLock getLockInstance() { return mLock; } // -------------------------------------------------------------------------------------------- }