package ai.domain.boxes;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import ai.domain.Variable;
import ai.domain.bool.Bool;
import ai.domain.boxes.BoxesWideningOperator.WideningStepThresholds;
import ai.domain.generic.NonRelationalDomain;
import ai.domain.generic.ProductDomain;
import ai.domain.interval.Interval;
import ai.domain.widening.DefaultWideningOperator;
import ai.domain.widening.WideningOperator;
public class BoxesWideningFactory {
private static Map<Variable, Set<Double>> surroundingBox(NonRelationalDomain<Interval> box) {
Map<Variable, Set<Double>> result = new HashMap<Variable, Set<Double>>();
for(Variable var: box.getVariables()){
Interval interval = box.getValueFor(var);
Set<Double> varThresholds = new HashSet<Double>();
result.put(var, varThresholds);
if (interval.getLeft() > Double.NEGATIVE_INFINITY)
varThresholds.add(interval.getLeft());
if (interval.getRight() < Double.POSITIVE_INFINITY)
varThresholds.add(interval.getRight()+1);
}
return result;
}
private static class MyThresholds implements WideningStepThresholds{
final Map<Variable, Set<Double>> thresholds;
public MyThresholds(Map<Variable, Set<Double>> thresholds){
this.thresholds = thresholds;
}
public MyThresholds join(MyThresholds otherOrNull) {
if (otherOrNull == null)
return this;
Map<Variable, Set<Double>> result = new HashMap<Variable, Set<Double>>();
for(Map.Entry<Variable, Set<Double>> entry: thresholds.entrySet()){
Variable var = entry.getKey();
Set<Double> thres = new HashSet(entry.getValue());
thres.addAll(otherOrNull.thresholds.get(var));
result.put(var, thres);
}
return new MyThresholds(result);
}
@Override
public Set<Double> getThresholds(Variable var) {
return thresholds.get(var);
}
}
private static abstract class BoolBoxesWideningBase implements WideningOperator<ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes>> {
protected abstract IntegerBoxes widenBoxes(IntegerBoxes left, IntegerBoxes right);
@Override
public ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> widen(
ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> left,
ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes> right) {
if (left.isBottom())
return right;
if (right.isBottom())
return left;
//regular bools
NonRelationalDomain<Bool> widBools = left.getLeft().widen(right.getLeft());
IntegerBoxes widBoxes = widenBoxes(left.getRight(), right.getRight());
return ProductDomain.create(widBools, widBoxes);
}
}
private static class FirstNBoxesWideningOperator extends BoolBoxesWideningBase{
MyThresholds thresholds = null;
private int boxesToGo;
public FirstNBoxesWideningOperator(int count) {
this.boxesToGo = count;
}
@Override
protected IntegerBoxes widenBoxes(IntegerBoxes left, IntegerBoxes right) {
if (boxesToGo > 0) {// compute new thresholds
boxesToGo -= 1;
MyThresholds newThresholds = new MyThresholds(surroundingBox(IntegerBoxesHelper.getSurroundingBox(left)));
thresholds = newThresholds.join(thresholds);
}
return BoxesWideningOperator.computeWidening(left, right, thresholds);
}
}
private static class FirstNArgsWideningOperator extends BoolBoxesWideningBase{
MyThresholds thresholds = null;
private int argsToGo;
public FirstNArgsWideningOperator(int args) {
this.argsToGo = args;
}
@Override
protected IntegerBoxes widenBoxes(IntegerBoxes left, IntegerBoxes right) {
if (argsToGo > 0) {// compute new thresholds
argsToGo -= 1;
MyThresholds newThresholds = new MyThresholds(IntegerBoxesHelper.getLocalPoints(left));
thresholds = newThresholds.join(thresholds);
}
return BoxesWideningOperator.computeWidening(left, right, thresholds);
}
}
public static WideningOperator<ProductDomain<NonRelationalDomain<Bool>, IntegerBoxes>> getWideningOperator(String repr) {
if (repr.length() == 0)
return DefaultWideningOperator.create();
String[] args = repr.split(":");
if (args.length != 2)
throw new RuntimeException("Unknown format '" + args +"'");
int count = Integer.parseInt(args[1]);
if (count < 0)
throw new RuntimeException("Invalid count '" + count +"'");
if (args[0].equals("box"))
return new FirstNBoxesWideningOperator(count);
if (args[0].equals("arg"))
return new FirstNArgsWideningOperator(count);
throw new RuntimeException("Unknown widening description '" + repr + "'");
}
}