All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.chocosolver.solver.trace.IOutputFactory Maven / Gradle / Ivy

The newest version!
/*
 * This file is part of choco-solver, http://choco-solver.org/
 *
 * Copyright (c) 2025, 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.ISelf;
import org.chocosolver.solver.Solver;
import org.chocosolver.solver.propagation.PropagationEngineObserver;
import org.chocosolver.solver.propagation.PropagationObserver;
import org.chocosolver.solver.propagation.PropagationProfiler;
import org.chocosolver.solver.search.loop.monitors.*;
import org.chocosolver.solver.variables.Variable;
import org.chocosolver.util.tools.StringUtils;

import java.io.Closeable;
import java.io.File;
import java.io.PrintWriter;
import java.util.Arrays;

/**
 * This aims at simplifying resolution trace output by providing
 * a unique entry point for most (not to say all) resolution message.
 * 
* * @author Charles Prud'homme * @version choco * @since 12/11/14 */ public interface IOutputFactory extends ISelf { /** * Default welcome message */ String WELCOME_MESSAGE = "** Choco 5.0.0-beta.1 (2025-02) : Constraint Programming Solver, Copyright (c) 2010-2025"; /** * Print the version message. */ default void printVersion() { ref().log().bold().blue().println(WELCOME_MESSAGE); } /** * Print (succint) features of the solver given in argument */ default void printFeatures() { ref().getMeasures().setReadingTimeCount(System.nanoTime() - ref().getModel().getCreationTime()); ref().log().printf("- Model[%s] features:\n", ref().getModel().getName()); ref().log().printf("\tLCG : %s\n", ref().isLCG()); ref().log().printf("\tVariables : %d\n", ref().getModel().getNbVars()); ref().log().printf("\tConstraints : %d\n", ref().getModel().getNbCstrs()); ref().log().printf("\tBuilding time : %.3fs\n", ref().getMeasures().getReadingTimeCount()); ref().log().printf("\tUser-defined search strategy : %s\n", ref().getModel().getSolver().isDefaultSearchUsed() ? "no" : "yes"); ref().log().printf("\tComplementary search strategy : %s\n", ref().isSearchCompleted() ? "yes" : "no"); } /** * Print (succint) features of the solver given in argument in a single line. */ default void printShortFeatures() { ref().getMeasures().setReadingTimeCount(System.nanoTime() - ref().getModel().getCreationTime()); String st = "Model[" + ref().getModelName() + "], " + String.format( "%d variables, %d constraints, building time: %.3fs, %s user-defined search strategy, %s complementary search strategy", ref().getModel().getNbVars(), ref().getModel().getNbCstrs(), ref().getMeasures().getReadingTimeCount(), ref().getModel().getSolver().isDefaultSearchUsed() ? "w/" : "w/o", ref().isSearchCompleted() ? "w/" : "w/o"); ref().log().bold().println(st); } /** * Print the resolution statistics. *

* Recommended usage: to be called after the resolution step. */ default void printStatistics() { printVersion(); printFeatures(); ref().log().println(ref().getMeasures().toString()); } /** * Output the resolution statistics in a single line. *

* Recommended usage: to be called after the resolution step. */ default void printShortStatistics() { ref().log().println(ref().getMeasures().toOneLineString()); } /** * Output the resolution statistics in a comma-separated single line. * The header is: *

     *     solutionCount;buildingTime(sec);initTime(sec);initPropag(sec);totalTime(sec);objective;nodes;backtracks;fails;restarts;fineProp;coarseProp;
     * 
*/ default void printCSVStatistics() { ref().log().println(ref().getMeasures().toCSV()); } /** * Plug a search monitor which calls {@link #printVersion()} * and {@link #printStatistics()} before closing the search. *

* Recommended usage: to be called before the resolution step. */ default void showStatistics() { ref().plugMonitor(new IMonitorInitialize() { @Override public void beforeInitialize() { printVersion(); printFeatures(); } }); ref().plugMonitor(new IMonitorClose() { @Override public void afterClose() { ref().log().println(ref().getMeasures().toString()); } }); } /** * Plug a search monitor which calls {@link #printShortStatistics()} before closing the search. *

* Recommended usage: to be called before the resolution step. */ default void showShortStatistics() { ref().plugMonitor(new IMonitorClose() { @Override public void beforeClose() { printShortStatistics(); } }); } /** * Calls {@link #printShortStatistics()} before the program ends (normally or not)? * This adds a shutdown hook. *

* Recommended usage: to be called before the resolution step. */ default void showShortStatisticsOnShutdown() { Runtime.getRuntime().addShutdownHook(new Thread(() -> ref().printShortStatistics())); } /** * Plug a search monitor which outputs {@code message} on each solution. *

* Recommended usage: to be called before the resolution step. * * @param message the message to print. */ default void showSolutions(final IMessage message) { ref().plugMonitor((IMonitorSolution) () -> ref().log().println(message.print())); } /** * Plug a search monitor which outputs a message on each solution. *

* Recommended usage: to be called before the resolution step. * * @see IOutputFactory.DefaultSolutionMessage */ default void showSolutions() { showSolutions(new DefaultSolutionMessage(ref())); } /** * Plug a search monitor which outputs a message on each solution, based on the variables * given in parameters. *

* Recommended usage: to be called before the resolution step. * * @see IOutputFactory.DefaultSolutionMessage */ default void showSolutions(Variable... variables) { showSolutions(new DefaultSolutionMessage(ref(), variables)); } /** * Plug a search monitor which outputs {@code message} on each decision. *

* Recommended usage: to be called before the resolution step. * * @param message the message to print. */ default void showDecisions(final IMessage message) { ref().plugMonitor(new IMonitorDownBranch() { @Override public void beforeDownBranch(boolean left) { ref().log().printf("%s %s ", StringUtils.pad("", ref().getEnvironment().getWorldIndex(), "."), ref().getDecisionPath().lastDecisionToString()); ref().log().printf(" // %s \n", message.print()); } }); } /** * Plug a search monitor which outputs a message on each decision. *

* Recommended usage: to be called before the resolution step. * * @see IOutputFactory.DefaultSolutionMessage */ default void showDecisions() { showDecisions(120); } /** * Plug a search monitor which outputs a message on each decision. *

* Recommended usage: to be called before the resolution step. * * @param nChars maximum number of characters to output * * @see IOutputFactory.DefaultSolutionMessage */ default void showDecisions(int nChars) { showDecisions(new DefaultDecisionMessage(ref(), nChars)); } /** * Plug a search monitor which outputs {@code message} on each restart. * *

* Recommended usage: to be called before the resolution step. * * @param message the message to print. */ default void showRestarts(final IMessage message) { ref().plugMonitor(new IMonitorRestart() { @Override public void afterRestart() { ref().log().printf("RUNS %d ", ref().getRestartCount()); ref().log().printf(" // %s \n", message.print()); } }); } default void showRestarts() { showRestarts(() -> ref().toOneLineString()); } /** * Plug a search monitor which outputs the contradictions thrown during the search. */ default void showContradiction() { ref().plugMonitor((IMonitorContradiction) cex -> ref().log().red().println(String.format("\t/!\\ %s", cex.toString()))); } /** * Plug a search monitor which prints a one-line statistics every {@code f} ms. * * @param f frequency, in millisecond */ default void showStatisticsDuringResolution(long f) { if (f > 0) { ref().plugMonitor(new LogStatEveryXXms(ref(), f)); } } /** * Plug a search monitor which prints an array-like statistics during solving like: *

*

     *         {@code
     *           Objective        |              Measures              |     Progress
     *      CurrentDomain BestBnd | Depth Decisions WrongDecs Restarts | SolCount   Time |
     *        0    47939       -- |    14      1478    71,04%        2 |        0     1s |
     *        3    47536       -- |    18      1878    98,67%        2 |        0     2s |
     *    14626    14626    14626 |   543       499    29,26%        0 |        1    40s |*
     *       ...
     *         }
     *     
*

* Solutions are starred. * It uses ASCII code for a better rendering. */ default void verboseSolving(long frequencyInMilliseconds) { ref().plugMonitor(new VerboseSolving(ref(), frequencyInMilliseconds)); } /** * Create and show a simple dashboard that render resolution statistics every 100 milliseconds. */ default void showDashboard() { this.showDashboard(100L); } /** * @Deprecated use {@link #observeSolving()} instead */ @Deprecated default void showDashboard(long refresh) { } /** *

* Plug a propagation observer. * It observes activities of propagators and modifications of variables. * Note, that this may impact the resolution statistics, since very fine events recording is done. *

* * @see #profilePropagation() */ default void observePropagation(PropagationObserver po) { ref().setEngine(new PropagationEngineObserver(ref().getModel(), po)); } /** *

* Plug a propagation profiler. * It records activities of propagators and modifications of variables. * Note, that this may impact the resolution statistics, since very fine events recording is done. *

*

* Once plugged, calls to {@link PropagationProfiler#writeTo(File, boolean)} * or {@link PropagationProfiler#writeTo(PrintWriter, boolean)} will * outuput the profiling data to a file (or a writer). *

*
 {@code
     * Solver s = m.getSolver();
     * PropagationProfiler profiler = s.profilePropagation();
     * s.findSolution();
     * profiler.writeTo(new File("profiling.txt"));
     * }
* * @return a propagation profiler */ default PropagationProfiler profilePropagation() { PropagationProfiler po = new PropagationProfiler(ref().getModel()); ref().observePropagation(po); return po; } /** * Create and return a {@link SolvingStatisticsFlow} object to observe solving statistics. *

* Then, any call to {@link SolvingStatisticsFlow#toJSON()} will return a JSON String with the updated statistics. *
* An example of usage is: *

     *      Solver solver = model.getSolver();
     *      Thread printer = new Thread(() -> {
     *          try {
     *              while (true) {
     *                  Thread.sleep(5);
     *                  System.out.printf("%s\n", SolvingStatisticsFlow.toJSON(solver));
     *              }
     *          } catch (InterruptedException e) {}
     *      });
     *      printer.start();
     *      while(solver.solve());
     *      printer.interrupt();
     *  
* * @return a {@link SolvingStatisticsFlow} object to observe solving statistics. */ default SolvingStatisticsFlow observeSolving() { return new SolvingStatisticsFlow(ref()); } /** * Populate a DOT file (gvFilename with search tree to be vizualized with * Graphviz. * * @param gvFilename dot filename * @return a {@link Closeable} object to be closed at the end of resolution */ default Closeable outputSearchTreeToGraphviz(String gvFilename) { return new GraphvizGenerator(gvFilename, this.ref()); } /** * Populate a GEXF file (gexfFilename with search tree to be vizualized with * Gephi. * * @param gexfFilename dot filename * @return a {@link Closeable} object to be closed at the end of resolution */ default Closeable outputSearchTreeToGephi(String gexfFilename) { return new GephiGenerator(gexfFilename, this.ref()); } /** * @deprecated */ @Deprecated default Closeable outputSearchTreeToCPProfiler(boolean domain) { return null; } /** * Populate a GEXF file (gexfFilename with constraint netwok to be vizualized with * Gephi. * * @param gexfFilename dot filename */ default void constraintNetworkToGephi(String gexfFilename) { GephiNetwork.write(gexfFilename, this.ref().getModel()); } ////////////// /** * The default solution message format */ class DefaultSolutionMessage implements IMessage { /** * Solver to output */ private final Solver solver; private Variable[] vars; /** * Create a solution message * * @param solver solver to output */ public DefaultSolutionMessage(Solver solver) { this(solver, null); } /** * Create a solution message * * @param solver solver to output * @param vars variables to output */ public DefaultSolutionMessage(Solver solver, Variable[] vars) { this.solver = solver; this.vars = vars; } @Override public String print() { if (vars == null) { vars = Arrays.stream(solver.getSearch().getVariables()).distinct().toArray(Variable[]::new); } return String.format("- Solution #%s found. %s \n\t%s.", solver.getSolutionCount(), solver.getMeasures().toOneLineString(), printVars() ); } private String printVars() { StringBuilder s = new StringBuilder(32); for (Variable v : vars) { s.append(v).append(' '); } return s.toString(); } } /** * The default decision message format */ class DefaultDecisionMessage implements IMessage { /** * Solver to output */ private final Solver solver; private final int limit; /** * Create a decision message * * @param solver solver to output * @param nChars maximum number of characters to output */ public DefaultDecisionMessage(Solver solver, int nChars) { this.solver = solver; this.limit = nChars; } @Override public String print() { Variable[] vars = solver.getSearch().getVariables(); StringBuilder s = new StringBuilder(32); for (int i = 0; i < vars.length && s.length() < limit; i++) { s.append(vars[i]).append(' '); } if (s.length() >= limit) { s.append("..."); } return s.toString(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy