IBM ILOG Solver User's Manual > Local Search > Writing a Neighborhood > Writing a new neighborhood > Writing a new neighborhood modifier

It is possible to write your own neighborhood modifier using Solver by subclassing the IloNHoodModifierI class. This abstract implementation class is used to describe a neighborhood structure that depends on other "child" neighborhood structures. Solver neighborhoods such as IloConcatenate, IloRandomize, and IloContinue belong to this category of neighborhood. Such neighborhoods do not generate neighbors in their own right, but pass back neighbors produced by their children. The main job of a neighborhood modifier is to maintain a mapping between the indices of neighbors for the neighborhood modifier and the corresponding child neighborhoods and indices within these child neighborhoods. The member function mapIndex performs this maintenance. Additional behaviors can be added. One example is to manipulate normally produced deltas in some way, for instance by adding additional variables, before they are returned.

The following class forms the concatenation of two neighborhoods.

class IloAddNHoodsI : public IloNHoodModifierI {
public:
  IloAddNHoodsI(IloEnv env, IloNHood nhood0, IloNHood nhood1,
                const char *name = 0);
  void mapIndex(IloSolver solver, IloInt i,
                IloNHood &nhood, IloInt &offset) const;
};

The constructor builds the base class.

IloAddNHoodsI::IloAddNHoodsI(IloEnv env,
                             IloNHood nhood0,
                             IloNHood nhood1,
                             const char *name)
: IloNHoodModifierI(env, nhood0, nhood1, name) { }

The correct neighborhood is determined by comparing the index against the size of the first neighborhood. If we map to the first neighborhood, the index is unaffected. Otherwise, it must be reduced by the size of the first neighborhood.

void IloAddNHoodsI::mapIndex(IloSolver solver, IloInt i,
                             IloNHood &nhood, IloInt &offset) const {
  IloInt size0 = getNHoodSize(0);
  if (i < size0) { nhood = getNHood(0); offset = i; }
  else           { nhood = getNHood(1); offset = i - size0; }
}

Example

The following small example shows how to code a neighborhood which has a side effect on another neighborhood. We assume that the delta will be adjusted in the call to define. First, we define the class which performs a null mapping between neighbors of the modifier and neighbors of the child neighborhood.

class IloAdjustNeighborsI : public IloNHoodModifierI {
public:
  IloAdjustNeighborsI(IloEnv env, IloNHood nhood, const char *name = 0);
  void mapIndex(IloSolver, IloInt i, IloNHood &nhood, IloInt &offset) const {
    nhood = getNHood(0); offset = i;
  }
  IloSolution define(IloSolver solver, IloInt i);
};

The constructor builds the base class.

IloAdjustNeighborsI::IloAdjustNeighborsI(IloEnv env,
                                         IloNHood nhood,
                                         const char *name)
: IloNHoodModifierI(env, nhood, name) { }

The definition of the delta should be done by a call to the base class. Shortcuts, such as getNHood(0).define(solver, i) are not recommended, as they make assumptions about both the implementation of IloNHoodModifierI::define and mapIndex.

IloSolution IloAdjustNeighborsI::define(IloSolver solver, IloInt i) {
  IloSolution delta = IloNHoodModifierI::define(solver, i);
  //
  // Adjust delta here.
  //
  return delta;
}