Пример #1
0
  /**
   * Check if a {@linkplain TRSPTwoOptMove 2-opt move} is feasible for the given <code>tour</code>
   *
   * @param tour the base tour
   * @param move the {@link TRSPTwoOptMove} to be tested
   * @return <code>true</code> if applying <code>move</code> to the given <code>tour</code> will
   *     result in a feasible tour
   */
  @Override
  public boolean isTwoOptFeasible(ITRSPTour itour, TRSPTwoOptMove move) {
    if (!TRSPTour.class.isAssignableFrom(itour.getClass())) {
      TRSPLogging.getOptimizationLogger()
          .warn(
              String.format(
                  "ToolsConstraint.isTwoOptFeasible: unsupported tour class (%s)",
                  itour.getClass()));
      return true;
    }
    TRSPTour tour = (TRSPTour) itour;

    if (!tour.isMainDepotVisited() // The main depot is not visited, the tour is already feasible
        || tour.isMainDepotVisited(
            tour.getSucc(move.getFirst())) // The visit to the main depot is done before
        // the first
        // affected node
        || !tour.isMainDepotVisited(move.getSecond())) // The visit to the main depot is done
      // after the last affected node
      return true;

    // The main depot is visited between j and m
    TRSPTourIterator it = tour.iterator(move.getSecond());

    // Start with node m and iterate backward
    int node = it.previous();
    while (node != tour.getMainDepotId() && it.hasNext()) {
      if (!tour.getInstance().hasRequiredTools(tour.getTechnician().getID(), node))
        // The technician does not have the required tools for this request
        return false;
    }

    // No incompatible request was found, the move is feasible
    return true;
  }
Пример #2
0
  /** Initialize and setup the post-optimizer */
  public void setupPostOp() {
    setPostOp(
        new SCGurobiSolver(
            getInstance(),
            getParams(),
            mTourPoolCB.getHasher(),
            !getALNSSol().getUnservedRequests().isEmpty()));

    getPostOp().addColumns(mTourPoolCB.getTourPool().getAllTours());

    mTourPoolSize = getTourPool().size();
    // Free some memory
    mTourPoolCB.getTourPool().clear();

    // Set initial solution
    getPostOp().setIncumbent(getALNSSol());

    if (getModelWriter() != null)
      try {
        getModelWriter()
            .write(
                getPostOp().getModel(),
                String.format("%s-%s", getInstance().getName(), getComment()));
      } catch (IOException e) {
        TRSPLogging.getOptimizationLogger()
            .exception(this.getClass().getSimpleName() + ".setupPostOp", e);
      }

    // Add stat writer
    if (getGRBStatCollector() != null) getGRBStatCollector().setModel(getPostOp().getModel());
  }
Пример #3
0
 /**
  * Check an insertion move feasibility
  *
  * @param tour
  * @param move
  * @return 1 if move is feasible, -1 if the technician does not have the required tools and no
  *     visit to main depot is planned, -2 if the required tools are not available at this point
  */
 private int checkInsFeasibility(ITRSPTour itour, InsertionMove move) {
   if (!TRSPTour.class.isAssignableFrom(itour.getClass())) {
     TRSPLogging.getOptimizationLogger()
         .warn(
             String.format(
                 "ToolsConstraint.checkInsFeasibility: unsupported tour class (%s)",
                 itour.getClass()));
     return 1;
   }
   TRSPTour tour = (TRSPTour) itour;
   InsertionMove m = move;
   if (m.isDepotTrip() || !tour.getInstance().isRequest(move.getNodeId())) return 1;
   if (!tour.isMainDepotVisited()
       && !m.isDepotTrip()
       && !tour.getInstance().hasRequiredTools(tour.getTechnician().getID(), m.getNodeId()))
     return -1;
   int pred = m.getInsertionPred();
   if (pred == ITRSPTour.UNDEFINED) {
     if (tour.getInstance().hasRequiredTools(tour.getTechnician().getID(), m.getNodeId()))
       return 1;
     else return -2;
   } else {
     for (int tool : itour.getInstance().getRequest(m.getNodeId()).getToolSet())
       if (!tour.isToolAvailable(pred, tool)) return -2;
   }
   return 1;
 }
