Skip to content

Commit

Permalink
Add CPProfiler back + MiniZinc support
Browse files Browse the repository at this point in the history
  • Loading branch information
cprudhom committed Jun 13, 2024
1 parent 685580b commit cb7b6cf
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 24 deletions.
17 changes: 17 additions & 0 deletions parsers/src/main/java/org/chocosolver/parser/RegParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.chocosolver.solver.search.strategy.BlackBoxConfigurator;
import org.chocosolver.solver.search.strategy.Search;
import org.chocosolver.solver.search.strategy.SearchParams;
import org.chocosolver.solver.trace.CPProfiler;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.solver.variables.Variable;
import org.chocosolver.util.tools.VariableUtils;
Expand All @@ -30,6 +31,7 @@
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
Expand Down Expand Up @@ -173,6 +175,9 @@ public abstract class RegParser implements IParser {
@Option(name = "-dfx", usage = "Force default explanation algorithm.")
public boolean dftexp = false;

@Option(name = "--cp-profiler", usage = "Connect to CP-Profiler. Two comma-separated values are expected: the execution id and the port.")
public String cpProfiler = null;

/**
* Default settings to apply
*/
Expand Down Expand Up @@ -339,7 +344,19 @@ public final void solve() {
getModel().getSolver().log().white().printf("Problem solving starts at %s\n", dtf.format(now));
}
if (portfolio.getModels().size() == 1) {
CPProfiler profiler = null;
if (cpProfiler != null) {
String[] params = cpProfiler.split(",");
profiler = new CPProfiler(getModel().getSolver(), Integer.parseInt(params[0]), Integer.parseInt(params[1]), false);
}
singleThread();
if (cpProfiler != null) {
try {
profiler.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} else {
manyThread();
}
Expand Down
4 changes: 2 additions & 2 deletions parsers/src/main/minizinc/choco.msc
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"id": "org.choco.choco",
"name": "Choco-solver",
"description": "Choco FlatZinc executable",
"version" : "4.10.14",
"version" : "4.10.15",
"mznlib" : "/Users/kyzrsoze/Sources/CHOCO/continuous-branch/parsers/src/main/minizinc/mzn_lib/",
"executable" : "/Users/kyzrsoze/Sources/CHOCO/continuous-branch/parsers/src/main/minizinc/fzn-choco",
"tags": ["cp","int"],
"stdFlags": ["-a","-f","-n","-p","-r","-s","-t"],
"stdFlags": ["-a","-f","-n","-p","-r","-s","-t","--cp-profiler"],
"supportsMzn": false,
"supportsFzn": true,
"needsSolns2Out": true,
Expand Down
18 changes: 13 additions & 5 deletions parsers/src/main/minizinc/fzn-choco
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@ OPTIONS:
-jar <j>
Override the jar file. (The default is $CHOCO_JAR.)
--cp-profiler id,port
Enable the cp-profiler with the given id and port.
--jargs <args>
Override default java argument (The default is $JAVA_ARGS.)
Override default java argument (The default is $JAVA_ARGS.)
EXAMPLES:
Expand Down Expand Up @@ -112,10 +115,15 @@ do
shift
;;

--jargs)
JAVA_ARGS="$2"
shift
;;
--jargs)
JAVA_ARGS="$2"
shift
;;

--cp-profiler)
ARGS="$ARGS --cp-profiler $2"
shift
;;

-*)
echo "$0: unknown option \`$1'" 1>&2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ OPTIONS:
Override the jar file. (The default is %CHOCO_JAR%.)

--jargs <args>
Override default java argument (The default is %JAVA_ARGS%.)
Override default java argument (The default is %JAVA_ARGS%.)

--cp-profiler <id>,<port>
Enable the cp-profiler with the given id and port.

EXAMPLES:

