/*
* Copyright 2006, United States Government as represented by the Administrator
* for the National Aeronautics and Space Administration. No copyright is
* claimed in the United States under Title 17, U.S. Code. All Other Rights
* Reserved.
*
* Created on Mar 30, 2004
*/
package gov.nasa.ial.mde.solver;
import gov.nasa.ial.mde.math.PNom;
import gov.nasa.ial.mde.math.PointXY;
import gov.nasa.ial.mde.math.RealZero;
import gov.nasa.ial.mde.solver.symbolic.AnalyzedEquation;
import gov.nasa.ial.mde.solver.symbolic.Expression;
import gov.nasa.ial.mde.solver.symbolic.RationalExpression;
import java.util.ArrayList;
import java.util.Collections;
/**
* The class represents a solved rational function.
*
* @author ddexter
* @version 1.0
* @since 1.0
*/
public class SolvedRationalFunction extends SolvedXYGraph {
private PNom fNumerator, fDenominator;
private PNom dfNumerator, dfDenominator;
private PNom[] qf;
private PointXY left, right;
private IntervalEndpoint[] endPoints;
/** Identify new features so we can access them with SolvedGraph.putFeature */
protected String[] newFeatures = { "FunctionAnalysisData" };
/**
* Constructs a solved rational function from the specified analyzed equation.
*
* @param ae the analyzed equation.
*/
public SolvedRationalFunction(AnalyzedEquation ae) {
this(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, ae);
} // end SolvedRationalFunction
/**
* Constructs a solved rational function from the specified analyzed equation
* and left and right values.
*
* @param lft the left endpoint.
* @param rgt the right endpoint.
* @param ae the analyzed equation.
*/
public SolvedRationalFunction(double lft, double rgt, AnalyzedEquation ae) {
super(ae);
Expression e = ae.getFunction();
if (e == null)
throw new IllegalArgumentException("Input equation is not a function.");
RationalExpression r = new RationalExpression(new Expression(e.toString()));
if (!r.isRationalExpression())
throw new IllegalArgumentException("Not a rational function");
r.setParameterHash(ae.getParameterHash());
if ((!r.getNumerator().hasConstantCoefficients()) || (!r.getDenominator().hasConstantCoefficients()))
throw new IllegalArgumentException("Not a rational function");
String iv = ae.getIndependentVariable();
fNumerator = PNom.getPNom(r.getNumerator(), iv);
fDenominator = PNom.getPNom(r.getDenominator(), iv);
// take out common factors
PNom cf = PNom.gcd(fNumerator, fDenominator);
if (!cf.isConstant()) {
fNumerator = fNumerator.quotient(cf)[0];
fDenominator = fDenominator.quotient(cf)[0];
} // end if
qf = fNumerator.quotient(fDenominator);
// d(Hi/Ho) = (Ho dHi - Hi dHo)/(HoHo)
dfNumerator = fDenominator.product(fNumerator.derivative()).difference(
fNumerator.product(fDenominator.derivative()));
dfDenominator = fDenominator.product(fDenominator);
// take out common factors
if (!(cf = PNom.gcd(dfNumerator, dfDenominator)).isConstant()) {
dfNumerator = dfNumerator.quotient(cf)[0];
dfDenominator = dfDenominator.quotient(cf)[0];
} // end if
setEndPoints(lft, rgt);
findPoints();
putNewFeatures(newFeatures);
if (qf[1].isTrivial()) {
putFeature("graphName", "polynomial");
//TODO mess with degree, get it for polynomial
putNewFeature("FunctionAnalysisData", "degree", "" + qf[0].getDegree(), true);
} // end if
else
putFeature("graphName", "RationalFunction");
putFeature("FunctionAnalysisData", getMFN());
} // end SolvedRationalFunction
/**
* Evaluates the function for the given value of x.
*
* @param x the value to evaluate.
* @return value of the function for the given value of x.
*/
public double eval(double x) {
if (Double.isInfinite(x))
return qf[0].eval(x);
return qf[0].eval(x) + qf[1].eval(x) / fDenominator.eval(x);
} // end eval
/**
* Sets the left and right endpoints.
*
* @param lft the left endpoint.
* @param rgt the right endpoint.
*/
public void setEndPoints(double lft, double rgt) {
left = new PointXY(lft, eval(lft));
right = new PointXY(rgt, eval(rgt));
} // end setEndPoints
private MdeFeatureNode getMFN() {
MdeFeatureNode r = new MdeFeatureNode();
int i, n = endPoints.length;
r.addKey("EndPoint");
r.addKey("intervalDescription");
for (i = 0; i < n; i++)
r.addValue("EndPoint", endPoints[i].getMFN());
for (i = 1; i < n; i++)
r.addValue("intervalDescription", new IntervalDescription(endPoints[i - 1], endPoints[i])
.getMFN());
return r;
} // end getMFN
private void findPoints() {
boolean addLeft = true, addRight = true;
ArrayList<IntervalEndpoint> points = new ArrayList<IntervalEndpoint>();
RealZero[] criticals = dfNumerator.getRealZeros();
RealZero[] singulars = fDenominator.getRealZeros();
IntervalEndpoint newPoint = null;
int i, nc = criticals.length, ns = singulars.length;
for (i = 0; i < nc; i++) {
double x = criticals[i].getX();
if (x < left.x)
continue;
if (x > right.x)
break;
if (x == left.x)
addLeft = false;
if (x == right.x)
addRight = false;
switch (criticals[i].getSignature(dfDenominator)) {
case RealZero.PLUS_PLUS:
case RealZero.MINUS_MINUS:
newPoint = new IntervalEndpoint(criticals[i], IntervalEndpoint.INFLECTION_POINT);
break;
case RealZero.MINUS_PLUS:
newPoint = new IntervalEndpoint(criticals[i], IntervalEndpoint.LOCAL_MIN);
break;
case RealZero.PLUS_MINUS:
newPoint = new IntervalEndpoint(criticals[i], IntervalEndpoint.LOCAL_MAX);
break;
} // end switch
newPoint.leftYValue = newPoint.rightYValue = fNumerator.eval(x) / fDenominator.eval(x);
points.add(newPoint);
} // end for i
for (i = 0; i < ns; i++) {
double x = singulars[i].getX();
if (x < left.x)
continue;
if (x > right.x)
break;
if (x == left.x)
addLeft = false;
if (x == right.x)
addRight = false;
newPoint = new IntervalEndpoint(singulars[i], IntervalEndpoint.VERTICAL_ASYMPTOTE);
switch (singulars[i].getSignature()) {
case RealZero.MINUS_MINUS:
newPoint.leftYValue = newPoint.rightYValue = Double.NEGATIVE_INFINITY * fNumerator.eval(x);
break;
case RealZero.PLUS_PLUS:
newPoint.leftYValue = newPoint.rightYValue = Double.POSITIVE_INFINITY * fNumerator.eval(x);
break;
case RealZero.PLUS_MINUS:
newPoint.leftYValue = Double.POSITIVE_INFINITY * fNumerator.eval(x);
newPoint.rightYValue = Double.NEGATIVE_INFINITY * fNumerator.eval(x);
break;
case RealZero.MINUS_PLUS:
newPoint.rightYValue = Double.POSITIVE_INFINITY * fNumerator.eval(x);
newPoint.leftYValue = Double.NEGATIVE_INFINITY * fNumerator.eval(x);
break;
} // end switch
points.add(newPoint);
} // end for i
if (addLeft)
points.add(new IntervalEndpoint(left));
if (addRight)
points.add(new IntervalEndpoint(right));
Collections.sort(points);
endPoints = points.toArray(new IntervalEndpoint[0]);
} // end findPoints
// public static void main(String[] args) {
// SolvedRationalFunction srf = new SolvedRationalFunction(
// new AnalyzedEquation(gov.nasa.ial.mde.util.StringSplitter.combineArgs(args)));
// System.out.println(srf.getXMLString());
// }
}