Package csp.backends

Source Code of csp.backends.TailorSolver$MinionKiller

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package csp.backends;

import csp.datatypes.CSPProblem;
import csp.datatypes.CSPSolution;
import csp.datatypes.Constraint;
import csp.datatypes.IntegerBinaryExpression;
import csp.datatypes.IntegerConstant;
import csp.datatypes.IntegerDomainVariable;
import csp.datatypes.IntegerEnumeratedVariable;
import csp.datatypes.IntegerExpressionVisitor;
import csp.datatypes.IntegerIfThenElseExpression;
import csp.datatypes.IntegerVariable;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;

/**
*
* @author Jeroen Janssen <Jeroen.Janssen@vub.ac.be>
*/
public class TailorSolver {

  // TODO: this class needs massive cleaning!!

  private String minionPath;
  private File temp;
  // We need to keep track of the outputted variables as minion only outputs
  // Sol: value in the order in which the variables were created, without
  // naming the variable in its output.
  private ArrayList<IntegerDomainVariable> dVars;
  private ArrayList<IntegerEnumeratedVariable> eVars;
  // Since tailor doesn't let us use variables of the forn near(a,t1,t2)
  // because the variable contains ( ) we will have to map our variables
  // back and forth between the tailor notation and the CSP notation ...
  private HashMap<String,String> varMap;
  private HashMap<String,String> revVarMap;
  // This counts the next free variable number in the tailor representation
  private int varCounter = 0;
  // The string we will use for variables in the tailor notation
  private String varString = "v";

  private int timeout = 1000;
  private boolean foundSolution = false;
  private static final String NL = System.getProperty("line.separator");
  private String tailorPath;

  // We need auxiliary variables to implement if-then-else constraints
  private static String dummyVar = "FURETAUX";
  private ArrayList<IntegerDomainVariable> dummyDomainVars;
  private ArrayList<IntegerEnumeratedVariable> dummyEnumeratedVars;
  private int dummyCounter = 0;
  // Some constants for new domain dummy variables
  private static int lowestVal = -999999999;
  private static int highestVal = 999999999;

  public static enum PPLEVEL {
    NONE, GAC, SACBounds,
    SAC, SSACBounds, SSAC
  }
  public static PPLEVEL PPLEVELNUMBER = PPLEVEL.NONE;
  public static enum VARORDER {
    NONE, SDF, SDF_RANDOM, SRF, SRF_RANDOM, LDF,
    LDF_RANDOM, RANDOM, STATIC;
  }
  public static VARORDER VARORDERNUMBER = VARORDER.NONE;

  public TailorSolver (String tailorPath, String minionPath) {
    this.tailorPath = tailorPath;
    this.minionPath = minionPath;
    dummyDomainVars = new ArrayList<IntegerDomainVariable>();
    dummyEnumeratedVars = new ArrayList<IntegerEnumeratedVariable>();
    varMap = new HashMap<String,String>();
    revVarMap = new HashMap<String,String>();
  }

