Skip to content

Commit e7c6177

Browse files
authored
Merge pull request #67 from arnaud-m/feature-63
Extended logging of the solving process - close #63
2 parents 6e9584b + 9ed71f7 commit e7c6177

16 files changed

+231
-95
lines changed

src/main/java/cryptator/Cryptagen.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,24 +32,22 @@ private Cryptagen() {
3232
}
3333

3434
public static void main(final String[] args) {
35+
JULogUtil.configureDefaultLoggers();
3536
final int exitCode = doMain(args);
3637
System.exit(exitCode);
3738
}
3839

3940
public static int doMain(final String[] args) {
40-
JULogUtil.configureLoggers();
41-
int exitCode = -1;
42-
4341
CryptagenOptionsParser optparser = new CryptagenOptionsParser();
4442
if (optparser.parseOptions(args)) {
4543
final CryptagenConfig config = optparser.getConfig();
4644
final WordArray words = buildWords(config.getArguments(), config);
4745
if (words != null) {
48-
exitCode = generate(words, config);
46+
return generate(words, config);
4947
}
5048
}
5149
JULogUtil.flushLogs();
52-
return exitCode;
50+
return -1;
5351
}
5452

5553
private static List<String> readWords(final String filename) {

src/main/java/cryptator/Cryptamancer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ private static void play(final ICryptaGameEngine engine) {
105105
}
106106

107107
public static void main(final String[] args) throws Exception {
108-
JULogUtil.configureLoggers();
108+
JULogUtil.configureDefaultLoggers();
109109

110110
CryptamancerOptionsParser optparser = new CryptamancerOptionsParser();
111111
if (!optparser.parseOptions(args)) {

src/main/java/cryptator/Cryptator.java

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
*/
99
package cryptator;
1010

11-
import static cryptator.tree.TreeUtils.writePostorder;
12-
13-
import java.io.ByteArrayOutputStream;
1411
import java.util.logging.Level;
1512
import java.util.logging.Logger;
1613

@@ -24,7 +21,6 @@
2421
import cryptator.solver.CryptaSolverException;
2522
import cryptator.specs.ICryptaNode;
2623
import cryptator.specs.ICryptaSolver;
27-
import cryptator.tree.TreeUtils;
2824

2925
public final class Cryptator {
3026

@@ -34,13 +30,12 @@ private Cryptator() {
3430
}
3531

3632
public static void main(final String[] args) {
33+
JULogUtil.configureDefaultLoggers();
3734
final int exitCode = doMain(args);
3835
System.exit(exitCode);
3936
}
4037

4138
public static int doMain(final String[] args) {
42-
JULogUtil.configureLoggers();
43-
4439
CryptatorOptionsParser optparser = new CryptatorOptionsParser();
4540
if (!optparser.parseOptions(args)) {
4641
return -1;
@@ -73,7 +68,7 @@ public String getArgumentName() {
7368
@Override
7469
protected void configureLoggers() {
7570
if (config.isVerbose()) {
76-
JULogUtil.setLevel(Level.CONFIG, getLogger(), CryptaSolver.LOGGER);
71+
JULogUtil.configureLoggers(Level.ALL);
7772
}
7873
}
7974
}
@@ -88,12 +83,7 @@ private static ICryptaSolver buildSolver(final CryptatorConfig config) {
8883
public static ICryptaNode parseCryptarithm(final String cryptarithm, final CryptaParserWrapper parser,
8984
final Logger logger) throws CryptaParserException {
9085
final ICryptaNode node = parser.parse(cryptarithm);
91-
logger.log(Level.INFO, "Parse cryptarithm {0} [OK]", cryptarithm);
92-
if (logger.isLoggable(Level.CONFIG)) {
93-
final ByteArrayOutputStream os = new ByteArrayOutputStream();
94-
writePostorder(node, os);
95-
logger.log(Level.CONFIG, "Display postorder internal cryptarithm:\n{0}", os);
96-
}
86+
logger.log(Level.INFO, "Parse cryptarithm [OK]\n{0}", cryptarithm);
9787
return node;
9888

9989
}
@@ -103,16 +93,13 @@ private static long solve(final String cryptarithm, final CryptaParserWrapper pa
10393
try {
10494
final ICryptaNode node = parseCryptarithm(cryptarithm, parser, LOGGER);
10595

106-
if (LOGGER.isLoggable(Level.INFO)) {
107-
LOGGER.log(Level.INFO, "Cryptarithm features:\n{0}", TreeUtils.computeFeatures(node));
108-
}
109-
11096
final CryptaBiConsumer consumer = buildBiConsumer(config);
111-
final boolean solved = solver.solve(node, config, s -> consumer.accept(node, s));
97+
final boolean solved = solver.solve(node, config, consumer);
11298
String status = "ERROR";
11399
if (consumer.getErrorCount() == 0) {
114100
status = solved ? "OK" : "KO";
115101
}
102+
consumer.logOnLastSolution();
116103
LOGGER.log(Level.INFO, "Solve cryptarithm {0} [{1}]", new Object[] {cryptarithm, status});
117104
return consumer.getErrorCount();
118105
} catch (CryptaParserException e) {

src/main/java/cryptator/JULogUtil.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,22 @@ public static void readResourceConfigurationLoggers(final String resourcePath) {
3636
}
3737
}
3838

39-
public static void configureLoggers() {
39+
public static void configureDefaultLoggers() {
4040
readResourceConfigurationLoggers(PROPERTIES);
4141
}
4242

4343
public static void configureTestLoggers() {
4444
readResourceConfigurationLoggers(PROPERTIES);
45-
setLevel(Level.WARNING, Cryptator.LOGGER, Cryptamancer.LOGGER, Cryptagen.LOGGER, CryptaSolver.LOGGER,
46-
CryptaGameEngine.LOGGER);
45+
configureLoggers(Level.WARNING);
4746
}
4847

49-
public static void configureJsonLoggers() {
48+
public static void configureSilentLoggers() {
5049
readResourceConfigurationLoggers(PROPERTIES);
51-
setLevel(Level.INFO, Cryptator.LOGGER, Cryptamancer.LOGGER, Cryptagen.LOGGER, CryptaSolver.LOGGER,
50+
configureLoggers(Level.OFF);
51+
}
52+
53+
public static void configureLoggers(final Level level) {
54+
setLevel(level, Cryptator.LOGGER, Cryptamancer.LOGGER, Cryptagen.LOGGER, CryptaSolver.LOGGER,
5255
CryptaGameEngine.LOGGER);
5356
}
5457

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
* This file is part of cryptator, https://github.com/arnaud-m/cryptator
3+
*
4+
* Copyright (c) 2022, Université Côte d'Azur. All rights reserved.
5+
*
6+
* Licensed under the BSD 3-clause license.
7+
* See LICENSE file in the project root for full license information.
8+
*/
9+
package cryptator.choco;
10+
11+
import java.util.Formatter;
12+
import java.util.Locale;
13+
import java.util.logging.Level;
14+
import java.util.logging.Logger;
15+
16+
import org.chocosolver.solver.Model;
17+
import org.chocosolver.solver.Solution;
18+
import org.chocosolver.solver.Solver;
19+
20+
public final class ChocoLogger {
21+
22+
private final Logger logger;
23+
24+
public ChocoLogger(Logger logger) {
25+
super();
26+
this.logger = logger;
27+
}
28+
29+
public void logOnModel(final Model model) {
30+
if (logger.isLoggable(Level.CONFIG)) {
31+
logger.log(Level.CONFIG, "Model diagnostics:\n{0}", toDimacs(model));
32+
logger.log(Level.FINE, "Pretty model:{0}", model);
33+
}
34+
}
35+
36+
public void logOnSolution(final Solution solution) {
37+
if (logger.isLoggable(Level.FINER)) {
38+
solution.record();
39+
logger.log(Level.FINER, "Solver solution:\n{0}", solution);
40+
}
41+
}
42+
43+
public void logOnSolution(final Model model) {
44+
logOnSolution(new Solution(model));
45+
}
46+
47+
public void logOnSolver(Model model) {
48+
if (logger.isLoggable(Level.INFO)) {
49+
logger.log(Level.INFO, "Solver diagnostics:\n{0}", toDimacs(model.getSolver()));
50+
}
51+
}
52+
53+
public static String toDimacs(Model model) {
54+
final StringBuilder b = new StringBuilder();
55+
Formatter fmt = new Formatter(b, Locale.US);
56+
fmt.format("c MODEL_NAME %s", model.getName());
57+
fmt.format("%nd VARIABLES %d", model.getNbVars());
58+
fmt.format("%nd CONSTRAINTS %d", model.getNbCstrs());
59+
fmt.format("%nd BOOL_VARS %d", model.getNbBoolVar());
60+
fmt.format("%nd INT_VARS %d", model.getNbIntVar(false));
61+
fmt.close();
62+
return b.toString();
63+
}
64+
65+
public static String toDimacs(final Solver s) {
66+
final StringBuilder b = new StringBuilder(256);
67+
Formatter fmt = new Formatter(b, Locale.US);
68+
fmt.format("s %s", s.getSearchState());
69+
if (s.hasObjective()) {
70+
fmt.format("%no %3.f", s.getBoundsManager().getBestSolutionValue());
71+
}
72+
fmt.format(
73+
"%nd NBSOLS %d%nd TIME %.3f%nd NODES %d%nd BACKTRACKS %d%nd BACKJUMPS %d%nd FAILURES %d%nd RESTARTS %d",
74+
s.getSolutionCount(), s.getTimeCount(), s.getNodeCount(), s.getBackTrackCount(), s.getBackjumpCount(),
75+
s.getFailCount(), s.getRestartCount());
76+
fmt.close();
77+
return b.toString();
78+
}
79+
}

src/main/java/cryptator/cmd/AbstractOptionsParser.java

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99
package cryptator.cmd;
1010

11+
import java.io.ByteArrayOutputStream;
1112
import java.util.logging.Level;
1213
import java.util.logging.Logger;
1314

@@ -73,22 +74,34 @@ public final boolean parseOptions(final String[] args) {
7374
} else {
7475
getLogger().log(Level.SEVERE, "Parse arguments [FAIL]\n{0}", config.getArguments());
7576
}
77+
} else {
78+
getLogger().log(Level.SEVERE, "Check options [FAIL]");
7679
}
80+
7781
} catch (CmdLineException e) {
78-
getLogger().log(Level.SEVERE, "Parse arguments [FAIL]", e);
82+
getLogger().log(Level.SEVERE, "Parse options [FAIL]", e);
7983
}
8084

81-
// if there's a problem in the command line,
82-
// you'll get this exception. this will report
83-
// an error message.
84-
System.err.println("java " + getCommandName() + " [options...] " + getArgumentName());
85-
// print the list of available options
86-
parser.printUsage(System.err);
87-
// print option sample. This is useful some time
88-
System.err.println("\n Example: java " + getCommandName() + " " + parser.printExample(OptionHandlerFilter.ALL)
89-
+ " " + getArgumentName());
90-
getLogger().severe("Parse options [FAIL]");
85+
if (getLogger().isLoggable(Level.INFO)) {
86+
getLogger().info(buildHelpMessage(parser));
87+
}
9188
return false;
9289

9390
}
91+
92+
private String buildHelpMessage(CmdLineParser parser) {
93+
StringBuilder b = new StringBuilder();
94+
b.append(" Help:\n");
95+
b.append("java ").append(getCommandName()).append(" [options...] ").append(getArgumentName()).append("\n");
96+
final ByteArrayOutputStream os = new ByteArrayOutputStream();
97+
parser.printUsage(os);
98+
b.append(os.toString());
99+
b.append("\nExamples:");
100+
b.append("\njava ").append(getCommandName()).append(" ")
101+
.append(parser.printExample(OptionHandlerFilter.REQUIRED)).append(" ").append(getArgumentName());
102+
103+
b.append("\njava ").append(getCommandName()).append(" ").append(parser.printExample(OptionHandlerFilter.ALL))
104+
.append(" ").append(getArgumentName());
105+
return b.toString();
106+
}
94107
}

src/main/java/cryptator/cmd/CryptaBiConsumer.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.io.File;
1212
import java.io.IOException;
1313
import java.math.BigInteger;
14+
import java.util.Optional;
1415
import java.util.function.BiConsumer;
1516
import java.util.logging.Level;
1617
import java.util.logging.Logger;
@@ -32,20 +33,31 @@ public class CryptaBiConsumer implements BiConsumer<ICryptaNode, ICryptaSolution
3233

3334
private long solutionCount;
3435

36+
private Optional<ICryptaSolution> lastSolution;
37+
3538
private int errorCount;
3639

3740
private BiConsumer<ICryptaNode, ICryptaSolution> internal;
3841

3942
public CryptaBiConsumer(final Logger logger) {
4043
super();
4144
this.logger = logger;
45+
lastSolution = Optional.empty();
4246
internal = new SolutionCounter();
4347
}
4448

4549
public final long getSolutionCount() {
4650
return solutionCount;
4751
}
4852

53+
public final Optional<ICryptaSolution> getLastSolution() {
54+
return lastSolution;
55+
}
56+
57+
public final Optional<ICryptaSolution> getUniqueSolution() {
58+
return solutionCount <= 1 ? lastSolution : Optional.empty();
59+
}
60+
4961
public final int getErrorCount() {
5062
return errorCount;
5163
}
@@ -71,10 +83,18 @@ public void accept(final ICryptaNode t, final ICryptaSolution u) {
7183
internal.accept(t, u);
7284
}
7385

86+
public void logOnLastSolution() {
87+
if (lastSolution.isPresent()) {
88+
logger.log(Level.INFO, "Last cryptarithm solution #{0}:\n{1}",
89+
new Object[] {solutionCount, lastSolution.get()});
90+
}
91+
}
92+
7493
private class SolutionCounter implements BiConsumer<ICryptaNode, ICryptaSolution> {
7594

7695
@Override
7796
public void accept(final ICryptaNode t, final ICryptaSolution u) {
97+
lastSolution = Optional.of(u);
7898
solutionCount++;
7999
}
80100
}
@@ -113,15 +133,15 @@ private class SolutionChecker implements BiConsumer<ICryptaNode, ICryptaSolution
113133
public void accept(final ICryptaNode n, final ICryptaSolution s) {
114134
try {
115135
if (eval.evaluate(n, s, base).compareTo(BigInteger.ZERO) != 0) {
116-
logger.info("Eval cryptarithm solution [OK]");
117-
return;
136+
logger.log(Level.CONFIG, "Eval cryptarithm solution #{0} [OK]", solutionCount);
118137
} else {
119-
logger.severe("Eval cryptarithm solution [KO]");
138+
errorCount++;
139+
logger.log(Level.SEVERE, "Eval cryptarithm solution #{0} [KO]", solutionCount);
120140
}
121141
} catch (CryptaEvaluationException e) {
122-
logger.log(Level.SEVERE, "Eval cryptarithm solution [FAIL]", e);
142+
errorCount++;
143+
logger.log(Level.SEVERE, e, () -> "Eval cryptarithm solution #" + solutionCount + " [FAIL]");
123144
}
124-
errorCount++;
125145
}
126146
}
127147

@@ -134,10 +154,10 @@ public void accept(final ICryptaNode n, final ICryptaSolution s) {
134154
final Graph graph = GraphvizExport.exportToGraphviz(n, s);
135155
final File file = File.createTempFile("cryptarithm-", ".svg");
136156
Graphviz.fromGraph(graph).width(WIDTH).render(Format.SVG).toFile(file);
137-
logger.log(Level.INFO, "Export cryptarithm solution [OK]\n{0}", file);
157+
logger.log(Level.INFO, "Export cryptarithm solution #{0} [OK]\n{1}",
158+
new Object[] {solutionCount, file});
138159
} catch (IOException e) {
139-
logger.log(Level.SEVERE, "Export cryptarithm solution [FAIL]", e);
140-
160+
logger.log(Level.SEVERE, e, () -> "Export cryptarithm solution #" + solutionCount + " [FAIL]\n");
141161
}
142162
}
143163

0 commit comments

Comments
 (0)