package calculus;
import java.util.ArrayList;
import java.util.concurrent.RecursiveTask;
import lipstone.joshua.parser.Parser;
import lipstone.joshua.parser.exceptions.ParserException;
import lipstone.joshua.parser.types.BigDec;
import lipstone.joshua.parser.util.ConsCell;
import lipstone.joshua.parser.util.ConsType;
public class NIThread extends RecursiveTask<BigDec> {
private ConsCell equation;
private ArrayList<ConsCell> varCells;
private static String var;
private static Parser parser;
private int N;
private static int maxN;
private static double accuracy;
private BigDec min, max;
public ParserException error;
private static Calculus caller;
private static BigDec maxRange;
private NIThread(ConsCell equation, int N, BigDec min, BigDec max) {
super();
this.equation = equation.clone();
this.N = N;
this.min = min;
this.max = max;
varCells = equation.allInstancesOf(new ConsCell(var, ConsType.IDENTIFIER));
}
public NIThread(ConsCell equation, Parser parser, int N, int maxN, double accuracy, BigDec min, BigDec max, BigDec maxRange, String var, Calculus caller) {
super();
this.equation = equation.clone();
this.parser = parser;
this.N = N;
this.maxN = maxN;
this.accuracy = accuracy;
this.min = min;
this.max = max;
this.maxRange = maxRange;
this.var = var;
this.caller = caller;
varCells = equation.allInstancesOf(new ConsCell(var, ConsType.IDENTIFIER));
}
private BigDec trapezoidal(BigDec last, int N) throws ParserException {
BigDec answer = BigDec.ZERO, deltaX = max.subtract(min).divide(new BigDec(N)).abs(), sigma = BigDec.ZERO;
for (int n = 0; n < N; n++) {
//In basic types: sigma = sigma + Double.parseDouble(parser.run(equation.replaceAll(var, new Double(a + n*deltaX).toString()), false)) +
//Double.parseDouble(parser.run(equation.replaceAll(var, new Double(a + (n+1)*deltaX).toString()), false));
BigDec x = min.add(deltaX.multiply(new BigDec(n)));
for (ConsCell varCell : varCells)
varCell.replaceCar(new ConsCell(x, ConsType.NUMBER));
sigma = sigma.add((BigDec) parser.run(equation).getCar());
x = min.add(deltaX.multiply((new BigDec(n).add(new BigDec(1)))));
for (ConsCell varCell : varCells)
varCell.replaceCar(new ConsCell(x, ConsType.NUMBER));
sigma = sigma.add((BigDec) parser.run(equation).getCar());
}
//In basic types: answer = (b-a)/(2*N)*sigma
answer = (max.subtract(min).divide(new BigDec(N).multiply(new BigDec(2)))).multiply(sigma);
if (answer.subtract(last).abs().doubleValue() < accuracy)
return answer;
else if (N >= maxN)
throw new ParserException("The integration system ran out of time", caller);
else
return trapezoidal(answer, N * 2);
}
@Override
protected BigDec compute() {
BigDec answer = BigDec.ZERO;
try {
if (max.subtract(min).lteq(maxRange))
answer = trapezoidal(BigDec.ZERO, N);
else {
NIThread left = new NIThread(equation, N / 2, min, min.add(max.subtract(min).divide(new BigDec(2))));
NIThread right = new NIThread(equation, N / 2, min.add(max.subtract(min).divide(new BigDec(2))), max);
left.fork();
answer = right.compute();
answer = answer.add(left.join());
if (right.error != null) {
error = right.error;
if (error.getThrower() == null)
error.setThrower(caller);
return answer;
}
if (left.error != null) {
error = left.error;
if (error.getThrower() == null)
error.setThrower(caller);
return answer;
}
}
}
catch (ParserException e) {
error = e;
}
return answer;
}
}