IBM ILOG Solver User's Manual > Local Search > Combining Complete and Local Search: Locating Warehouses > Model > Define search functions

We first define a function, TabuSearch, to perform a simple tabu search with a short-term memory. We define a neighborhood using IloFlip and randomize it using IloRandomize. We define a goal, move, that makes a single move and, if the solution is improved, stores it in the solution object whole. The function IloSingleMove scans the randomized neighborhood nh using sol as the current solution. The metaheuristic mh uses tabu search to filter moves, and the search selector selectMove selects a move that minimizes the cost.

// Function to perform simple tabu search with a short term memory

void TabuSearch(IloSolver solver,
                IloIntVarArray open,
                IloSolution sol,
                IloSolution whole,
                IloGoal subGoal,
                IloInt iter = IloIntMax) {
  IloEnv env = solver.getEnv();
  IloRandom rand(env);
  IloNHood nh = IloRandomize(env, IloFlip(env, open), rand);
  IloMetaHeuristic mh = IloTabuSearch(env, 2);
  IloIntVar cost = sol.getObjectiveVar();
  IloSearchSelector selectMove = IloMinimizeVar(env, cost, 1.0);

  // Goal makes a move, and updates the (whole) best solution if better.
  IloGoal move = IloSingleMove(env, sol, nh, mh, selectMove, subGoal) &&
                 IloStoreBestSolution(env, whole);

Finally, we define a standard optimization loop that continues the search until all iterations have been completed or the tabu search is complete.

  // Standard optimization loop.
  do {
    IloInt i = 0;
    while (--iter >= 0 && solver.solve(move)) {
      solver.out() << "Iter = " << ++i << ", "
                   << sol.getObjectiveValue() << " : ";
      for (IloInt j = 0; j < open.getSize(); j++)
        solver.out() << solver.getValue(open[j]);
      solver.out() << " (Best = " << whole.getObjectiveValue() << ")" << endl;
    }
  } while (iter > 0 && !mh.complete());
}

We define a goal, IloSetOffer, that chooses a client with the smallest number of available open warehouses (an open warehouse is available if it has sufficient remaining capacity to satisfy the client's demand), and assign the client to the available open warehouse with the lowest cost.

// Goal to assign customers to specific warehouses

ILCGOAL4(IlcSetOffer, IlcIntVarArray, offer, IlcIntVarArray, open,
                      IloArray<IloIntArray>, costs, IloIntArray, buildCosts) {
  IlcInt i = IlcChooseMinSizeInt(offer);
  if (i >= 0) {
    // Choose closest warehouse first.
    IlcInt best = -1;
    IlcInt lowest = IlcIntMax;
    for (IlcIntExpIterator it(offer[i]); it.ok(); ++it) {
      IloIntArray row = costs[i];
      IlcInt cost = row[*it] + buildCosts[*it] * (open[*it].getMin() == 0);
      if (cost <= lowest) { lowest = cost; best = *it; }
    }
    return IlcAnd(IlcOr(IlcSetValue(offer[i], best),
                        IlcRemoveValue(offer[i], best)),
                  this);
  }
  return 0;
}