package janala.solvers;
import org.chocosolver.solver.Solver;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.solver.variables.VariableFactory;
import org.chocosolver.solver.constraints.IntConstraintFactory;
import org.chocosolver.solver.constraints.LogicalConstraintFactory;
import org.chocosolver.util.ESat;
import janala.config.Config;
import janala.interpreters.*;
import janala.utils.MyLogger;
import janala.utils.Inputs;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import janala.interpreters.COMPARISON_OPS;
/** A solver that uses Choco as backend. */
public class ChocoSolver implements janala.solvers.Solver {
boolean first = true;
List<InputElement> inputs;
List<String> solution;
IntVar[] vars;
Solver solver;
private final static Logger logger = MyLogger.getLogger(ChocoSolver.class.getName());
public void setInputs(List<InputElement> inputs) {
this.inputs = inputs;
this.first = true;
solution = null;
}
public void setPathConstraint(List<Constraint> pathConstraint) {
}
public void setPathConstraintIndex(int pathConstraintIndex) {
}
private SymbolicInt initSolver(SymbolicInt c) {
if (first) {
first = false;
solver = new Solver();
int len = inputs.size();
vars = new IntVar[len];
for (int i = 0; i < len; i++) {
vars[i] = VariableFactory.integer("x" + i,
VariableFactory.MIN_INT_BOUND, VariableFactory.MAX_INT_BOUND, solver);
}
return c.not();
}
return c;
}
public void visitSymbolicInt(SymbolicInt c) {
SymbolicInt tmp = initSolver(c);
solver.post(createConstraintForSymbolicInt(tmp));
}
public void visitSymbolicIntCompare(SymbolicIntCompareConstraint c) {
throw new RuntimeException("Unimplemented feature");
}
private org.chocosolver.solver.constraints.Constraint createConstraintForSymbolicInt(SymbolicInt c) {
logger.log(Level.INFO, "{0}", c);
int n = c.getLinear().size();
IntVar[] variables = new IntVar[n];
int[] coeff = new int[n];
int idx = 0;
for (Map.Entry<Integer, Long> it : c.getLinear().entrySet()) {
int varIdx = it.getKey() - 1;
variables[idx] = vars[varIdx];
coeff[idx] = it.getValue().intValue();
idx++;
}
// Create a fixed variable for the right-hand side
IntVar rhs = VariableFactory.fixed(-(int) c.getConstant(), solver);
String op = c.getOp().toString();
return IntConstraintFactory.scalar(variables, coeff, op, rhs);
}
public void visitSymbolicOr(SymbolicOrConstraint or) {
org.chocosolver.solver.constraints.Constraint[] con =
new org.chocosolver.solver.constraints.Constraint[or.constraints.size()];
int idx = 0;
for (Constraint c : or.constraints) {
SymbolicInt tmp = initSolver((SymbolicInt)c);
con[idx] = createConstraintForSymbolicInt(tmp);
idx++;
}
solver.post(LogicalConstraintFactory.or(con));
}
public void visitSymbolicStringPredicate(SymbolicStringPredicate symbolicStringPredicate) {
throw new RuntimeException(
"String functions and regular expressions are not supported with Choco solver");
}
public void visitSymbolicAnd(SymbolicAndConstraint c) {
throw new RuntimeException("Unsupported");
}
public void visitSymbolicNot(SymbolicNotConstraint c) {
throw new RuntimeException("Unsupported");
}
public void visitSymbolicTrue(SymbolicTrueConstraint c) {
throw new RuntimeException("Unsupported");
}
public void visitSymbolicFalse(SymbolicFalseConstraint c) {
throw new RuntimeException("Unsupported");
}
public boolean solve() {
if (solver != null) {
System.out.println("Running choco solver ...");
logger.log(Level.INFO, "Running Choco Solver ...");
solver.findSolution();
logger.log(Level.INFO, "end running Choco Solver ");
if (solver.isFeasible() == ESat.TRUE) {
solution = new ArrayList<String>();
for (int i = 0; i < vars.length; i++) {
int var = vars[i].getValue();
Value input = inputs.get(i).value;
if (input instanceof janala.interpreters.StringValue) {
solution.add(StringConstants.instance.get(var));
} else {
solution.add(Integer.toString(var));
}
}
return true;
} else {
logger.log(Level.INFO, "-- Infeasible");
return false;
}
}
return false;
}
public List<String> getSolution() {
return solution;
}
}