  public void read(CSPProblem model) {
    try {
      temp = File.createTempFile("furet", ".eprime");
      // To make sure we don't get a string index error from tailor *sigh*
      System.err.println("Temp File created at: " + temp.getAbsolutePath());

      // TODO DEBUG
      //temp.deleteOnExit();

      BufferedWriter out = new BufferedWriter(new FileWriter(temp));

      // We only know how many aux vars we need after outputting all constraints
      // so we'll have to keep two stringbuffers: one for the part of the file
      // before the constraints and one for the part with the constraints ...
      StringBuffer varBuff = new StringBuffer ();

      //out.write("language ESSENCE' 1.b.a" + NL);
      //out.newLine();
      varBuff.append("language ESSENCE' 1.b.a" + NL);
      varBuff.append(NL);

      // TODO: let minion output the variable names as well so we can
      // parse them more easily
      dVars = new ArrayList<IntegerDomainVariable>();

//      for (IntegerDomainVariable dVar : model.getDomainVariables()) {
//        dVars.add(dVar);
//        out.write("find " + dVar.getName() + " : int(" + dVar.getLowerBound()
//            + ".." + dVar.getUpperBound() + ")" + NL);
//      }

      for (IntegerDomainVariable dVar : model.getDomainVariables()) {
        String varName = varString+(varCounter++);
        dVars.add(dVar);
        varMap.put(dVar.getName(), varName);
        revVarMap.put(varName,dVar.getName());
        varBuff.append("find " + varName + " : int(" + dVar.getLowerBound()
            + ".." + dVar.getUpperBound() + ")" + NL);
      }

      //HashSet<MinionEnumeratedVariable> eVars = model.getEnumeratedVariables();
      eVars = new ArrayList<IntegerEnumeratedVariable>();

//      for (IntegerEnumeratedVariable eVar : model.getEnumeratedVariables()) {
//        eVars.add(eVar);
//        out.write("find " + eVar.getName() + " : int(");
//        Iterator<Integer> it = eVar.getValues().iterator();
//        if (it.hasNext()) {
//          out.write(it.next().toString());
//        }
//        while (it.hasNext()) {
//          out.write("," + it.next());
//        }
//        out.write(")" + NL);
//      }

      for (IntegerEnumeratedVariable eVar : model.getEnumeratedVariables()) {
        String varName = varString + (varCounter++);
        eVars.add(eVar);
        varMap.put(eVar.getName(),varName);
        revVarMap.put(varName,eVar.getName());
        varBuff.append("find " + varName + " : int(");
        Iterator<Integer> it = eVar.getValues().iterator();
        if (it.hasNext()) {
          varBuff.append(it.next().toString());
        }
        while (it.hasNext()) {
          varBuff.append("," + it.next());
        }
        varBuff.append(")" + NL);
      }

      //out.newLine();

      StringBuffer constrBuff = new StringBuffer ();

//      out.write("such that" + NL);
//      out.newLine();
//
//      Iterator<Constraint> cit = model.getConstraints().iterator();
//
//      if (cit.hasNext()) {
//        outputConstraint(out, cit.next());
//      }
//      while (cit.hasNext()) {
//        out.write("," + NL);
//        outputConstraint(out, cit.next());
//      }

      constrBuff.append("such that" + NL);
      constrBuff.append(NL);

      Iterator<Constraint> cit = model.getConstraints().iterator();

      if (cit.hasNext()) {
        outputConstraint(constrBuff, cit.next());
      }
      while (cit.hasNext()) {
        constrBuff.append("," + NL);
        outputConstraint(constrBuff, cit.next());
      }

      for (IntegerDomainVariable dVar : dummyDomainVars) {
        varBuff.append("find " + dVar.getName() + " : int(" + dVar.getLowerBound()
            + ".." + dVar.getUpperBound() + ")" + NL);
      }

      for (IntegerEnumeratedVariable eVar : dummyEnumeratedVars) {
        varBuff.append("find " + eVar.getName() + " : int(");
        Iterator<Integer> it = eVar.getValues().iterator();
        if (it.hasNext()) {
          varBuff.append(it.next().toString());
        }
        while (it.hasNext()) {
          varBuff.append("," + it.next());
        }
        varBuff.append(")" + NL);
      }

      out.write(varBuff.toString() + NL + constrBuff.toString() + NL);
      out.close();
    } catch (IOException e) {
      System.err.println("Could not create temp file for solving: " + e);
    }
  }

  // TODO: remove this function and use constraintToTailor
//  private void outputConstraint(BufferedWriter out, Constraint c)
//      throws IOException {
  private void outputConstraint(StringBuffer buff, Constraint c) {
//    Constraint.Operator op = c.getOperator();
//    //System.out.println("Operator: " + op);
//    TailorOutputter mOutput = new TailorOutputter();
//    String lhs = c.getLHS().accept(mOutput);
//    String rhs = c.getRHS().accept(mOutput);
//    if (op.equals(Constraint.Operator.GEQ)) {
//      out.write(lhs + " >= " + rhs);
//    } else if (op.equals(Constraint.Operator.LEQ)) {
//      out.write(lhs + " <= " + rhs);
//    } else if (op.equals(Constraint.Operator.EQ)) {
//      out.write(lhs + " = " + rhs);
//    } else {
//      System.err.println("Unknown operator: " + op);
//    }
    buff.append(constraintToTailor(c));
  }