Expand Down Expand Up @@ -102,6 +105,10 @@ if /i "%~1"=="-jar" (
set "CHOCO_JAR=%~2"
shift
)else
if /i "%~1"=="--cp-profiler" (
set ARGS=%ARGS%" --cp-profiler %~2"
shift
)else
if /i "%~1"=="--jargs" (
set "JAVA_ARGS=%~2"
shift
Expand Down
130 changes: 130 additions & 0 deletions solver/src/main/java/org/chocosolver/solver/trace/CPProfiler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* This file is part of choco-solver, http://choco-solver.org/
*
* Copyright (c) 2024, 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 cpp.Connector;
import cpp.Message;
import org.chocosolver.solver.Solver;

import java.io.Closeable;
import java.io.IOException;

/**
* A search monitor to send data to <a href="https://github.com/cp-profiler/cp-profiler">cp-profiler</a>.
* It enables to profile and to visualize Constraint Programming. An installation is needed and is
* described <a href="https://github.com/cp-profiler/cp-profiler">here</a>. This monitor relies on
* its <a href="https://github.com/cp-profiler/java-integration">java integration</a>. <p> Note that
* CPProfiler is {@link Closeable} and can be used as follow: <p>
* <pre> {@code
* Model model = ProblemMaker.makeCostasArrays(7);
* try (CPProfiler profiler = new CPProfiler(model)) {
* while (model.getSolver().solve()) ;
* out.println(model.getSolver().getSolutionCount());
* }
* }</pre>
* <p> <p> Created by cprudhom on 22/10/2015. Project: choco.
*
* @author Charles Prud'homme
* @since 3.3.2
*/
public class CPProfiler extends SearchViz {

/**
* Used to communicate every node
*/
private Connector connector;

/**
* Active connection to <a href="https://github.com/cp-profiler/cp-profiler">cp-profiler</a>.
* This requires cp-profiler to be installed and launched before.
*
* @param aSolver solver to observe resolution
*/
public CPProfiler(Solver aSolver) {
this(aSolver, -1, 6565, false);
}

/**
* Active connection to <a href="https://github.com/cp-profiler/cp-profiler">cp-profiler</a>.
* This requires cp-profiler to be installed and launched before.
*
* @param aSolver solver to observe resolution
* @param sendDomain set to <i>true</i> to send domain into 'info' field (beware, it can
* increase the memory consumption and slow down the overall execution), set
* to <i>false</i> otherwise.
*/
public CPProfiler(Solver aSolver, int executionId, int port, boolean sendDomain) {
super(aSolver, sendDomain);
connect(aSolver.getModelName(), executionId, port);
}

protected boolean connect(String label, int executionId, int port) {
if (connector == null) {
connector = new Connector(port); // 6565 is the port used by cpprofiler by default
}
try {
connector.connect();
connector.start(label, executionId, true); // starting a new tree (also used in case of a restart)
} catch (IOException e) {
System.err.println("Unable to connect to CPProfiler, make sure it is started. No information will be sent.");
return false;
}
return true;
}

@Override
protected void disconnect() {
if (connected) {
try {
connector.done();
connector.disconnect();
} catch (IOException e) {
System.err.println("Unable to disconnect CPProfiler.");
}
}
}

@Override
protected void sendNode(int nc, int pid, int alt, int kid, int rid, String label, String info) {
send(nc, pid, alt, kid, rid, Message.NodeStatus.BRANCH, label, info);
}

@Override
protected void sendSolution(int nc, int pid, int alt, int kid, int rid, String label, String info) {
send(nc, pid, alt, kid, rid, Message.NodeStatus.SOLVED, label, info);
}

@Override
protected void sendFailure(int nc, int pid, int alt, int kid, int rid, String label, String info) {
send(nc, pid, alt, kid, rid, Message.NodeStatus.FAILED, label, info);
}

@Override
protected void sendRestart(int rid) {
try {
connector.restart(rid);
} catch (IOException e) {
System.err.println("Lost connection with CPProfiler. No more information will be sent.");
connected = false;
}
}

private void send(int nc, int pid, int alt, int kid, int rid, Message.NodeStatus status, String label, String info) {
try {
connector.createNode(nc, pid, rid, alt, kid, status)
.setInfo(info)
.setLabel(label)
.send();
} catch (IOException e) {
System.err.println("Lost connection with CPProfiler. No more information will be sent.");
connected = false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,6 @@ public GephiGenerator(String gexfFile, Solver aSolver) {
this.edges = new StringBuilder();
}

@Override
protected boolean connect(String label) {
return true;
}

@Override
protected void disconnect() {
Path file = Paths.get(instance);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,6 @@ public GraphvizGenerator(String gvFile, Solver aSolver) {
connected = true;
}


@Override
protected boolean connect(String label) {
return true;
}

@Override
protected void disconnect() {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,16 +136,12 @@ public String print() {
public SearchViz(Solver aSolver, boolean sendDomain) {
this.mSolver = aSolver;
this.sendDomain = sendDomain;
if(connected = connect(mSolver.getModel().getName())) {
mSolver.plugMonitor(this);
}
mSolver.plugMonitor(this);
alt_stack.push(-1); // -1 is alt for the root node
pid_stack.push(-1); // -1 is pid for the root node
last_stack.push(-1);
}

protected abstract boolean connect(String label);

protected abstract void disconnect();

protected abstract void sendNode(int nc, int pid, int alt, int kid, int rid, String label, String info);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* This file is part of choco-solver, http://choco-solver.org/
*
* Copyright (c) 2022, 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.search.loop.monitors;

import org.chocosolver.solver.Model;
import org.chocosolver.solver.search.loop.lns.neighbors.RandomNeighborhood;
import org.chocosolver.solver.trace.CPProfiler;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.util.ProblemMaker;
import org.testng.annotations.Test;

import java.io.IOException;

import static java.lang.System.out;

/**
* <p>
* Project: choco-solver.
*
* @author Charles Prud'homme
* @since 13/09/2016.
*/
public class CPProfilerTest {

@Test(groups = "1s", timeOut = 60000)
public void test1() throws IOException {
Model s1 = ProblemMaker.makeCostasArrays(7);
try (CPProfiler profiler = new CPProfiler(s1.getSolver())) {
while (s1.getSolver().solve()) ;
out.println(s1.getSolver().getSolutionCount());
}
}

@Test(groups = "1s", timeOut = 60000)
public void test2() throws IOException {
Model s1 = ProblemMaker.makeCostasArrays(7);
CPProfiler profiler = new CPProfiler(s1.getSolver());
while (s1.getSolver().solve()) ;
out.println(s1.getSolver().getSolutionCount());
profiler.close();
}

@Test(groups = "1s", timeOut = 60000)
public void test3() throws IOException {
Model s1 = ProblemMaker.makeGolombRuler(11);
s1.getSolver().setLNS(new RandomNeighborhood((IntVar[]) s1.getHook("ticks"), 10, 0));
CPProfiler profiler = new CPProfiler(s1.getSolver());
s1.getSolver().limitSolution(9);
while (s1.getSolver().solve()) ;
out.println(s1.getSolver().getSolutionCount());
profiler.close();
}

}

0 comments on commit cb7b6cf

Please sign in to comment.