Пример #4
0
  public void setupALNS() {
    // ----------------------------------------
    // Setup the ALNS
    IComponentHandler<IDestroy<TRSPSolution>> destroyComponents = null;
    IComponentHandler<IRepair<TRSPSolution>> repairComponents = null;

    getInitSol().setCostDelegate(getALNSCostDelegate(getInitSol()));

    Class<?> handlerClass = getParams().get(TRSPGlobalParameters.ALNS_COMP_HANDLER);
    if (handlerClass == ALNSComponentHandler.class) {
      destroyComponents =
          new ALNSComponentHandler<IDestroy<TRSPSolution>>(
              getParams().getALNSRndStream(),
              newDestroySet(getParams()),
              getParams().get(ALNS_A_SIGMA1),
              getParams().get(ALNS_A_SIGMA2),
              getParams().get(ALNS_A_SIGMA3),
              getParams().get(ALNS_A_R),
              getParams().get(ALNS_A_L));
      repairComponents =
          new ALNSComponentHandler<IRepair<TRSPSolution>>(
              getParams().getALNSRndStream(),
              newRepairSet(getTourCtrHandler(), getParams()),
              getParams().get(ALNS_A_SIGMA1),
              getParams().get(ALNS_A_SIGMA2),
              getParams().get(ALNS_A_SIGMA3),
              getParams().get(ALNS_A_R),
              getParams().get(ALNS_A_L));
    } else if (handlerClass == RndComponentHanlder.class) {
      destroyComponents =
          new RndComponentHanlder<IDestroy<TRSPSolution>>(
              getParams().getALNSRndStream(), newDestroySet(getParams()), false);
      repairComponents =
          new RndComponentHanlder<IRepair<TRSPSolution>>(
              getParams().getALNSRndStream(),
              newRepairSet(getTourCtrHandler(), getParams()),
              false);
    } else {
      TRSPLogging.getSetupLogger()
          .error(
              this.getClass().getSimpleName()
                  + ".setupALNS: Unsupported ALNS component handler: %s",
              handlerClass);
    }

    getALNSGlobalParams()
        .set(
            ALNSGlobalParameters.DESTROY_SIZE_RANGE,
            new double[] {
              getParams().get(TRSPGlobalParameters.ALNS_XI_MIN),
              getParams().get(TRSPGlobalParameters.ALNS_XI_MAX)
            });

    // Parallel ALNS
    if (getParams().get(TRSPGlobalParameters.ALNS_PARALLEL)) {
      // && getParams().get(TRSPGlobalParameters.THREAD_COUNT) > 1) {
      getALNSGlobalParams()
          .set(
              ALNSGlobalParameters.PALNS_IT_P,
              getParams().get(TRSPGlobalParameters.ALNS_PALNS_IT_P));
      getALNSGlobalParams()
          .set(
              ALNSGlobalParameters.PALNS_POOL_SIZE,
              getParams().get(TRSPGlobalParameters.ALNS_PALNS_POOL_SIZE));
      getALNSGlobalParams()
          .set(
              ALNSGlobalParameters.PALNS_POOL,
              getParams().get(TRSPGlobalParameters.ALNS_PALNS_POOL));
      getALNSGlobalParams()
          .set(
              ALNSGlobalParameters.DIVERSITY_METRIC,
              getParams().get(TRSPGlobalParameters.ALNS_PALNS_DIV_METRIC));
      getALNSGlobalParams()
          .set(ALNSGlobalParameters.PALNS_THREAD_COUNT, getParams().getThreadCount());

      ParallelALNS<TRSPSolution> alns =
          new ParallelALNS<TRSPSolution>(
              OptimizationSense.MINIMIZATION,
              getParams().getALNSRndStream(),
              getALNSGlobalParams(),
              destroyComponents,
              repairComponents);
      setALNS(alns);

      // Setup the solution pool
      TRSPCostDelegate cd = getALNSCostDelegate(getInitSol());
      for (TRSPSolution s : mInitPool) { // FIXME update mInitPool in dynamic setting?
        s.setCostDelegate(cd);
        alns.getSolPool().add(s, true);
      }

    } else {
      // Sequential ALNS
      setALNS(
          new AdaptiveLargeNeighborhoodSearch<TRSPSolution>(
              OptimizationSense.MINIMIZATION,
              getParams().getALNSRndStream(),
              getALNSGlobalParams(),
              destroyComponents,
              repairComponents));
    }

    if (mLogger != null) mLogger.registerToALNS(getALNS());

    // ----------------------------------------
    mALNSParams =
        new SimpleParameters(
            LSStrategy.DET_BEST_IMPROVEMENT,
            getParams().get(ALNS_MAX_TIME),
            getParams().get(ALNS_MAX_IT),
            getParams().getALNSRndStream());

    if (getParams().get(TRSPGlobalParameters.SC_ENABLED)
        || getParams().get(TRSPGlobalParameters.TOUR_POOL_ENABLED)) {
      mTourPoolCB =
          new TourPoolCallBack(
              getInstance(),
              getParams().get(ALNS_MAX_IT),
              new NodeSetSolutionHasher(getInstance(), getParams().getHashRndStream()));
      getALNS().registerCallback(mTourPoolCB, ALNSEventType.REPAIRED);
    }

    if (getParams().get(TRSPGlobalParameters.ALNS_ENABLE_LOGGING)) {
      ALNSLogger<TRSPSolution> logger = new ALNSSALogger<TRSPSolution>("results/alns");
      logger.registerToALNS(getALNS());
    }

    // Setup SA acceptance criterion
    mALNSParams.setAcceptanceCriterion(
        new SAAcceptanceCriterion(
            OptimizationSense.MINIMIZATION,
            getParams().getALNSRndStream(),
            getInitSol().getObjectiveValue(),
            getParams().get(ALNS_SA_W),
            getParams().get(ALNS_SA_P),
            mALNSParams.getMaxIterations(),
            getParams().get(ALNS_SA_ALPHA),
            true));
  }
