Debugging and tracing

In this chapter, you will learn how to use Artelys Kalis in debugging and tracing mode. The following parts will be discussed:

  • managing outputs ;

  • managing exceptions generated by Artelys Kalis.

Using print methods for debugging

Different methods for printing information on the current states of the variables and constraints are available for debugging purposes:

class KProblem
print()
Print the problem name.
Print the domains of variables linked to the problem.
Print the list of all the constraints posted to the problem.
Print the list of all the disjunctions posted to the problem and their status.

Note

The status of a disjunction can be either Known if the solver has proved that a branch of the disjunction must be true or false, or Unknown when the solver does not know yet the status of the branch.

printVariablesStates()

Print the domains of variables linked to the problem.

printDisjunctionStates()

Print the list of all the disjunctions posted to the problem.

printMinimalConflictSet()

Print the minimal conflict set of the problem.

computeMinimalConflictSet()

Return a KConstraintArray*() of the minimal conflict set of the problem.

Example of use :

problem.pushWorld();
if (problem.propagate()) {
    printf("Problem is infeasible\n");

    problem.popWorld();
    problem.printMinimalConflictSet();
}
class KIntVar
print()

Print the name of the variable and output its current domain (possibly reduced by propagation).

class KConstraint
print()

Print the constraint name.

Using callbacks for debugging

Warning

The use of callbacks for debugging is deprecated since version 8.0. It will be removed in future versions. Instead users shall use KSolverEventListener to reproduce the callbacks functionalities in a more object-oriented manner (see next section).

Different callbacks functions can be specified in reaction to a specific event. The different callbacks and their corresponding events are listed in the following table:

Triggering event

Method

A solution has been found

KSolver::setSolutionFunctionPtr()

The solver opens a node

KSolver::setNodeFunctionPtr()

The solver goes down/up a branch

KSolver::setBranchFunctionPtr()

A new branching scheme is used

KSolver::setBranchingSchemeFunctionPtr()

The following code sample shows how to define and specify a function solution_found() that will be called when a solution will be found by the solver:

int solution_found(void *param)
{
    KProblem * p = (KProblem *) param;
    p->getSolution().printResume();
    return 0;
}

KSolver solver();
solver.setSolutionFunctionPtr(solution_found,&problem);

Using KSolverEventListener

The KSolverEventListener class is an interface that should be implemented in order to debug or even control the search. The implemented method will be called in reaction to specific search events. The different listener methods and their corresponding events are listed in the following table:

Triggering event

Method

A solution has been found

KSolverEventListener::solutionFound()

The solver opens a node

KSolverEventListener::nodeExplored()

The solver goes down a branch

KSolverEventListener::branchGoDown()

The solver goes up a branch

KSolverEventListener::branchGoUp()

A new branching scheme is used

KSolverEventListener::branchingSchemeSwitch()

In addition, the method KSolverEventListener::stopComputations() can be implemented in order to control the termination of the search. This method is called at each node and shall return true if the search must be terminated. In such case, the integer attribute KSolver::SearchLimitReached() will be set to the value KSolver::SearchLimitedByUser().

The following code sample shows how to define and specify a listener SolutionListener that will display each solution found and that will terminate the search if at least 5 solutions have been found:

class SolutionListener: public KSolverEventListener
{
    SolutionListener(KProblem* problem): KSolverEventListener(problem) {}

    void solutionFound(const KSolution& solution)
    {
        solution.printResume();
    }

    bool stopComputations()
    {
        if (getProblem()->getNumberOfSolutions() >= 5)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
};

KProblem problem(/* … */);
KSolver solver(/* … */);
SolutionListener solutionListener(&problem);
solver.setSolverEventListener(&solutionListener);

Total time spent in user callbacks can be retrieved from the solver attributes:

double cbTime = solver.getDblAttrib(KSolver::CallBackTime);

Managing exceptions

Artelys Kalis uses the standard C++ exception mechanism to inform your application that an exception was raised. Artelys Kalis offers a special exception object named ArtelysException that can be used to know what kind of error occured. ArtelysException gives two informations: an error code and an error message that describes the error.

To catch Artelys Kalis exceptions, just enclose your code like in the example:

try
{
    /* Your application code goes here */
}
catch (ArtelysException &artelysException)
{
    cout << "Exception " << artelysException.getCode() << " raised:" << artelysException.getMessage() << endl;
}