/**
* Copyright 2010 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.drools.planner.examples.nurserostering.competition;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Map;
import java.util.TreeMap;
import org.apache.commons.io.IOUtils;
import org.drools.planner.core.score.HardAndSoftScore;
import org.drools.planner.examples.common.app.LoggingMain;
import org.drools.planner.examples.common.business.SolutionBusiness;
import org.drools.planner.examples.nurserostering.app.NurseRosteringApp;
/**
* @author Geoffrey De Smet
*/
public class NurseRosteringEvaluatorHelper extends LoggingMain {
private static final boolean ALL_INPUT_FILES = true;
private static final String INPUT_FILE_PREFIX = "long_late04";
private static final String OUTPUT_FILE_SUFFIX = "_geoffrey_de_smet";
private static final String DEFAULT_LINE_CONTAINS_FILTER = null;
public static void main(String[] args) {
String lineContainsFilter;
if (args.length > 0) {
lineContainsFilter = args[0];
} else {
lineContainsFilter = DEFAULT_LINE_CONTAINS_FILTER;
}
NurseRosteringEvaluatorHelper helper = new NurseRosteringEvaluatorHelper();
if (!ALL_INPUT_FILES) {
helper.evaluate(INPUT_FILE_PREFIX, OUTPUT_FILE_SUFFIX, lineContainsFilter);
} else {
File inputDir = helper.getImportDir();
File[] inputFiles = inputDir.listFiles();
if (inputFiles == null) {
throw new IllegalArgumentException(
"Your working dir should be drools-planner-examples and contain: " + inputDir);
}
Arrays.sort(inputFiles);
for (File inputFile : inputFiles) {
String inputFileName = inputFile.getName();
if (inputFileName.endsWith(".xml")) {
String filePrefix = inputFileName.substring(0, inputFileName.lastIndexOf(".xml"));
helper.evaluate(filePrefix, OUTPUT_FILE_SUFFIX, lineContainsFilter);
}
}
}
}
protected NurseRosteringApp nurseRosteringApp;
protected SolutionBusiness solutionBusiness;
public NurseRosteringEvaluatorHelper() {
nurseRosteringApp = new NurseRosteringApp();
solutionBusiness = nurseRosteringApp.createSolutionBusiness();
}
public File getImportDir() {
return solutionBusiness.getImportDataDir();
}
public void evaluate(String filePrefix, String fileSuffix, String lineContainsFilter) {
Process process = null;
try {
File inputFile = new File(solutionBusiness.getImportDataDir(),
filePrefix + ".xml").getCanonicalFile();
File solvedFile = new File(solutionBusiness.getSolvedDataDir(),
filePrefix + fileSuffix + ".xml").getCanonicalFile();
if (!solvedFile.exists()) {
logger.info("Skipping inputFile ({}) because no solvedFile found.", inputFile);
return;
}
solutionBusiness.openSolution(solvedFile);
HardAndSoftScore score = (HardAndSoftScore) solutionBusiness.getScore();
File outputFile = new File(solutionBusiness.getExportDataDir(),
filePrefix + fileSuffix + ".xml").getCanonicalFile();
solutionBusiness.exportSolution(outputFile);
File evaluatorDir = new File("local/competition/nurserostering/");
String command = "java -jar evaluator.jar " + inputFile.getAbsolutePath()
+ " " + outputFile.getAbsolutePath();
process = Runtime.getRuntime().exec(command, null, evaluatorDir);
EvaluatorSummaryFilterOutputStream out = new EvaluatorSummaryFilterOutputStream(outputFile.getName(), lineContainsFilter);
IOUtils.copy(process.getInputStream(), out);
IOUtils.copy(process.getErrorStream(), System.err);
out.writeResults();
int penaltyTotal = out.getPenaltyTotal();
if (score.getHardScore() == 0) {
if (score.getSoftScore() == (-penaltyTotal)) {
System.out.println("The calculated soft score (" + score.getSoftScore()
+ ") is the same as the evaluator penalty total (" + penaltyTotal + ").");
} else {
throw new IllegalStateException("The calculated soft score (" + score.getSoftScore()
+ ") is not the same as the evaluator penalty total (" + penaltyTotal + ").");
}
}
} catch (IOException e) {
throw new IllegalStateException(e);
} finally {
if (process != null) {
process.destroy();
}
}
}
private static class EvaluatorSummaryFilterOutputStream extends OutputStream {
private String name;
private String lineContainsFilter;
private StringBuilder lineBuffer = new StringBuilder(120);
private Map<String, int[]> costMap = new TreeMap<String, int[]>();
private String lastEmployeeCode = null;
private int penaltyTotal;
private EvaluatorSummaryFilterOutputStream(String name, String lineContainsFilter) {
super();
this.name = name;
this.lineContainsFilter = lineContainsFilter;
}
public int getPenaltyTotal() {
return penaltyTotal;
}
public void write(int c) throws IOException {
if (c == '\n') {
String line = lineBuffer.toString();
lineBuffer.delete(0, lineBuffer.length());
processLine(line);
} else {
lineBuffer.append((char) c);
}
}
private void processLine(String line) {
int employeeIndex = line.indexOf("Employee: ");
if (employeeIndex >= 0) {
lastEmployeeCode = line.substring(employeeIndex).replaceAll("Employee: (.+)", "$1");
} else if (line.contains("Penalty:")) {
lastEmployeeCode = null;
}
if (lineContainsFilter == null || line.contains(lineContainsFilter)) {
int excessIndex = line.indexOf("excess = ");
if (excessIndex >= 0) {
String key = line.substring(0, excessIndex);
int costIndex = line.indexOf("cost = ");
int value = Integer.parseInt((line.substring(costIndex) + " ").replaceAll("cost = (\\d+) .*", "$1"));
int[] cost = costMap.get(key);
if (cost == null) {
cost = new int[]{1, value};
costMap.put(key, cost);
} else {
cost[0]++;
cost[1] += value;
}
}
if (lastEmployeeCode != null) {
System.out.print("E(" + lastEmployeeCode + ") ");
}
System.out.println(line);
}
}
public void writeResults() {
System.out.println("EvaluatorHelper results for " + name);
penaltyTotal = 0;
if (lineContainsFilter != null) {
System.out.println("with lineContainsFilter (" + lineContainsFilter + ")");
}
for (Map.Entry<String, int[]> entry : costMap.entrySet()) {
int[] cost = entry.getValue();
penaltyTotal += cost[1];
System.out.println(entry.getKey() + " count = " + cost[0] + " total = " + cost[1]);
}
System.out.println("The penaltyTotal: " + penaltyTotal);
}
}
}