  private String constraintToTailor (Constraint c) {
    StringBuffer out = new StringBuffer();
    Constraint.Operator op = c.getOperator();
    //System.out.println("Operator: " + op);
    TailorOutputter mOutput = new TailorOutputter();
    String lhs = c.getLHS().accept(mOutput);
    String rhs = c.getRHS().accept(mOutput);
    if (op.equals(Constraint.Operator.GEQ)) {
      out.append(lhs + " >= " + rhs);
    } else if (op.equals(Constraint.Operator.LEQ)) {
      out.append(lhs + " <= " + rhs);
    } else if (op.equals(Constraint.Operator.EQ)) {
      out.append(lhs + " = " + rhs);
    } else {
      System.err.println("Unknown operator: " + op);
    }
    if(!mOutput.getExtraConstraints().isEmpty()) {
      out.append("," + NL);
      Iterator<String> it = mOutput.getExtraConstraints().iterator();
      out.append(it.next());
      while(it.hasNext()) {
        out.append("," + NL);
        out.append(it.next());
      }
    }
    return out.toString();
  }

  public CSPSolution solve() {
               
    CSPSolution model = null;
    try {
      // Tailor is quite picky over where the flags can occur
      // so -out FILENAME must be up front!!
                        System.out.println("start taylor");
      Process tailor = Runtime.getRuntime().exec(
          "java -jar "
          + tailorPath + " "
          + "-out " + temp.getAbsolutePath() + ".minion"
          + " " + temp.getAbsolutePath());
      // Let's wait for tailor to exit
      // this while loop is apparently necessary, because otherwise
      // the JVM will not wait for tailor to end before calling minion
      String line;
      BufferedReader tailorOutput =
          new BufferedReader(new InputStreamReader(tailor.getInputStream()));
      while ((line = tailorOutput.readLine()) != null) {
        //System.err.println(line);
      }
      tailorOutput.close();

      String minionString = minionPath + " -timelimit " + timeout + " "
          + "-noresume " + getPreprocessString() + " " + getVarorderString()
          + " " + temp.getAbsolutePath() + ".minion";
      System.out.println("Running minion with: " + minionString);
      Process p = Runtime.getRuntime().exec(minionString);
      // TODO: killer does not work in netbeans. Does it work on CLI?
      Runtime.getRuntime().addShutdownHook(new Thread(new MinionKiller(p)));
      BufferedReader input =
          new BufferedReader(new InputStreamReader(p.getInputStream()));
      model = parseMinionOutput(input);
      /*while ((line = input.readLine()) != null) {
      System.out.println(line);
      }*/
      // remove temporary minion file on quit
      //new File(temp.getAbsolutePath() + ".minion").deleteOnExit();
      input.close();
    } catch (Exception err) {
      System.err.println("TailorSolver could not solve the problem:");
      err.printStackTrace();
    }
    //temp.delete();
    return model;
  }

  private CSPSolution parseMinionOutput(BufferedReader reader) {
    CSPSolution model = new CSPSolution();
    boolean hasSolution = false;
    int i = 0;
    int j = 0;
    String line;
    String solutionPrefix = "Sol: ";
    String hasSolutionPrefix = "Problem solvable?: ";
    try {
      while ((line = reader.readLine()) != null) {
        //System.err.println(line);
        if (line.startsWith(solutionPrefix)) {
          hasSolution = true;
          Integer value = Integer.parseInt(line.trim().substring(solutionPrefix.length()));
          String variable = "";
          if (i < dVars.size()) {
            variable = dVars.get(i++).getName();
            model.addVariable(variable, value);
          } else if (j < eVars.size()) {
            variable = eVars.get(j++).getName();
            model.addVariable(variable, value);
          }
        } else if (line.startsWith(hasSolutionPrefix)) {
          String solStatus = line.trim().substring(hasSolutionPrefix.length());
          if(solStatus.equals("yes")) {
            hasSolution = true;
          } else {
            hasSolution = false;
          }
        }
      }
      if (!hasSolution) {
        return null;
      } else {
        return model;
      }
    } catch (Exception err) {
      System.err.println("Error parsing minion output.");
      err.printStackTrace();
      return null;
    }
  }


  public boolean isFeasible() {
    return foundSolution;
  }

  public void setTimeout(int timeoutSec) {               
    this.timeout = timeoutSec;
  }

  private String getPreprocessString() {
    if (PPLEVELNUMBER.equals(PPLEVEL.NONE))
      return "";
    else
      return "-preprocess " + PPLEVELNUMBER.name();
  }