Пример #5
0
  @Override
  public Object[] getStats(BestKnownSolutions bks, int runId, int runNum) {
    String group =
        getInstance().getName().substring(0, (getInstance().getName().contains("RC") ? 3 : 2));

    String instanceName = getInstance().getName().replace(".txt", "");

    TRSPCostDelegate wtDel;
    // sCVRPTW
    if (getParams().isCVRPTW()) wtDel = new TRSPDistance();
    else wtDel = new TRSPWorkingTime();
    TRSPTourBalance tbDel =
        new TRSPTourBalance(
            wtDel, getParams().get(TRSPGlobalParameters.BALANCE_COST_DELEGATE_MEASURE));

    double init_wt = wtDel.evaluateSolution(getInitSol(), true, true);
    // double init_wt_dev = tbDel.evaluateSolution(getInitSol(), true, true);
    double alns_wt = wtDel.evaluateSolution(getALNSSol(), true, true);
    // double alns_wt_dev = tbDel.evaluateSolution(getALNSSol(), true, true);
    double postop_wt = wtDel.evaluateSolution(getFinalSolution(), true, true);
    // double postop_wt_dev = tbDel.evaluateSolution(getFinalSolution(), true, true);
    double postop_bbgap = Double.NaN;
    if (getPostOp() != null) {
      try {
        double mipObj = getPostOp().getModel().get(DoubleAttr.ObjVal);
        double mipLB = getPostOp().getModel().get(DoubleAttr.ObjBound);
        postop_bbgap = mipLB != 0 ? (mipObj - mipLB) / mipObj : mipObj / 100;
      } catch (GRBException e) {
        TRSPLogging.getProcedureLogger()
            .exception(this.getClass().getSimpleName() + ".collectStats", e);
      }
    }
    Object[] stats =
        new Object[] {
          runId,
          getInstance().getName(), // name
          group, // group
          getInstance().getRequestCount(), // size
          getInstance().getFleet().size(), // crew count
          runNum,
          getComment(), // comment
          mInitTimer.readTimeS(), // init_time
          getInit().getIterationCount(), // init_it
          // mInit.getAssignmentStrategy(),// init_strat
          getInit().getStatus(), // init_status
          getInitSol().getUnservedCount(), // init_unserved
          init_wt, // init_wt
          // init_wt_dev,// init_wt_dev
          getALNS().getTimer().readTimeS(), // alns_time
          getALNS().getStoppingCriterion().getIterationCount(), // alns_it
          getALNSSol().getUnservedCount(), // alns_unserved
          alns_wt, // alns_wt
          // alns_wt_dev,// alns_wt_dev
          getALNSSol().getActualTourCount(), // alns_K
          (init_wt - alns_wt) / init_wt, // wt imp
          // (init_wt_dev - alns_wt_dev) / init_wt_dev, // wt dev imp
          getChecker().checkSolution(getALNSSol()), // alns_feasible
          getPostOp() == null ? 0l : getPostOp().getTimer().readTimeS(), // postop_time
          getFinalSolution().getUnservedCount(), // postop_unserved
          postop_wt, // postop_wt
          // postop_wt_dev, // postop_wt_dev
          getFinalSolution().getActualTourCount(), // postop_K
          (alns_wt - postop_wt) / alns_wt, // postop_wt improvement
          // (alns_wt_dev - postop_wt_dev) / alns_wt_dev, // postop_wt_dev improvement
          getChecker().checkSolution(getFinalSolution()), // postop_checksol
          postop_bbgap, // postop_gap
          getPostOp() != null
              ? getPostOp().getStatus()
              : SolverStatus.UNKNOWN_STATUS, // postop_status
          getPostOp() != null ? getPostOp().getColumnCount() : 0, // postop_pool_size
          getHashPoolCollisionCount(), // postop_pool_collisions
          bks.getBKS(instanceName), // BKS
          bks.getGapToBKS(instanceName, alns_wt, OptimizationSense.MINIMIZATION), // ALNS GAP
          bks.getGapToBKS(instanceName, postop_wt, OptimizationSense.MINIMIZATION), // POSTOP GAP
          bks.getIntValue(instanceName, "K"), // BKS - K
          bks.isOptimal(instanceName) ? 1 : 0, // BKS is optimal?
          Utilities.toShortString(getParams().get(TRSPGlobalParameters.RUN_SEEDS)), // seeds
          getFinalSolution().toShortString()
        };
    return stats;
  }
