mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-20 14:20:39 +01:00
[poincare] Create the method getPolynomialCoefficients on Expression
This commit is contained in:
@@ -20,6 +20,7 @@ public:
|
||||
Type type() const override;
|
||||
Expression * clone() const override;
|
||||
int polynomialDegree(char symbolName) const override;
|
||||
int getPolynomialCoefficients(char symbolName, Expression ** coefficients) const override;
|
||||
/* Evaluation */
|
||||
template<typename T> static Complex<T> compute(const Complex<T> c, const Complex<T> d);
|
||||
template<typename T> static Matrix * computeOnMatrices(const Matrix * m, const Matrix * n) {
|
||||
|
||||
@@ -222,10 +222,12 @@ public:
|
||||
* variables would overflow the maxNumberOfVariables, getVariables return -1 */
|
||||
static constexpr int k_maxNumberOfVariables = 6;
|
||||
virtual int getVariables(char * variables) const;
|
||||
/* getPolynomialCoefficients fill the table coefficients with the expressions
|
||||
* of the first 4 polynomial coefficients. coefficients is null-terminated
|
||||
* and has up to 4 entries. */
|
||||
//virtual void getPolynomialCoefficients(char symbolName, Expression ** coefficients) const;
|
||||
/* getPolynomialCoefficients fills the table coefficients with the expressions
|
||||
* of the first 5 polynomial coefficients and return polynomialDegree.
|
||||
* coefficients has up to 5 entries. It supposed to be called on Reduced
|
||||
* expression. */
|
||||
static constexpr int k_maxNumberOfPolynomialCoefficients = 4+1;
|
||||
virtual int getPolynomialCoefficients(char symbolName, Expression ** coefficients) const;
|
||||
|
||||
/* Comparison */
|
||||
/* isIdenticalTo is the "easy" equality, it returns true if both trees have
|
||||
@@ -244,6 +246,7 @@ public:
|
||||
/* Simplification */
|
||||
static Expression * ParseAndSimplify(const char * text, Context & context, AngleUnit angleUnit = AngleUnit::Default);
|
||||
static void Simplify(Expression ** expressionAddress, Context & context, AngleUnit angleUnit = AngleUnit::Default);
|
||||
static void Reduce(Expression ** expressionAddress, Context & context, AngleUnit angleUnit, bool recursively = true);
|
||||
|
||||
/* Evaluation Engine
|
||||
* The function evaluate creates a new expression and thus mallocs memory.
|
||||
@@ -293,7 +296,6 @@ private:
|
||||
/* Layout Engine */
|
||||
virtual ExpressionLayout * privateCreateLayout(PrintFloat::Mode floatDisplayMode, ComplexFormat complexFormat) const = 0;
|
||||
/* Simplification */
|
||||
static void Reduce(Expression ** expressionAddress, Context & context, AngleUnit angleUnit, bool recursively = true);
|
||||
Expression * deepBeautify(Context & context, AngleUnit angleUnit);
|
||||
Expression * deepReduce(Context & context, AngleUnit angleUnit);
|
||||
// TODO: should be virtual pure
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
Expression * clone() const override;
|
||||
Sign sign() const override;
|
||||
int polynomialDegree(char symbolName) const override;
|
||||
int getPolynomialCoefficients(char symbolName, Expression ** coefficients) const override;
|
||||
/* Evaluation */
|
||||
template<typename T> static Complex<T> compute(const Complex<T> c, const Complex<T> d);
|
||||
template<typename T> static Matrix * computeOnComplexAndMatrix(const Complex<T> * c, const Matrix * m) {
|
||||
|
||||
@@ -22,6 +22,7 @@ public:
|
||||
Expression * clone() const override;
|
||||
Sign sign() const override;
|
||||
int polynomialDegree(char symbolName) const override;
|
||||
int getPolynomialCoefficients(char symbolName, Expression ** coefficients) const override;
|
||||
template<typename T> static Complex<T> compute(const Complex<T> c, const Complex<T> d);
|
||||
private:
|
||||
constexpr static int k_maxNumberOfTermsInExpandedMultinome = 25;
|
||||
|
||||
@@ -37,6 +37,7 @@ public:
|
||||
Expression * clone() const override;
|
||||
int polynomialDegree(char symbolName) const override;
|
||||
int getVariables(char * variables) const override;
|
||||
int getPolynomialCoefficients(char symbolName, Expression ** coefficients) const override;
|
||||
Sign sign() const override;
|
||||
bool isMatrixSymbol() const;
|
||||
bool isScalarSymbol() const;
|
||||
|
||||
@@ -35,6 +35,25 @@ int Addition::polynomialDegree(char symbolName) const {
|
||||
return degree;
|
||||
}
|
||||
|
||||
int Addition::getPolynomialCoefficients(char symbolName, Expression ** coefficients) const {
|
||||
int deg = polynomialDegree(symbolName);
|
||||
if (deg < 0 || deg > k_maxNumberOfPolynomialCoefficients-1) {
|
||||
return -1;
|
||||
}
|
||||
for (int k = 0; k < deg+1; k++) {
|
||||
coefficients[k] = new Addition();
|
||||
}
|
||||
Expression * intermediateCoefficients[k_maxNumberOfPolynomialCoefficients];
|
||||
for (int i = 0; i < numberOfOperands(); i++) {
|
||||
int d = operand(i)->getPolynomialCoefficients(symbolName, intermediateCoefficients);
|
||||
assert(d < k_maxNumberOfPolynomialCoefficients-1);
|
||||
for (int j = 0; j < d+1; j++) {
|
||||
static_cast<Addition *>(coefficients[j])->addOperand(intermediateCoefficients[j]);
|
||||
}
|
||||
}
|
||||
return deg;
|
||||
}
|
||||
|
||||
/* Layout */
|
||||
|
||||
bool Addition::needParenthesisWithParent(const Expression * e) const {
|
||||
|
||||
@@ -219,6 +219,15 @@ int Expression::getVariables(char * variables) const {
|
||||
return numberOfVariables;
|
||||
}
|
||||
|
||||
int Expression::getPolynomialCoefficients(char symbolName, Expression ** coefficients) const {
|
||||
int deg = polynomialDegree(symbolName);
|
||||
if (deg == 0) {
|
||||
coefficients[0] = clone();
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool Expression::isOfType(Type * types, int length) const {
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (type() == types[i]) {
|
||||
|
||||
@@ -43,6 +43,33 @@ int Multiplication::polynomialDegree(char symbolName) const {
|
||||
return degree;
|
||||
}
|
||||
|
||||
int Multiplication::getPolynomialCoefficients(char symbolName, Expression ** coefficients) const {
|
||||
int deg = polynomialDegree(symbolName);
|
||||
if (deg < 0 || deg + 1 > k_maxNumberOfPolynomialCoefficients) {
|
||||
return -1;
|
||||
}
|
||||
int degA = operand(0)->getPolynomialCoefficients(symbolName, coefficients);
|
||||
assert(degA + 1 <= k_maxNumberOfPolynomialCoefficients);
|
||||
Expression * intermediateCoefficients[k_maxNumberOfPolynomialCoefficients];
|
||||
for (int i = 1; i < numberOfOperands(); i++) {
|
||||
int degB = operand(i)->getPolynomialCoefficients(symbolName, intermediateCoefficients);
|
||||
assert(degB + 1 <= k_maxNumberOfPolynomialCoefficients);
|
||||
for (int j = deg; j > 0; j--) {
|
||||
Addition * a = new Addition();
|
||||
for (int l = 0; l <= j; l++) {
|
||||
if (l <= degB && j-l <= degA) {
|
||||
a->addOperand(new Multiplication(intermediateCoefficients[l], coefficients[j-l], true));
|
||||
}
|
||||
}
|
||||
if (j <= degA) { delete coefficients[j]; };
|
||||
if (j <= degB) { delete intermediateCoefficients[j]; };
|
||||
coefficients[j] = a;
|
||||
}
|
||||
coefficients[0] = new Multiplication(coefficients[0], intermediateCoefficients[0], false);
|
||||
}
|
||||
return deg;
|
||||
}
|
||||
|
||||
bool Multiplication::needParenthesisWithParent(const Expression * e) const {
|
||||
Type types[] = {Type::Division, Type::Power, Type::Factorial};
|
||||
return e->isOfType(types, 3);
|
||||
|
||||
@@ -79,6 +79,33 @@ int Power::polynomialDegree(char symbolName) const {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Power::getPolynomialCoefficients(char symbolName, Expression ** coefficients) const {
|
||||
int deg = polynomialDegree(symbolName);
|
||||
if (deg <= 0) {
|
||||
return deg;
|
||||
}
|
||||
/* Here we only consider the case x^4 as getPolynomialCoefficients is
|
||||
* supposed to be called after reducing the expression. */
|
||||
if (operand(0)->type() == Type::Symbol && static_cast<const Symbol *>(operand(0))->name() == symbolName && operand(1)->type() == Type::Rational) {
|
||||
const Rational * r = static_cast<const Rational *>(operand(1));
|
||||
if (!r->denominator().isOne() || r->sign() == Sign::Negative) {
|
||||
return -1;
|
||||
}
|
||||
if (Integer::NaturalOrder(r->numerator(), Integer(Integer::k_maxExtractableInteger)) > 0) {
|
||||
return -1;
|
||||
}
|
||||
int n = r->numerator().extractedInt();
|
||||
if (n < k_maxNumberOfPolynomialCoefficients) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
coefficients[i] = new Rational(0);
|
||||
}
|
||||
coefficients[n] = new Rational(1);
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Expression * Power::setSign(Sign s, Context & context, AngleUnit angleUnit) {
|
||||
assert(s == Sign::Positive);
|
||||
assert(operand(0)->sign() == Sign::Negative);
|
||||
|
||||
@@ -133,6 +133,16 @@ int Symbol::getVariables(char * variables) const {
|
||||
return variablesLength;
|
||||
}
|
||||
|
||||
int Symbol::getPolynomialCoefficients(char symbolName, Expression ** coefficients) const {
|
||||
if (m_name == symbolName) {
|
||||
coefficients[0] = new Rational(0);
|
||||
coefficients[1] = new Rational(1);
|
||||
return 1;
|
||||
}
|
||||
coefficients[0] = clone();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Expression * Symbol::replaceSymbolWithExpression(char symbol, Expression * expression) {
|
||||
if (m_name == symbol) {
|
||||
Expression * value = expression->clone();
|
||||
|
||||
@@ -102,3 +102,30 @@ QUIZ_CASE(poincare_get_variables) {
|
||||
assert_parsed_expression_has_variables("abcde", "abcde");
|
||||
assert_parsed_expression_has_variables("x^2+2*y+k!*A+w", "xykw");
|
||||
}
|
||||
|
||||
void assert_parsed_expression_has_polynomial_coefficient(const char * expression, char symbolName, const char ** coefficients, Expression::AngleUnit angleUnit = Expression::AngleUnit::Degree) {
|
||||
GlobalContext globalContext;
|
||||
Expression * e = parse_expression(expression);
|
||||
Expression::Reduce(&e, globalContext, angleUnit);
|
||||
Expression * coefficientBuffer[Poincare::Expression::k_maxNumberOfPolynomialCoefficients];
|
||||
int d = e->getPolynomialCoefficients(symbolName, coefficientBuffer);
|
||||
for (int i = 0; i <= d; i++) {
|
||||
Expression * f = parse_expression(coefficients[i]);
|
||||
Expression::Reduce(&coefficientBuffer[i], globalContext, angleUnit);
|
||||
Expression::Reduce(&f, globalContext, angleUnit);
|
||||
assert(coefficientBuffer[i]->isIdenticalTo(f));
|
||||
delete f;
|
||||
delete coefficientBuffer[i];
|
||||
}
|
||||
assert(coefficients[d+1] == 0);
|
||||
delete e;
|
||||
}
|
||||
|
||||
QUIZ_CASE(poincare_get_polynomial_coefficients) {
|
||||
const char * coefficient0[] = {"2", "1", "1", 0};
|
||||
assert_parsed_expression_has_polynomial_coefficient("x^2+x+2", 'x', coefficient0);
|
||||
const char * coefficient1[] = {"12+(-6)*P", "12", "3", 0}; //3*x^2+12*x-6*π+12
|
||||
assert_parsed_expression_has_polynomial_coefficient("3*(x+2)^2-6*P", 'x', coefficient1);
|
||||
const char * coefficient2[] = {"2+32*x", "2", "6", "2", 0}; //2*n^3+6*n^2-2*n+2+32*x
|
||||
assert_parsed_expression_has_polynomial_coefficient("2*(n+1)^3-4n+32*x", 'n', coefficient2);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user