  private String getVarorderString() {
    // Code assumes the varorders are saved ass SDF_RANDOM if the minion input
    // should be sdf-random etc.
    if (VARORDERNUMBER.equals(VARORDER.NONE))
      return "";
    else
      return "-varorder " + VARORDERNUMBER.name().toLowerCase().replaceAll("_", "-");
  }

  private class MinionKiller implements Runnable {

    private Process minionProcess;

    public MinionKiller(Process minonProcess) {
      this.minionProcess = minionProcess;
    }

    public void run() {
      //System.err.println("Killing minion ...");
      if (minionProcess != null) {
        minionProcess.destroy();
      }
      //System.err.println("Killed minion!");
    }
  }

  private class TailorOutputter implements IntegerExpressionVisitor<String> {
    // needed for the dummy variables
    ArrayList<String> extraConstraints;

    public TailorOutputter () {
      extraConstraints = new ArrayList<String>();
    }

    @Override
    public String visitBinaryExpression(IntegerBinaryExpression exp) {
      String lhs = exp.getLHS().accept(this);
      String rhs = exp.getRHS().accept(this);
      StringBuffer buff = new StringBuffer();
      if (exp.getOperator().equals(IntegerBinaryExpression.Operator.MAX)) {
        buff.append("max(");
        buff.append(lhs);
        buff.append(",");
        buff.append(rhs);
        buff.append(")");
      } else if (exp.getOperator().equals(IntegerBinaryExpression.Operator.MULT)) {
        buff.append("(");
        buff.append(lhs);
        //buff.append(")");
        buff.append(" * ");
        //buff.append("(");
        buff.append(rhs);
        buff.append(")");
      } else if (exp.getOperator().equals(IntegerBinaryExpression.Operator.SUM)) {
        buff.append("(");
        buff.append(lhs);
        //buff.append(")");
        buff.append(" + ");
        //buff.append("(");
        buff.append(rhs);
        buff.append(")");
      }
      return buff.toString();
    }

    @Override
    public String visitConstant(IntegerConstant c) {
      return Integer.toString(c.getConstant());
    }

    @Override
    public String visitDomainVariable(IntegerDomainVariable v) {
      return varMap.get(v.getName());
    }

    @Override
    public String visitEnumeratedVariable(IntegerEnumeratedVariable v) {
      return varMap.get(v.getName());
    }

    @Override
    public String visitIfThenElseExpression(IntegerIfThenElseExpression exp) {
      // Small optimization
      // TODO quite hacky though with the instanceof
      String auxName;
      if(exp.getTrueExpression() instanceof IntegerConstant
          && exp.getFalseExpression() instanceof IntegerConstant) {
        Integer intTrue = ((IntegerConstant)exp.getTrueExpression()).getConstant();
        Integer intFalse = ((IntegerConstant)exp.getFalseExpression()).getConstant();
        ArrayList<Integer> values = new ArrayList<Integer>();
        values.add(intTrue);
        values.add(intFalse);
        Collections.sort(values);
        IntegerEnumeratedVariable aux = getNewEnumeratedDummy(values);
        dummyEnumeratedVars.add(aux);
        auxName = aux.getName();
      } else {
        IntegerDomainVariable aux = getNewDummyVariable(lowestVal,highestVal);
        dummyDomainVars.add(aux);
        auxName = aux.getName();
      }
      String cond = constraintToTailor(exp.getCondition());
      String expTrue = exp.getTrueExpression().accept(this);
      String expFalse = exp.getFalseExpression().accept(this);
      StringBuffer buff = new StringBuffer ();
      extraConstraints.add("(" + cond + ")" + " => " + "(" + auxName + "=" + expTrue + ")");
      extraConstraints.add("!" + "(" + cond + ")" + " => " + "(" + auxName + "=" + expFalse + ")");
      return auxName;
    }

    private IntegerEnumeratedVariable getNewEnumeratedDummy(ArrayList<Integer> values) {
      return new IntegerEnumeratedVariable(dummyVar+(dummyCounter++),values);
    }

    private IntegerDomainVariable getNewDummyVariable(int lowerBound, int upperBound) {
      return new IntegerDomainVariable(dummyVar+(dummyCounter++),lowerBound,upperBound);
    }

    public ArrayList<String> getExtraConstraints() {
      return extraConstraints;
    }
  }
}
TOP

Related Classes of csp.backends.TailorSolver$MinionKiller

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.