[poincare] Create the method getPolynomialCoefficients on Expression

This commit is contained in:
Émilie Feral
2018-05-28 10:01:07 +02:00
parent 3047803447
commit 85fcc9c705
11 changed files with 130 additions and 5 deletions

View File

@@ -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) {

View File

@@ -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

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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]) {

View File

@@ -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);

View File

@@ -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);

View File

@@ -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();

View File

@@ -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);
}