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(); }
problem.pushWorld() if problem.propagate(): print("Problem is infeasible") problem.popWorld() problem.printMinimalConflictSet()
problem.pushWorld(); if (problem.propagate()) { System.out.println("Problem is infeasible"); problem.popWorld(); problem.printMinimalConflictSet(); }
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 |
|
The solver opens a node |
|
The solver goes down/up a branch |
|
A new branching scheme is used |
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);
# myPythonCallBack class is defined and derived from C++ class KPyCallBack.
# It has to implement a 'call' function taking no argument.
class MySolutionCallBack(KPyCallBack):
def __init__(self, p):
# Call C++ base class constructor
KPyCallBack.__init__(self)
self.problem = p
def call(self):
print('Solution callback called')
self.problem.display()
return 0
solver = KSolver(problem)
solutionCb = MySolutionCallBack(problem)
setSolutionFunctionPtr(solver, solutionCb)
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 |
|
The solver opens a node |
|
The solver goes down a branch |
|
The solver goes up a branch |
|
A new branching scheme is used |
|
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);
class SolutionListener(KSolverEventListener):
def __init__(self, problem: KProblem):
KSolverEventListener.__init__(self, problem)
def solutionFound(self, solution: KSolution, thread_id: int):
solution.printResume()
def stopComputations(self):
if self.getProblem().getNumberOfSolutions() >= 5:
return True
else:
return False
solver = KSolver(problem)
solutionListener = SolutionListener(problem)
solver.setSolverEventListener(solutionListener)
class MySolverEventListener extends KSolverEventListener
{
public void nodeExplored() {
System.out.println("Node explored");
}
public void branchGoDown() {
System.out.println("Branch go down");
}
public void branchGoUp() {
System.out.println("Branch go up");
}
public void branchingScheme() {
}
public boolean stopComputations() {
return false;
}
public void solutionFound() {
System.out.println("A solution has been found!");
}
}
KSolver solver = new KSolver(problem,myBa);
solver.setSolverEventListener(new MySolverEventListener());
Total time spent in user callbacks can be retrieved from the solver attributes:
double cbTime = solver.getDblAttrib(KSolver::CallBackTime);
cbTime = solver.getDblAttrib(solver.CallBackTime)
double cbTime = solver.getDblAttrib(KSolver.DblAttrib.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;
}
try:
# Your application code goes here
except ArtelysException as e:
print("Exception ", e.getCode(), " raised: ", e.getMessage())
try {
// Your application code goes here
}
catch (Exception e)
{
e.printStackTrace();
}