/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package jmathexpr.arithmetic.pattern;
import jmathexpr.Constant;
import jmathexpr.Expression;
import jmathexpr.Variable;
import jmathexpr.arithmetic.Numbers;
import jmathexpr.arithmetic.integer.Integers;
import jmathexpr.arithmetic.natural.NaturalNumber;
import jmathexpr.arithmetic.natural.Naturals;
import jmathexpr.arithmetic.op.Division;
import jmathexpr.arithmetic.op.Exponentiation;
import jmathexpr.arithmetic.op.Multiplication;
import jmathexpr.arithmetic.op.Negation;
import jmathexpr.util.pattern.AbstractPattern;
import jmathexpr.util.pattern.FunctionPattern;
/**
* Pattern for a polynomial term (ax^n).
*
* @author Elemér Furka
*/
public class PolynomialTermPattern extends AbstractPattern {
private final Variable x;
private final NumberPattern n = new NumberPattern();
private final Constant coeff = Numbers.constant("c");
private final NaturalNumber degree;
/**
* Creates a new pattern that matches any polynomial term of the given
* indeterminate.
*
* @param x the indeterminate
*/
public PolynomialTermPattern(Variable x) {
this.x = x;
degree = null;
}
/**
* Creates a new pattern that matches any polynomial of the given degree.
*
* @param x the indeterminate
* @param degree the polynomial term's expected degree
*/
public PolynomialTermPattern(Variable x, long degree) {
this.x = x;
this.degree = Naturals.getInstance().create(degree);
}
@Override
public boolean matches(Expression expr) {
value = expr;
if (coeff.matches(expr) && (degree == null || degree.isZero())) { // P = const
return n.matches(Naturals.zero());
} else if (matchesPower(expr)) { // P = x or x^n
return coeff.matches(Naturals.one());
} else if (expr instanceof Negation) { // P = -(Q)
if (matches(((Negation) expr).getChild())) {
return coeff.matches(new Negation(coeff.hit()).evaluate());
}
} else {
FunctionPattern f = new FunctionPattern(x);
Negation nf = new Negation(f);
if (nf.matches(expr) && matchesPower(f.hit())) {
return coeff.matches(Integers.getInstance().create(-1));
}
Multiplication ax = new Multiplication(coeff, f);
if (ax.matches(expr) && matchesPower(f.hit())) { // P = ax^n
return true;
}
Constant c = Numbers.constant("c");
Division xc = new Division(f, c);
if (xc.matches(expr) && matchesPower(f.hit())) { // P = x^n/c
return coeff.matches(new Division(Naturals.one(), c.hit()).evaluate());
}
}
value = null;
return false;
}
private boolean matchesPower(Expression expr) {
if (x.matches(expr) && (degree == null || degree.isOne())) { // x
return n.matches(Naturals.one());
} else {
Exponentiation xn = new Exponentiation(x, n);
if (xn.matches(expr) && (degree == null || degree.equals(n.hit()))) { // x^n
return true;
}
}
return false;
}
/**
* Returns the polynomial's coefficient after a successful match.
*
* @return the matching polynomial's coefficient
*/
public Expression coefficient() {
return coeff.hit();
}
/**
* Returns the polynomial's degree.
*
* @return the exponent of the indeterminate
*/
public NaturalNumber exponent() {
return (NaturalNumber) n.hit();
}
@Override
public String toString() {
return String.format("PTP[%s]", degree);
}
}