package urban.shapes;
import static urban.util.Pair.pairOf;
import java.util.Map.Entry;
import urban.model.Rule;
import urban.transformers.RuleToRuleGraphTransformer;
/**
* Calculates rates from the given ShapeParameters for Rules
*
* @see ShapeParameters
* @see urban.model.Rule
*/
public class RateCalculator {
private final ShapeParameters parameters;
/**
* @param parameters The values and shapes used for calculating the rates
*/
public RateCalculator(ShapeParameters parameters) {
this.parameters = parameters;
}
/**
* @param g Generator for the rule
* @param in Rule which the rates will be calculated from
* @return A new rule with a calculated rate, if no shape or generator matches then the rates will be 1
*/
public Rule calculateRates(Generator g, Rule in){
RuleGraph rg = new RuleToRuleGraphTransformer().transform(in);
Double forward = Math.pow(Math.E, getConstant(g) + shapes(g,rg, false, 0) - shapes(g,rg, true, 0) );
Double backward = Math.pow(Math.E, getConstant(g) + shapes(g,rg, false, 1) - shapes(g,rg, true, 1) );
return new Rule(in.getName(), in.getLhs(), in.getRhs(), true, forward, backward);
}
private Double getConstant(Generator g) {
Double val = parameters.constants.get(g);
return Math.log(val == null ? 0.0 : val);
}
private Double shapes(Generator g, RuleGraph rg, boolean left, double lambdaMod) {
double tmp = 0;
for(Entry<Shape, Double> epsilon : parameters.epsilons.entrySet()){
final Double value = epsilon.getValue();
if (value != 0.0){
final Shape shape = epsilon.getKey();
tmp += (getLambda(g, shape) + lambdaMod) * value * shape.getMatchPermutations(rg, left).size();
}
}
return tmp;
}
private Double getLambda(Generator g, final Shape shape) {
Double tmp = parameters.lambda.get(pairOf(g,shape));
return tmp == null ? -0.5 : tmp;
}
}