Пример #6
0
  @Override
  public TRSPSolution call() {
    TRSPLogging.getProcedureLogger()
        .info(
            this.getClass().getSimpleName() + "[start ]: Solving instance %s (I=%s, SC=%s)",
            getInstance().getName(),
            getParams().get(TRSPGlobalParameters.ALNS_MAX_IT),
            getParams().get(TRSPGlobalParameters.SC_ENABLED));

    if (getInitSol() == null) {
      initialization();
      TRSPLogging.getProcedureLogger()
          .info(
              this.getClass().getSimpleName() + "[init  ]: Initialization finished in %.1fs",
              mInitTimer.readTimeS());
      TRSPLogging.getProcedureLogger()
          .info(
              this.getClass().getSimpleName() + "[init  ]: Initial solution: %.3f (%s)",
              getInitSol().getObjectiveValue(),
              getInitSol().getUnservedCount());
      String err = getChecker().checkSolution(getInitSol());
      if (!err.isEmpty()) {
        TRSPLogging.getProcedureLogger()
            .warn(this.getClass().getSimpleName() + "[init  ]:  Infeasibility: %s", err);
      }
    }

    setupALNS();
    if (ParallelALNS.class.isAssignableFrom(getALNS().getClass()))
      TRSPLogging.getProcedureLogger()
          .info(
              this.getClass().getSimpleName() + "[init  ]: Penalty: %.3f - Initial pool: %s",
              getInitSol().getCostDelegate().getUnservedPenalty(),
              ((ParallelALNS<?>) getALNS()).getSolPool());
    alns();
    TRSPLogging.getProcedureLogger()
        .info(
            this.getClass().getSimpleName() + "[alns  ]: ALNS finished in %.1fs %s",
            getALNS().getTimer().readTimeS(),
            getALNS().getStoppingCriterion());
    if (ParallelALNS.class.isAssignableFrom(getALNS().getClass()))
      TRSPLogging.getProcedureLogger()
          .info(
              this.getClass().getSimpleName() + "[alns  ]: Final pool: %s",
              ((ParallelALNS<?>) getALNS()).getSolPool());
    if (getALNSSol() != null)
      TRSPLogging.getProcedureLogger()
          .info(
              this.getClass().getSimpleName() + "[alns  ]: ALNS solution  : %.3f (%s)",
              getALNSSol().getObjectiveValue(),
              getALNSSol().getUnservedCount());
    String err = getChecker().checkSolution(getALNSSol());
    if (!err.isEmpty()) {
      TRSPLogging.getProcedureLogger()
          .warn(this.getClass().getSimpleName() + "[alns  ]:  Infeasibility: %s", err);
    }

    if (getParams().get(TRSPGlobalParameters.SC_ENABLED) && getALNSSol() != null) {
      TRSPLogging.getProcedureLogger()
          .info(this.getClass().getSimpleName() + "[postop]: Post-optimization");
      setupPostOp();
      postOp();
      TRSPLogging.getProcedureLogger()
          .info(
              this.getClass().getSimpleName() + "[postop]: Post-optimization finished in %.1fs",
              getPostOp().getTimer().readTimeS());
      err = getChecker().checkSolution(getFinalSolution());
      if (!err.isEmpty()) {
        TRSPLogging.getProcedureLogger()
            .warn(this.getClass().getSimpleName() + "[end  ]:  Infeasibility: %s", err);
      }
    } else {
      setFinalSolution(getALNSSol());
    }

    TRSPLogging.getProcedureLogger()
        .info(
            this.getClass().getSimpleName() + "[end   ]: Final solution : %.3f (%s)",
            getFinalSolution() != null ? getFinalSolution().getObjectiveValue() : Double.NaN,
            getFinalSolution() != null ? getFinalSolution().getUnservedCount() : "na");

    return getFinalSolution();
  }
