org.drools.planner.examples.nurserostering.competition.NurseRosteringEvaluatorHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.drools.planner.examples.nurserostering.competition.NurseRosteringEvaluatorHelper.java

Source

/**
 * 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);
        }
    }

}