package com.hpctoday.fada.integersolver;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import com.hpctoday.fada.Condition;
import com.hpctoday.fada.Expression;
import com.hpctoday.fada.FADA_Index;
import com.hpctoday.fada.Inequation;
import com.hpctoday.fada.Quast;
import com.hpctoday.jpip.Pip;
import com.hpctoday.jpip.math.NumberFactory;
import com.hpctoday.jpip.math.RationalNumber;
import com.hpctoday.jpip.math.IntegerNumber;
import com.hpctoday.jpip.math.RationalVector;
import com.hpctoday.jpip.solution.NewParameter;
import com.hpctoday.jpip.solution.PipList;
import com.hpctoday.jpip.solution.PipQuast;
import com.hpctoday.jpip.solution.PipSolution;
import com.hpctoday.jpip.solution.SubSolution;
public class JPipSolver<N extends IntegerNumber<N>> extends Solver {
private static final Logger log = Logger.getLogger(JPipSolver.class.getName());
private NumberFactory<N> numFactory;
public JPipSolver(NumberFactory<N> factory){
super();
numFactory = factory;
}
private List<List<RationalNumber<N>>> CodeConstraints() {
log.trace("Code Constraints:");
Map<String, Integer> var = new HashMap<String, Integer>();
Map<String, Integer> param = new HashMap<String, Integer>();
int i = 0;
for (String it : GetVariables())
var.put(it, i++);
log.trace("Var: " + var);
i = 0;
for (String it : GetParameters())
param.put(it, i++);
log.trace("Param: " + param);
List<List<RationalNumber<N>>> result = new ArrayList<List<RationalNumber<N>>>();
for (Inequation it : GetConstraints()){
List<Integer> vector = it.ToVector(GetVariables(), var, GetParameters(), param);
ArrayList<RationalNumber<N>> newVector = new ArrayList<RationalNumber<N>>();
for(int v: vector){
newVector.add(new RationalNumber<N>(numFactory, v));
}
result.add(newVector);
}
log.trace("CodedConstraints: " + result);
return result;
}
public Quast Max() {
if (IsPIPized()) {
log.trace("IsPIPized");
log.trace("Launch PIP :============================");
List<List<RationalNumber<N>>> coded_constraints = CodeConstraints();
log.trace("Constraints:");
log.trace(coded_constraints);
// Launch PIP
int nVar = this.GetVariables().size();
int nParm = this.GetParameters().size() + 1;
log.trace("nVar: " + nVar);
log.trace("nParm: " + nParm);
log.trace("nIneq: " + coded_constraints.size());
Pip<N> pip = new Pip<N>(numFactory);
pip.setIntegerSolution(true);
pip.initialize(coded_constraints,nVar, nParm, true); // to get the max_lex
PipSolution<N> result = pip.solve();
log.trace("Result: ");
log.trace(result);
log.trace("End PIP :============================");
Map<Integer, Expression> mapping = new HashMap<Integer, Expression>();
return FromPipQuast(this.GetIndex(), this.GetDeep(), GetVariables(), GetParameters(), result, mapping);
} else {
log.trace("Not IsPIPized");
int nb_variables = GetVariables().size();
List<Inequation> new_constraints = new ArrayList<Inequation>();
PIPize(GetVariables(), new_constraints);
// RemoveNegativeVariablesPIPLimitation(GetVariables(),GetParameters(),&new_constraints);
Solver s = SolverFactory.createSolver();
s.set(GetIndex(), GetDeep(), GetVariables(), GetParameters(), new_constraints, true);
// cout<<"\n======================================================\n";
// s.Print();
Quast result = s.Max();
// cout<<"\n NB variables .... ="<<nb_variables;
// result.Print("\n");
// cout<<"\n======================================================\n";
result.DropAddedVariables(nb_variables);
return result;
}
}
public Quast Min() {
List<List<RationalNumber<N>>> coded_constraints = CodeConstraints();
// Launch PIP
Pip<N> pip = new Pip<N>(numFactory);
pip.setIntegerSolution(true);
pip.initialize(coded_constraints, this.GetVariables().size(), this.GetParameters().size(), false);
PipSolution<N> result = pip.solve();
Map<Integer, Expression> mapping = new HashMap<Integer, Expression>();
return FromPipQuast(this.GetIndex(), GetDeep(), GetVariables(), GetParameters(), result, mapping);
}
// ! \name Exporting and importing from/to PIPlib structures.
// ! \brief Import a quast from a pip datastructure
// public static Quast FromPIPQuast(int __index, List<String> variables, PipQuast __quast);
// ! \brief Import a quast from a pip datastructure
private Quast FromPipQuast(int __index, int __deep, List<String> __counters, List<String> __params, PipSolution<N> solution,
Map<Integer, Expression> new_param) {
if(!solution.hasSolution()){
return new Quast();
}
Map<Integer, Expression> __new_param = new HashMap<Integer, Expression>(new_param);
List<NewParameter<N>> parameters = solution.getParameters();
for(NewParameter<N> parm: parameters){
int new_rank = parm.getIndex();
RationalVector<N> vector = parm.getParameters();
RationalNumber<N> gcd = vector.gcd().inverse();
vector = vector.multiply(gcd);
Expression num = PipVectorToExpression(vector, __params, __new_param);
//Build denominator
Expression newparm_def;
if(gcd.isInteger()){
int value = (int)gcd.value();
Expression deno = new Expression(value);
newparm_def = new Expression(num, Expression.Operation.FADA_DIV, deno);
} else {
int n = (int)gcd.getNumerator().value();
int d = (int)gcd.getDenominator().value();
Expression exp1 = new Expression(new Expression(d), Expression.Operation.FADA_MUL, num);
newparm_def = new Expression(exp1, Expression.Operation.FADA_DIV, new Expression(n));
}
__new_param.put(new_rank, newparm_def);
}
SubSolution<N> sSolution = solution.getSolution();
// conditional node
if(sSolution instanceof PipQuast){
PipQuast<N> __quast = (PipQuast<N>)sSolution;
Expression ineq = PipVectorToExpression(__quast.getCondition(), __params, __new_param);
Condition __cond = new Condition(new Inequation(ineq.GetLeftChild(), Inequation.Predicate.FADA_GREATER_EQ, ineq.GetRightChild()));
log.trace("Cond: " + __cond);
return new Quast(__cond,
FromPipQuast(__index, __deep, __counters, __params, __quast.getThen(), __new_param),
FromPipQuast(__index, __deep, __counters, __params, __quast.getElse(), __new_param));
} else if(sSolution instanceof PipList){ // leaf
PipList<N> list = (PipList<N>)sSolution;
return new Quast(__index, __deep, __counters, PipListToIndex(list, __counters.size(), __params, __new_param));
} else {
return new Quast();
}
}
// ! \brief Import an index from a PIPlib Data
private FADA_Index PipListToIndex(PipList<N> __pipl, int __nb_variables, List<String> __params, Map<Integer, Expression> new_param) {
Map<Integer, Expression> __new_param = new HashMap<Integer, Expression>(new_param);
List<Expression> result = new ArrayList<Expression>(__nb_variables);
List<RationalVector<N>> list = __pipl.getList();
for (int i = 0; i < __nb_variables; i++) {
result.add(PipVectorToExpression(list.get(i), __params, __new_param).Simplify());
}
return new FADA_Index(result);
}
// ! \brief Import a pip expression
private Expression PipVectorToExpression(RationalVector<N> __pipv, List<String> __param, Map<Integer, Expression> new_param) {
int nb_parameters = __param.size();
Map<Integer, Expression> __new_param = new HashMap<Integer, Expression>(new_param);
if (__pipv.getLength() != nb_parameters + __new_param.size() + 1) {
throw new RuntimeException("PipVectorToExpression:: Fatal error ... bad List size: " + __pipv.getLength() + " vs " + (nb_parameters + __new_param.size()));
}
// cout<<"\n..................................\n";
// pip_List_print(stdout,__pipv);
log.trace("param: " + __param);
log.trace("pipv: " + __pipv);
Expression result_pos;
Expression result_neg;
if (__pipv.get(nb_parameters + __new_param.size()).signum() >= 0) { // constant
// FIXME: Downcasting
int value = (int)__pipv.get(nb_parameters + __new_param.size()).value();
result_pos = new Expression(value);
result_neg = new Expression(0);
} else {
int value = (int)__pipv.get(nb_parameters + __new_param.size()).value();
result_pos = new Expression(0);
result_neg = new Expression(-1 * value);
}
for (int i = 0; i < nb_parameters; i++) { // handle old parameters
// FIXME: Downcasting
int coef = (int) __pipv.get(i).value();
// cout<<"\n i = "<<i<<" coef = "<<coef<<" nom param = "<<__param.operator[](i);
if (coef != 0) {
Expression param = new Expression(__param.get(i));
switch (coef) {
case 1:
result_pos = new Expression(result_pos, Expression.Operation.FADA_ADD, param);
break;
case -1:
result_neg = new Expression(result_neg, Expression.Operation.FADA_ADD, param);
break;
case 0:
break;
default: {
if (coef > 0) {
Expression __coef = new Expression(coef);
Expression __term = new Expression(__coef, Expression.Operation.FADA_MUL, param);
result_pos = new Expression(result_pos, Expression.Operation.FADA_ADD, __term);
} else {
Expression __coef = new Expression(-1 * coef);
Expression __term = new Expression(__coef, Expression.Operation.FADA_MUL, param);
result_neg = new Expression(result_pos, Expression.Operation.FADA_ADD, __term);
}
break;
}
}
}
}
// cout<<"\n\nhhhhhhhhhhhhhhhhh\n";
// Newparms handling
for (int i : __new_param.keySet()) {
Expression param = __new_param.get(i);
// FIXME: Downcasting
int coef = (int) __pipv.get(i).value();
switch (coef) {
case 0:
break;
case 1:
result_pos = new Expression(result_pos, Expression.Operation.FADA_ADD, param);
break;
case -1:
result_neg = new Expression(result_neg, Expression.Operation.FADA_ADD, param);
break;
default:
if (coef > 0) {
Expression __coef = new Expression(coef);
Expression __term = new Expression(__coef, Expression.Operation.FADA_MUL, param);
result_pos = new Expression(result_pos, Expression.Operation.FADA_ADD, __term);
} else {
Expression __coef = new Expression(-1 * coef);
Expression __term = new Expression(__coef, Expression.Operation.FADA_MUL, param);
result_neg = new Expression(result_pos, Expression.Operation.FADA_ADD, __term);
}
break;
}
}
result_pos = result_pos.Simplify();
// result_pos.Print();
Expression final_res = new Expression(result_pos.Simplify(), Expression.Operation.FADA_SUB, result_neg.Simplify());
// cout<<"\n\nhhhhhhhhhhhhhhhhh\n";
// final_res.Print();
return final_res;
}
}