org.chocosolver.solver.trace.VerboseSolving Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of choco-solver Show documentation
Show all versions of choco-solver Show documentation
Open-source constraint solver.
/*
* This file is part of choco-solver, http://choco-solver.org/
*
* Copyright (c) 2023, IMT Atlantique. All rights reserved.
*
* Licensed under the BSD 4-clause license.
*
* See LICENSE file in the project root for full license information.
*/
package org.chocosolver.solver.trace;
import org.chocosolver.solver.Solver;
import org.chocosolver.solver.search.loop.monitors.IMonitorClose;
import org.chocosolver.solver.search.loop.monitors.IMonitorInitialize;
import org.chocosolver.solver.search.loop.monitors.IMonitorSolution;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.util.ESat;
import org.chocosolver.util.tools.StringUtils;
/**
* A search monitor logger which prints statistics every XX ms.
*
*
* @author Charles Prud'homme
* @since 18 aug. 2010
*/
public class VerboseSolving implements IMonitorInitialize, IMonitorSolution, IMonitorClose {
/**
* A thread which prints short line statistics.
*/
private final Thread printer;
private final Solver solver;
private final long[] counters = new long[3];
/**
* A boolean to kill the printer when the resolution ends.
*/
private volatile boolean alive;
private int calls = 0;
/**
* Create a monitor which outputs shot-line statistics every duration milliseconds
*
* @param solver the solver to instrument
*/
public VerboseSolving(final Solver solver, final long duration) {
this.solver = solver;
printer = new Thread(() -> {
alive = true;
try {
Thread.sleep(duration);
do {
body(false);
//noinspection BusyWait
Thread.sleep(duration);
} while (alive);
} catch (InterruptedException ignored) {
}
});
printer.setDaemon(true);
}
@Override
public void afterInitialize(boolean correct) {
if (correct) {
if(!printer.isAlive())
printer.start();
}
}
@Override
public void onSolution() {
body(true);
}
@Override
public void afterClose() {
if (solver.isFeasible().equals(ESat.FALSE)) {
alive = false;
printer.interrupt();
}
}
private void header() {
boolean opt = solver.getObjectiveManager().isOptimization();
solver.log().white().printf((opt ? " Objective |" : "")
+ " Measures | Progress %n" +
(opt ? " CurrentDomain BestBnd |" : "")
+ " Depth Decisions WrongDecs Restarts | SolCount Time |%n"
);
}
private void body(boolean onSol) {
if((calls % 20) == 0){
header();
}
boolean opt = solver.getObjectiveManager().isOptimization();
if (opt) {
bodyOpt(onSol);
} else {
bodySat(onSol);
}
counters[0] = solver.getNodeCount();
counters[1] = solver.getFailCount();
counters[2] = solver.getRestartCount();
calls++;
}
private void bodySat(boolean onSol) {
solver.log().white().printf("%s %5d %9d %8.2f%% %8d | %8d %5.0fs |%s%n%s",
onSol ? StringUtils.ANSI_BOLD + StringUtils.ANSI_BLACK : StringUtils.ANSI_WHITE,
solver.getCurrentDepth(),
solver.getNodeCount() - counters[0],
(solver.getFailCount() - counters[1]) * 100f / (solver.getNodeCount() - counters[0]),
solver.getRestartCount() - counters[2],
solver.getSolutionCount(),
solver.getTimeCount(),
onSol ? "*" : "",
StringUtils.ANSI_RESET
);
}
private void bodyOpt(boolean onSol) {
IntVar obj = solver.getObjectiveManager().getObjective().asIntVar();
Number best = solver.getObjectiveManager().getBestSolutionValue();
solver.log().white().printf("%s%8d %8d %8s | %5d %9d %8.2f%% %8d | %8d %5.0fs |%s%n%s",
onSol ? StringUtils.ANSI_BOLD + StringUtils.ANSI_BLACK : StringUtils.ANSI_WHITE,
obj.getLB(),
obj.getUB(),
solver.getSolutionCount() > 0 ? best : "--",
solver.getCurrentDepth(),
solver.getNodeCount() - counters[0],
(solver.getFailCount() - counters[1]) * 100f / (solver.getNodeCount() - counters[0]),
solver.getRestartCount() - counters[2],
solver.getSolutionCount(),
solver.getTimeCount(),
onSol ? "*" : "",
StringUtils.ANSI_RESET
);
}
}