package mmc;
/**
* This class provides routines for function interpolation. Include the function to be interpolated
* in a class that implements the interface FunctionInt or FunctionInt2 (defined below).
* Methods contained here are based on the Numerical Recipes (W. H. Press et al.).
*
* interface FunctionInt{
* double functionInt(double x);
* }
*
* interface FunctionInt2{
* double functionInt(double x1, double x2);
* }
*
* @author Dmitry Chirkin
*/
public class Interpolate extends MathModel implements FunctionInt{
private int romberg, rombergY;
private double[] iX;
private double[] iY;
private double[] c;
private double[] d;
private int max;
private double xmin, xmax, step;
private boolean rational, relative;
private FunctionInt2 function2int;
private Interpolate[] I;
private int row, starti;
private boolean rationalY, relativeY;
private boolean reverse, self=true, flag;
private boolean isLog, logSubst;
public double precision, worstX;
public double precision2, worstX2;
public double precisionY, worstY;
public static boolean fast=true;
//----------------------------------------------------------------------------------------------------//
/**
* initializes class for the 1-dimensional function
*/
public Interpolate(int max, double xmin, double xmax, FunctionInt function2int,
int romberg, boolean rational, boolean relative, boolean isLog,
int rombergY, boolean rationalY, boolean relativeY, boolean logSubst){
this(max, xmin, xmax, romberg, rational, relative, isLog, rombergY, rationalY, relativeY, logSubst);
int i;
double aux, xaux;
for(i=0,aux=this.xmin+step/2; i 0, setting to 1");
max=1;
}
if(isLog){
if(xmin<=0){
Output.err.println("Warning (in Interpolate/Interpolate/1): xmin = "+xmin+" must be > 0, setting to 1");
xmin=1;
}
if(xmax<=0){
Output.err.println("Warning (in Interpolate/Interpolate/2): xmax = "+xmax+" must be > 0, setting to 1");
xmax=1;
}
}
if(xmin==xmax) max=1;
else if(xmin>xmax){ aux=xmin; xmin=xmax; xmax=aux; }
if(romberg<=0){
Output.err.println("Warning (in Interpolate/Interpolate/3): romberg = "+romberg+" must be > 0, setting to 1");
romberg=1;
}
if(romberg>max){
Output.err.println("Warning (in Interpolate/Interpolate/4): romberg = "+romberg+" must be <= max = "+max+", setting to "+max);
romberg=max;
}
if(rombergY<=0){
Output.err.println("Warning (in Interpolate/Interpolate/5): rombergY = "+rombergY+" must be > 0, setting to 1");
rombergY=1;
}
if(rombergY>max){
Output.err.println("Warning (in Interpolate/Interpolate/6): rombergY = "+rombergY+" must be <= max = "+max+", setting to "+max);
rombergY=max;
}
this.max=max;
if(Math.log(max)/Math.log(2)+romberg=max) starti=max-1;
start=(int)(aux-0.5*(romberg-1));
if(start<0) start=0;
if(start+romberg>max || start>max) start=max-romberg;
result=interpolate(x, start);
if(logSubst) if(self) result=exp(result);
return result;
}
//----------------------------------------------------------------------------------------------------//
/**
* interpolates f(x) for 2d function
*/
public double interpolate(double x1, double x2){
int i, start;
double aux, aux2=0, result;
if(isLog) x2=Math.log(x2);
reverse=true;
aux=(x2-xmin)/step;
starti=(int)aux;
if(starti<0) starti=0;
if(starti>=max) starti=max-1;
start=(int)(aux-0.5*(romberg-1));
if(start<0) start=0;
if(start+romberg>max || start>max) start=max-romberg;
for(i=start; iaux){
aux=I[i].precision;
aux2=I[i].worstX;
}
if(aux>precision2){
precision2=aux;
worstX2=aux2;
}
}
result=interpolate(x2, start);
if(logSubst) result=exp(result);
return result;
}
//----------------------------------------------------------------------------------------------------//
/**
* interpolates f(x) for 1d function if the arrays already exist.
*/
public double interpolateArray(double x){
int i, j, m, start, auxdir;
boolean dir;
reverse=false;
i=0;
j=max-1;
dir=iX[max-1]>iX[0];
while(j-i>1){
m=(i+j)/2;
if(x>iX[m]==dir) i=m;
else j=m;
}
if(i+1max || start>max) start=max-romberg;
return interpolate(x, start);
}
//----------------------------------------------------------------------------------------------------//
/**
* interpolates f(x) based on the values iY[i]=f(iX[i]) in the romberg-vicinity of x
*/
private double interpolate(double x, int start){
int num, i, k;
boolean dd, doLog;
double error=0, result=0;
double aux, aux2, dx1, dx2;
doLog=false;
if(logSubst) if(reverse) for(i=0;iaux2-x == aux2>aux) dd=true;
else dd=false;
}
else{
if(Math.abs(x-aux) > Math.abs(x-aux2)) dd=true;
else dd=false;
}
}
result=iY[start+num];
if(doLog) result=exp(result);
for(k=1;kprecision){
precision=aux;
worstX=x;
}
}
if(doLog) result=log(result);
return result;
}
//----------------------------------------------------------------------------------------------------//
/**
* finds x: f(x)=y, 1d initialization required
*/
public double findLimit(double y){
int i, j, m, start, auxdir, auxR;
boolean dir, rat=false, rel;
double result, aux;
double[] ii;
reverse=false;
if(logSubst) y=log(y);
i=0;
j=max-1;
dir=iY[max-1]>iY[0];
while(j-i>1){
m=(i+j)/2;
if(y>iY[m]==dir) i=m;
else j=m;
}
ii=iX; iX=iY; iY=ii;
if(!fast){
aux=precision; precision=precisionY; precisionY=aux;
aux=worstX; worstX=worstY; worstY=aux;
rat=rational; rational=rationalY;
}
auxR=romberg; romberg=rombergY; rombergY=auxR;
rel=relative; relative=relativeY;
if(i+1max || start>max) start=max-romberg;
result=interpolate(y, start);
ii=iX; iX=iY; iY=ii;
if(!fast){
aux=precision; precision=precisionY; precisionY=aux;
aux=worstX; worstX=worstY; worstY=aux;
rational=rat;
}
auxR=romberg; romberg=rombergY; rombergY=auxR;
relative=rel;
if(resultxmax) result=xmax;
if(isLog) result=Math.exp(result);
return result;
}
//----------------------------------------------------------------------------------------------------//
/**
* flag check helper
*/
private double IX(int i, double x){
return flag?I[i].interpolate(x):iX[i];
}
//----------------------------------------------------------------------------------------------------//
/**
* flag check helper
*/
private double IY(int i, double x){
return flag?I[i].interpolate(x):iY[i];
}
//----------------------------------------------------------------------------------------------------//
/**
* finds x: f(a,x)=y, 2d initialization required
*/
public double findLimit(double x1, double y){
int i, j, m, start, auxdir, auxR;
boolean dir, rat=false, rel;
double result, aux, aux2=0;
double[] ii;
reverse=false;
if(logSubst) y=log(y);
if(!flag) for(i=0; iIY(0, x1);
while(j-i>1){
m=(i+j)/2;
aux=IY(m, x1);
if(y>aux==dir) i=m;
else j=m;
}
ii=iX; iX=iY; iY=ii;
if(!fast){
aux=precision; precision=precisionY; precisionY=aux;
aux=worstX; worstX=worstY; worstY=aux;
rat=rational; rational=rationalY;
}
auxR=romberg; romberg=rombergY; rombergY=auxR;
rel=relative; relative=relativeY;
if(i+1max || start>max) start=max-romberg;
if(flag) for(i=start; ixmax) result=xmax;
if(!fast){
aux=0;
for(i=start; iaux){
aux=I[i].precision;
aux2=I[i].worstX;
}
if(aux>precision2){
precision2=aux;
worstX2=aux2;
}
}
if(isLog) result=Math.exp(result);
return result;
}
//----------------------------------------------------------------------------------------------------//
final protected static double bigNumber=-300;
final protected static double aBigNumber=-299;
/**
* Exp if not zero
*/
private static double exp(double x){
if(x<=aBigNumber) return 0;
else return Math.exp(x);
}
//----------------------------------------------------------------------------------------------------//
/**
* Log if not zero
*/
private static double log(double x){
if(x<=0) return bigNumber;
else return Math.log(x);
}
//----------------------------------------------------------------------------------------------------//
private static double x_save=1, y_save=0;
/**
* Log it again
*/
private static double slog(double x){
return x==x_save?y_save:(y_save=Math.log(x_save=x));
}
}