Пример #7
0
  /**
   * Check if a {@linkplain TRSPShiftMove shift move} is feasible for the given <code>solution
   * </code>
   *
   * @param solution the base solution
   * @param move the {@link TRSPShiftMove} to be tested
   * @return <code>true</code> if applying <code>move</code> to the given <code>solution</code> will
   *     result in a feasible mSolution
   */
  @Override
  public boolean isShiftFeasible(ITRSPTour itour, TRSPShiftMove move) {
    if (!TRSPTour.class.isAssignableFrom(itour.getClass())) {
      TRSPLogging.getOptimizationLogger()
          .warn(
              String.format(
                  "ToolsConstraint.isShiftFeasible: unsupported tour class (%s)",
                  itour.getClass()));
      return true;
    }
    TRSPTour tour = (TRSPTour) itour;

    if (!tour.isMainDepotVisited()) {
      // The main depot is not visited, we assume that the tour is and will remain feasible
      return true;
    } else {
      // The main depot is visited
      if (move.getNode() == tour.getMainDepotId()) {
        // The shifted node is the main depot
        if (!move.isForward()) {
          // A backward move of the main depot is always feasible
          return true;
        } else {
          // Check if the requests between the current depot position and its new one require a
          // visit to
          // the depot to be served
          List<Integer> seq = move.getChangedSequence();
          for (int s : seq) {
            if (s == tour.getMainDepotId())
              // The requests after the main depot will be feasible
              return true;
            else if (!tour.getInstance().hasRequiredTools(tour.getTechnician().getID(), s))
              // This request will be before the depot visit but the technician does not have the
              // required
              // skills
              return false;
          }
          throw new IllegalStateException(
              "Illegal state when checking the feasibility of move " + move);
        }
      } else {
        if (tour.getInstance().hasRequiredTools(tour.getTechnician().getID(), move.getNode()))
          // The technician already has the tools to serve the shifted node, the move is feasible in
          // all cases
          return true;

        int pred =
            move.getNewSucc() != ITRSPTour.UNDEFINED
                ? tour.getPred(move.getNewSucc())
                : tour.getLastNode();
        if (tour.isMainDepotVisited(move.getNode()) == tour.isMainDepotVisited(pred)) {
          // Both the shifted node and its new predecessor are on the same "side" of the tour
          // (either before
          // or after the depot visit), the move is therefore feasible
          return true;
        } else {
          // The shifted node and its new predecessor are on different "side" of the tour (one is
          // before
          // while the other is after the depot visit)
          if (move.isForward()) {
            // The node will be after the depot visit, the move is therefore feasible
            return true;
          } else {
            // The node is shifted before the depot visit, while the technician does not have the
            // required
            // tools (tested before)
            return false;
          }
        }
      }
    }
  }