IBM ILOG Solver User's Manual > Extending the Library > Writing a Goal: Car Sequencing > Writing your own goal > Example of writing your own goal: Implementing IlcInstantiate

As an example of goal programming, you are going to look closely at how the function IlcInstantiate is implemented. This function takes a constrained variable as its argument and binds it. More precisely, this function selects a value in the domain of the constrained variable and assigns it to the constrained variable. Solver automatically propagates the constraints posted on this constrained variable.

With the ideas about choice points and backtracking that you have just learned in mind, now you can implement IlcInstantiate by means of goals. To do so, you will use the following algorithm:

Assigning a value to (or removing a value from) a constrained variable is straightforward. To do so, use the Solver constraints == and !=.

The Solver code corresponding to IlcInstantiate for constrained integer variables is quite simple. You will see a couple versions of it to clarify a few points about goals.

As you remember, if you want to define a goal, you use a macro of the form ILCGOALn, where n is the number of arguments of the goal. The arguments of ILCGOALn are the name of the goal, followed by the types and names of the goal's arguments. Then the macro is followed by the body of a C++ function. This body defines how to execute the goal. The return value of that function is the subgoal of the goal defined by the macro itself. When there are no such subgoals, the function must return 0.

Now you can define IlcInstantiate as a choice point between two goals. Before setting a choice point, Solver checks whether the constrained integer variable has been bound, and if not, Solver selects a value in its domain. The second subgoal recursively calls IlcInstantiate.

Here is a first version of IlcInstantiate:

ILCGOAL1(IlcInstantiate, IlcIntVar, var) {
    if (var.isBound())
        return 0;
    IlcInt value = var.getMin();
    return IlcOr( var == value,
                  IlcAnd( var != value,
                          IlcInstantiate(getSolver(), var)));
}

Actually, the ILCGOALn macros define classes of IlcGoalI. As a consequence, you can use this to refer to the current goal. With that possibility in mind, here is a second version of IlcInstantiate:

ILCGOAL1(IlcInstantiate, IlcIntVar, var) {
    if (var.isBound())
        return 0;
    IlcInt value = var.getMin();
    return IlcOr( var == value,
                  IlcAnd( var != value,
                          this));
}

(The actual implementation of IlcInstantiate is slightly different since the choice of the value can be indicated by a parameter, but these two versions indicate the substance of the implementation.)

If you want to have an IloGoal object returned that can then be passed as a parameter of the IloSolver::solve and IloSolver:startNewSearch functions, use the macro ILOCPGOALWRAPPER.

For example, you can define IloInstantiate this way:

ILOCPGOALWRAPPER1(IloInstantiate, solver, IloNumVar, x){
       return IlcInstantiate(solver, solver.getIntVar(x));
}

To create an instance of this goal you write:

IloInstantiate(env, x);