diff --git a/apps/calculation/calculation_store.cpp b/apps/calculation/calculation_store.cpp index 850ea48c5..f6028d79a 100644 --- a/apps/calculation/calculation_store.cpp +++ b/apps/calculation/calculation_store.cpp @@ -97,7 +97,7 @@ ExpiringPointer CalculationStore::push(const char * text, Context * // Outputs hold exact output, approximate output and its duplicate constexpr static int numberOfOutputs = Calculation::k_numberOfExpressions - 1; Expression outputs[numberOfOutputs] = {Expression(), Expression(), Expression()}; - PoincareHelpers::ParseAndSimplifyAndApproximate(inputSerialization, &(outputs[0]), &(outputs[1]), context, false); + PoincareHelpers::ParseAndSimplifyAndApproximate(inputSerialization, &(outputs[0]), &(outputs[1]), context, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined); outputs[2] = outputs[1]; int numberOfSignificantDigits = Poincare::PrintFloat::k_numberOfStoredSignificantDigits; for (int i = 0; i < numberOfOutputs; i++) { diff --git a/apps/shared/poincare_helpers.h b/apps/shared/poincare_helpers.h index 0f2ba050e..31010f61f 100644 --- a/apps/shared/poincare_helpers.h +++ b/apps/shared/poincare_helpers.h @@ -50,25 +50,26 @@ inline T ApproximateWithValueForSymbol(const Poincare::Expression e, const char } template -inline T ApproximateToScalar(const char * text, Poincare::Context * context, bool symbolicComputation = true) { +inline T ApproximateToScalar(const char * text, Poincare::Context * context, Poincare::ExpressionNode::SymbolicComputation symbolicComputation = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition) { Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences(); Poincare::Preferences::ComplexFormat complexFormat = Poincare::Expression::UpdatedComplexFormatWithTextInput(preferences->complexFormat(), text); return Poincare::Expression::ApproximateToScalar(text, context, complexFormat, preferences->angleUnit(), symbolicComputation); } -inline Poincare::Expression ParseAndSimplify(const char * text, Poincare::Context * context, bool symbolicComputation = true) { +inline Poincare::Expression ParseAndSimplify(const char * text, Poincare::Context * context, Poincare::ExpressionNode::SymbolicComputation symbolicComputation = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition) { Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences(); Poincare::Preferences::ComplexFormat complexFormat = Poincare::Expression::UpdatedComplexFormatWithTextInput(preferences->complexFormat(), text); return Poincare::Expression::ParseAndSimplify(text, context, complexFormat, preferences->angleUnit(), symbolicComputation); } -inline void Simplify(Poincare::Expression * e, Poincare::Context * context, Poincare::ExpressionNode::ReductionTarget target, bool symbolicComputation = true) { +inline void Simplify(Poincare::Expression * e, Poincare::Context * context, Poincare::ExpressionNode::ReductionTarget target, Poincare::ExpressionNode::SymbolicComputation symbolicComputation = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition) { Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences(); Poincare::Preferences::ComplexFormat complexFormat = Poincare::Expression::UpdatedComplexFormatWithExpressionInput(preferences->complexFormat(), *e, context); - *e = e->simplify(context, complexFormat, preferences->angleUnit(), target, symbolicComputation); + + *e = e->simplify(Poincare::ExpressionNode::ReductionContext(context, complexFormat, preferences->angleUnit(), target, symbolicComputation)); } -inline void ParseAndSimplifyAndApproximate(const char * text, Poincare::Expression * simplifiedExpression, Poincare::Expression * approximateExpression, Poincare::Context * context, bool symbolicComputation = true) { +inline void ParseAndSimplifyAndApproximate(const char * text, Poincare::Expression * simplifiedExpression, Poincare::Expression * approximateExpression, Poincare::Context * context, Poincare::ExpressionNode::SymbolicComputation symbolicComputation = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition) { Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences(); Poincare::Preferences::ComplexFormat complexFormat = Poincare::Expression::UpdatedComplexFormatWithTextInput(preferences->complexFormat(), text); Poincare::Expression::ParseAndSimplifyAndApproximate(text, simplifiedExpression, approximateExpression, context, complexFormat, preferences->angleUnit(), symbolicComputation); diff --git a/apps/solver/equation_store.cpp b/apps/solver/equation_store.cpp index 6fe84b003..899a6b522 100644 --- a/apps/solver/equation_store.cpp +++ b/apps/solver/equation_store.cpp @@ -168,7 +168,7 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context, bool bool isLinear = true; // Invalid the linear system if one equation is non-linear Preferences * preferences = Preferences::sharedPreferences(); for (int i = 0; i < numberOfDefinedModels(); i++) { - isLinear = isLinear && modelForRecord(definedRecordAtIndex(i))->standardForm(context, replaceFunctionsButNotSymbols).getLinearCoefficients((char *)m_variables, Poincare::SymbolAbstract::k_maxNameSize, coefficients[i], &constants[i], context, updatedComplexFormat(context), preferences->angleUnit()); + isLinear = isLinear && modelForRecord(definedRecordAtIndex(i))->standardForm(context, replaceFunctionsButNotSymbols).getLinearCoefficients((char *)m_variables, Poincare::SymbolAbstract::k_maxNameSize, coefficients[i], &constants[i], context, updatedComplexFormat(context), preferences->angleUnit(), replaceFunctionsButNotSymbols ? ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions : ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition); if (!isLinear) { // TODO: should we clean pool allocated memory if the system is not linear #if 0 @@ -199,7 +199,7 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context, bool // Step 3. Polynomial & Monovariable? assert(numberOfVariables == 1 && numberOfDefinedModels() == 1); Expression polynomialCoefficients[Expression::k_maxNumberOfPolynomialCoefficients]; - int degree = modelForRecord(definedRecordAtIndex(0))->standardForm(context, replaceFunctionsButNotSymbols).getPolynomialReducedCoefficients(m_variables[0], polynomialCoefficients, context, updatedComplexFormat(context), preferences->angleUnit()); + int degree = modelForRecord(definedRecordAtIndex(0))->standardForm(context, replaceFunctionsButNotSymbols).getPolynomialReducedCoefficients(m_variables[0], polynomialCoefficients, context, updatedComplexFormat(context), preferences->angleUnit(), replaceFunctionsButNotSymbols ? ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions : ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition); if (degree == 2) { // Polynomial degree <= 2 m_type = Type::PolynomialMonovariable; @@ -299,7 +299,7 @@ EquationStore::Error EquationStore::oneDimensialPolynomialSolve(Expression exact assert(degree == 2); // Compute delta = b*b-4ac Expression delta = Subtraction::Builder(Power::Builder(coefficients[1].clone(), Rational::Builder(2)), Multiplication::Builder(Rational::Builder(4), coefficients[0].clone(), coefficients[2].clone())); - delta = delta.simplify(context, updatedComplexFormat(context), Poincare::Preferences::sharedPreferences()->angleUnit(), ExpressionNode::ReductionTarget::SystemForApproximation); + delta = delta.simplify(ExpressionNode::ReductionContext(context, updatedComplexFormat(context), Poincare::Preferences::sharedPreferences()->angleUnit(), ExpressionNode::ReductionTarget::SystemForApproximation)); if (delta.isUninitialized()) { delta = Poincare::Undefined::Builder(); } diff --git a/poincare/include/poincare/addition.h b/poincare/include/poincare/addition.h index 25e32a7d6..cf90a80ef 100644 --- a/poincare/include/poincare/addition.h +++ b/poincare/include/poincare/addition.h @@ -25,7 +25,7 @@ public: // Properties Type type() const override { return Type::Addition; } int polynomialDegree(Context * context, const char * symbolName) const override; - int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const override; + int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const override; // Evaluation template static Complex compute(const std::complex c, const std::complex d, Preferences::ComplexFormat complexFormat) { return Complex::Builder(c+d); } @@ -79,7 +79,7 @@ public: // Expression Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); Expression shallowBeautify(ExpressionNode::ReductionContext reductionContext); - int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const; + int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const; void sortChildrenInPlace(NAryExpressionNode::ExpressionOrder order, Context * context, bool canBeInterrupted) { NAryExpression::sortChildrenInPlace(order, context, true, canBeInterrupted); } diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 05939e68d..77dec6c9e 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -187,14 +187,14 @@ public: * the variables hold in 'variables'. Otherwise, it fills 'coefficients' with * the coefficients of the variables hold in 'variables' (following the same * order) and 'constant' with the constant of the expression. */ - bool getLinearCoefficients(char * variables, int maxVariableLength, Expression coefficients[], Expression constant[], Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; + bool getLinearCoefficients(char * variables, int maxVariableLength, Expression coefficients[], Expression constant[], Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation) const; /* getPolynomialCoefficients fills the table coefficients with the expressions * of the first 3 polynomial coefficients and returns the polynomial degree. * It is supposed to be called on a reduced expression. * coefficients has up to 3 entries. */ static constexpr int k_maxPolynomialDegree = 2; static constexpr int k_maxNumberOfPolynomialCoefficients = k_maxPolynomialDegree+1; - int getPolynomialReducedCoefficients(const char * symbolName, Expression coefficients[], Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; + int getPolynomialReducedCoefficients(const char * symbolName, Expression coefficients[], Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation) const; Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) { return node()->replaceSymbolWithExpression(symbol, expression); } /* Complex */ @@ -231,12 +231,12 @@ public: * account the complex format required in the expression they return. * (For instance, in Polar mode, they return an expression of the form * r*e^(i*th) reduced and approximated.) */ - static Expression ParseAndSimplify(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool symbolicComputation = true); - Expression simplify(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target, bool symbolicComputation = true); + static Expression ParseAndSimplify(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition); + Expression simplify(ExpressionNode::ReductionContext reductionContext); - static void ParseAndSimplifyAndApproximate(const char * text, Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool symbolicComputation = true); - void simplifyAndApproximate(Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool symbolicComputation = true); - Expression reduce(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target = ExpressionNode::ReductionTarget::SystemForApproximation); + static void ParseAndSimplifyAndApproximate(const char * text, Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition); + void simplifyAndApproximate(Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition); + Expression reduce(ExpressionNode::ReductionContext context); Expression mapOnMatrixFirstChild(ExpressionNode::ReductionContext reductionContext); /* 'ExpressionWithoutSymbols' returns an uninitialized expression if it is @@ -251,7 +251,7 @@ public: template static U Epsilon(); template Expression approximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; template U approximateToScalar(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; - template static U ApproximateToScalar(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool symbolicComputation = true); + template static U ApproximateToScalar(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition); template U approximateWithValueForSymbol(const char * symbol, U x, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; /* Expression roots/extrema solver */ Coordinate2D nextMinimum(const char * symbol, double start, double step, double max, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const; @@ -337,7 +337,7 @@ protected: void removeChildrenInPlace(int currentNumberOfChildren) = delete; /* Properties */ - int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const { return node()->getPolynomialCoefficients(context, symbolName, coefficients); } + int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const { return node()->getPolynomialCoefficients(context, symbolName, coefficients, symbolicComputation); } Expression defaultReplaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression expression); /* 'deepReplaceReplaceableSymbols' returns an uninitialized expression if it * is circularly defined. Same convention as for 'ExpressionWithoutSymbols'.*/ diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index 0e311f4b6..d343a8a2d 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -123,6 +123,11 @@ public: * - identifying tangent in cos/sin polynoms ... */ User }; + enum class SymbolicComputation { + ReplaceAllSymbolsWithDefinitionsOrUndefined = 0, + ReplaceAllDefinedSymbolsWithDefinition = 1, + ReplaceDefinedFunctionsWithDefinitions = 2 + }; enum class Sign { Negative = -1, Unknown = 0, @@ -131,7 +136,7 @@ public: class ReductionContext { public: - ReductionContext(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ReductionTarget target, bool symbolicComputation = true) : + ReductionContext(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ReductionTarget target, SymbolicComputation symbolicComputation = SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition) : m_context(context), m_complexFormat(complexFormat), m_angleUnit(angleUnit), @@ -142,13 +147,13 @@ public: Preferences::ComplexFormat complexFormat() const { return m_complexFormat; } Preferences::AngleUnit angleUnit() const { return m_angleUnit; } ReductionTarget target() const { return m_target; } - bool symbolicComputation() const { return m_symbolicComputation; } + SymbolicComputation symbolicComputation() const { return m_symbolicComputation; } private: Context * m_context; Preferences::ComplexFormat m_complexFormat; Preferences::AngleUnit m_angleUnit; ReductionTarget m_target; - bool m_symbolicComputation; + SymbolicComputation m_symbolicComputation; }; virtual Sign sign(Context * context) const { return Sign::Unknown; } @@ -163,7 +168,7 @@ public: /*!*/ virtual Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression); /*!*/ virtual Expression setSign(Sign s, ReductionContext reductionContext); virtual int polynomialDegree(Context * context, const char * symbolName) const; - /*!*/ virtual int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const; + /*!*/ virtual int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const; /*!*/ virtual Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly); typedef bool (*isVariableTest)(const char * c, Poincare::Context * context); virtual int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const; diff --git a/poincare/include/poincare/function.h b/poincare/include/poincare/function.h index 82dc51223..efebf585a 100644 --- a/poincare/include/poincare/function.h +++ b/poincare/include/poincare/function.h @@ -25,7 +25,7 @@ public: Type type() const override { return Type::Function; } Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) override; int polynomialDegree(Context * context, const char * symbolName) const override; - int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const override; + int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const override; int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const override; float characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const override; diff --git a/poincare/include/poincare/multiplication.h b/poincare/include/poincare/multiplication.h index 0d8430888..7fb300738 100644 --- a/poincare/include/poincare/multiplication.h +++ b/poincare/include/poincare/multiplication.h @@ -23,7 +23,7 @@ public: Type type() const override { return Type::Multiplication; } Sign sign(Context * context) const override; int polynomialDegree(Context * context, const char * symbolName) const override; - int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const override; + int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const override; bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override; // Approximation @@ -75,7 +75,7 @@ public: static Multiplication Builder(Expression * children, size_t numberOfChildren) { return TreeHandle::NAryBuilder(children, numberOfChildren); } // Properties - int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const; + int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const; // Approximation template static void computeOnArrays(T * m, T * n, T * result, int mNumberOfColumns, int mNumberOfRows, int nNumberOfColumns); // Simplification diff --git a/poincare/include/poincare/power.h b/poincare/include/poincare/power.h index 06097d962..55861e502 100644 --- a/poincare/include/poincare/power.h +++ b/poincare/include/poincare/power.h @@ -31,7 +31,7 @@ public: bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override; int polynomialDegree(Context * context, const char * symbolName) const override; - int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const override; + int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const override; template static Complex compute(const std::complex c, const std::complex d, Preferences::ComplexFormat complexFormat); diff --git a/poincare/include/poincare/symbol.h b/poincare/include/poincare/symbol.h index 5a4fbc20c..fd64b4e4b 100644 --- a/poincare/include/poincare/symbol.h +++ b/poincare/include/poincare/symbol.h @@ -23,7 +23,7 @@ public: Type type() const override { return Type::Symbol; } Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) override; int polynomialDegree(Context * context, const char * symbolName) const override; - int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const override; + int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const override; int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const override; float characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const override; @@ -68,7 +68,7 @@ public: // Expression Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression); - int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const; + int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const; Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly); private: SymbolNode * node() const { return static_cast(Expression::node()); } diff --git a/poincare/src/addition.cpp b/poincare/src/addition.cpp index ab849187f..6d176c597 100644 --- a/poincare/src/addition.cpp +++ b/poincare/src/addition.cpp @@ -25,8 +25,8 @@ int AdditionNode::polynomialDegree(Context * context, const char * symbolName) c return degree; } -int AdditionNode::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const { - return Addition(this).getPolynomialCoefficients(context, symbolName, coefficients); +int AdditionNode::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const { + return Addition(this).getPolynomialCoefficients(context, symbolName, coefficients, symbolicComputation); } // Layout @@ -59,7 +59,7 @@ const Number Addition::NumeralFactor(const Expression & e) { return Rational::Builder(1); } -int Addition::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const { +int Addition::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const { int deg = polynomialDegree(context, symbolName); if (deg < 0 || deg > Expression::k_maxPolynomialDegree) { return -1; @@ -69,7 +69,7 @@ int Addition::getPolynomialCoefficients(Context * context, const char * symbolNa } Expression intermediateCoefficients[Expression::k_maxNumberOfPolynomialCoefficients]; for (int i = 0; i < numberOfChildren(); i++) { - int d = childAtIndex(i).getPolynomialCoefficients(context, symbolName, intermediateCoefficients); + int d = childAtIndex(i).getPolynomialCoefficients(context, symbolName, intermediateCoefficients, symbolicComputation); assert(d < Expression::k_maxNumberOfPolynomialCoefficients); for (int j = 0; j < d+1; j++) { static_cast(coefficients[j]).addChildAtIndexInPlace(intermediateCoefficients[j], coefficients[j].numberOfChildren(), coefficients[j].numberOfChildren()); @@ -394,8 +394,8 @@ Expression Addition::factorizeOnCommonDenominator(ExpressionNode::ReductionConte /* To simplify the numerator and the denominator, we allow symbolic * computation: all unwanted symbols should have already disappeared by now, - * and if we checked again for symbols we might find "paramter" symbols - * disconnected from the parametered expression, which would be replaed with + * and if we checked again for symbols we might find "parameter" symbols + * disconnected from the parametered expression, which would be replaced with * undef. * Example: int((ℯ^(-x))-x^(0.5), x, 0, 3), when creating the common * denominator for the integrand. */ @@ -404,7 +404,7 @@ Expression Addition::factorizeOnCommonDenominator(ExpressionNode::ReductionConte reductionContext.complexFormat(), reductionContext.angleUnit(), reductionContext.target(), - true); + ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition); // Step 4: Simplify the numerator numerator.shallowReduce(contextWithSymbolicComputation); diff --git a/poincare/src/equal.cpp b/poincare/src/equal.cpp index c7a5dd767..f5f16e686 100644 --- a/poincare/src/equal.cpp +++ b/poincare/src/equal.cpp @@ -50,7 +50,7 @@ Expression Equal::standardEquation(Context * context, Preferences::ComplexFormat * SystemForAnalysis. This enables to expand Newton multinom to be able to * detect polynom correctly ("(x+2)^2" in this form won't be detected * unless expanded). */ - return sub.reduce(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::SystemForAnalysis); + return sub.reduce(ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::SystemForAnalysis)); } Expression Equal::shallowReduce() { diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 924524856..cbfeb9e00 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -196,7 +196,7 @@ bool containsVariables(const Expression e, char * variables, int maxVariableSize return false; } -bool Expression::getLinearCoefficients(char * variables, int maxVariableSize, Expression coefficients[], Expression constant[], Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { +bool Expression::getLinearCoefficients(char * variables, int maxVariableSize, Expression coefficients[], Expression constant[], Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation) const { assert(!recursivelyMatches(IsMatrix, context, true)); // variables is in fact of type char[k_maxNumberOfVariables][maxVariableSize] int index = 0; @@ -211,7 +211,7 @@ bool Expression::getLinearCoefficients(char * variables, int maxVariableSize, Ex index = 0; Expression polynomialCoefficients[k_maxNumberOfPolynomialCoefficients]; while (variables[index*maxVariableSize] != 0) { - int degree = equation.getPolynomialReducedCoefficients(&variables[index*maxVariableSize], polynomialCoefficients, context, complexFormat, angleUnit); + int degree = equation.getPolynomialReducedCoefficients(&variables[index*maxVariableSize], polynomialCoefficients, context, complexFormat, angleUnit, symbolicComputation); switch (degree) { case 0: coefficients[index] = Rational::Builder(0); @@ -232,7 +232,7 @@ bool Expression::getLinearCoefficients(char * variables, int maxVariableSize, Ex equation = polynomialCoefficients[0]; index++; } - constant[0] = Opposite::Builder(equation.clone()).reduce(context, complexFormat, angleUnit); + constant[0] = Opposite::Builder(equation.clone()).reduce(ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::SystemForApproximation, symbolicComputation)); /* The expression can be linear on all coefficients taken one by one but * non-linear (ex: xy = 2). We delete the results and return false if one of * the coefficients contains a variable. */ @@ -444,11 +444,11 @@ int Expression::defaultGetPolynomialCoefficients(Context * context, const char * return -1; } -int Expression::getPolynomialReducedCoefficients(const char * symbolName, Expression coefficients[], Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const { +int Expression::getPolynomialReducedCoefficients(const char * symbolName, Expression coefficients[], Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation) const { // Reset interrupting flag because we use deepReduce - int degree = getPolynomialCoefficients(context, symbolName, coefficients); + int degree = getPolynomialCoefficients(context, symbolName, coefficients, symbolicComputation); for (int i = 0; i <= degree; i++) { - coefficients[i] = coefficients[i].reduce(context, complexFormat, angleUnit); + coefficients[i] = coefficients[i].reduce(ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::SystemForApproximation, symbolicComputation)); } return degree; } @@ -525,8 +525,8 @@ bool Expression::isIdenticalTo(const Expression e) const { } bool Expression::ParsedExpressionsAreEqual(const char * e0, const char * e1, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) { - Expression exp0 = Expression::ParseAndSimplify(e0, context, complexFormat, angleUnit, false); - Expression exp1 = Expression::ParseAndSimplify(e1, context, complexFormat, angleUnit, false); + Expression exp0 = Expression::ParseAndSimplify(e0, context, complexFormat, angleUnit, ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined); + Expression exp1 = Expression::ParseAndSimplify(e1, context, complexFormat, angleUnit, ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined); if (exp0.isUninitialized() || exp1.isUninitialized()) { return false; } @@ -543,12 +543,12 @@ int Expression::serialize(char * buffer, int bufferSize, Preferences::PrintFloat /* Simplification */ -Expression Expression::ParseAndSimplify(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool symbolicSimplification) { +Expression Expression::ParseAndSimplify(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation) { Expression exp = Parse(text, context, false); if (exp.isUninitialized()) { return Undefined::Builder(); } - exp = exp.simplify(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User, symbolicSimplification); + exp = exp.simplify(ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User, symbolicComputation)); /* simplify might have been interrupted, in which case the resulting * expression is uninitialized, so we need to check that. */ if (exp.isUninitialized()) { @@ -557,7 +557,7 @@ Expression Expression::ParseAndSimplify(const char * text, Context * context, Pr return exp; } -void Expression::ParseAndSimplifyAndApproximate(const char * text, Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool symbolicComputation) { +void Expression::ParseAndSimplifyAndApproximate(const char * text, Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation) { assert(simplifiedExpression); Expression exp = Parse(text, context, false); if (exp.isUninitialized()) { @@ -576,12 +576,11 @@ void Expression::ParseAndSimplifyAndApproximate(const char * text, Expression * } } -Expression Expression::simplify(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target, bool symbolicComputation) { +Expression Expression::simplify(ExpressionNode::ReductionContext reductionContext) { sSimplificationHasBeenInterrupted = false; - ExpressionNode::ReductionContext c = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, target, symbolicComputation); - Expression e = deepReduce(c); + Expression e = deepReduce(reductionContext); if (!sSimplificationHasBeenInterrupted) { - e = e.deepBeautify(c); + e = e.deepBeautify(reductionContext); } return sSimplificationHasBeenInterrupted ? Expression() : e; } @@ -647,7 +646,7 @@ void Expression::beautifyAndApproximateScalar(Expression * simplifiedExpression, } } -void Expression::simplifyAndApproximate(Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool symbolicComputation) { +void Expression::simplifyAndApproximate(Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation) { assert(simplifiedExpression); sSimplificationHasBeenInterrupted = false; // Step 1: we reduce the expression @@ -772,9 +771,9 @@ Expression Expression::angleUnitToRadian(Preferences::AngleUnit angleUnit) { return *this; } -Expression Expression::reduce(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target) { +Expression Expression::reduce(ExpressionNode::ReductionContext reductionContext) { sSimplificationHasBeenInterrupted = false; - return deepReduce(ExpressionNode::ReductionContext(context, complexFormat, angleUnit, target, true)); + return deepReduce(reductionContext); } Expression Expression::deepReduce(ExpressionNode::ReductionContext reductionContext) { @@ -824,8 +823,8 @@ U Expression::approximateToScalar(Context * context, Preferences::ComplexFormat } template -U Expression::ApproximateToScalar(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool symbolicSimplification) { - Expression exp = ParseAndSimplify(text, context, complexFormat, angleUnit, symbolicSimplification); +U Expression::ApproximateToScalar(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation) { + Expression exp = ParseAndSimplify(text, context, complexFormat, angleUnit, symbolicComputation); assert(!exp.isUninitialized()); return exp.approximateToScalar(context, complexFormat, angleUnit); } @@ -1147,8 +1146,8 @@ template Expression Expression::approximate(Context * context, Preferenc template float Expression::approximateToScalar(Context * context, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) const; template double Expression::approximateToScalar(Context * context, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) const; -template float Expression::ApproximateToScalar(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool symbolicComputation); -template double Expression::ApproximateToScalar(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool symbolicComputation); +template float Expression::ApproximateToScalar(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation); +template double Expression::ApproximateToScalar(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation); template Evaluation Expression::approximateToEvaluation(Context * context, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) const; template Evaluation Expression::approximateToEvaluation(Context * context, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) const; diff --git a/poincare/src/expression_node.cpp b/poincare/src/expression_node.cpp index 1dc699de6..2fee755c8 100644 --- a/poincare/src/expression_node.cpp +++ b/poincare/src/expression_node.cpp @@ -32,7 +32,7 @@ int ExpressionNode::polynomialDegree(Context * context, const char * symbolName) return 0; } -int ExpressionNode::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const { +int ExpressionNode::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const { return Expression(this).defaultGetPolynomialCoefficients(context, symbolName, coefficients); } diff --git a/poincare/src/function.cpp b/poincare/src/function.cpp index 0090a9c8e..cc2ddab24 100644 --- a/poincare/src/function.cpp +++ b/poincare/src/function.cpp @@ -26,13 +26,13 @@ int FunctionNode::polynomialDegree(Context * context, const char * symbolName) c return e.polynomialDegree(context, symbolName); } -int FunctionNode::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const { +int FunctionNode::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const { Function f(this); Expression e = SymbolAbstract::Expand(f, context, true); if (e.isUninitialized()) { return -1; } - return e.getPolynomialCoefficients(context, symbolName, coefficients); + return e.getPolynomialCoefficients(context, symbolName, coefficients, symbolicComputation); } int FunctionNode::getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const { @@ -120,7 +120,7 @@ Expression Function::shallowReduce(ExpressionNode::ReductionContext reductionCon } Expression result = SymbolAbstract::Expand(*this, reductionContext.context(), true); if (result.isUninitialized()) { - if (reductionContext.symbolicComputation()) { + if (reductionContext.symbolicComputation() != ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined) { return *this; } result = Undefined::Builder(); diff --git a/poincare/src/integer.cpp b/poincare/src/integer.cpp index 1b8485ecf..d442edce8 100644 --- a/poincare/src/integer.cpp +++ b/poincare/src/integer.cpp @@ -699,7 +699,7 @@ Expression Integer::CreateEuclideanDivision(const Integer & num, const Integer & Expression quo = DivisionQuotient::Reduce(num, denom); Expression rem = DivisionRemainder::Reduce(num, denom); Expression e = Equal::Builder(Rational::Builder(num), Addition::Builder(Multiplication::Builder(Rational::Builder(denom), quo), rem)); - ExpressionNode::ReductionContext defaultReductionContext = ExpressionNode::ReductionContext(nullptr, Preferences::ComplexFormat::Real, Preferences::AngleUnit::Radian, ExpressionNode::ReductionTarget::User, false); + ExpressionNode::ReductionContext defaultReductionContext = ExpressionNode::ReductionContext(nullptr, Preferences::ComplexFormat::Real, Preferences::AngleUnit::Radian, ExpressionNode::ReductionTarget::User, ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined); e = e.deepBeautify(defaultReductionContext); return e; } diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 999597b6d..688984f67 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -50,8 +50,8 @@ int MultiplicationNode::polynomialDegree(Context * context, const char * symbolN return degree; } -int MultiplicationNode::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const { - return Multiplication(this).getPolynomialCoefficients(context, symbolName, coefficients); +int MultiplicationNode::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const { + return Multiplication(this).getPolynomialCoefficients(context, symbolName, coefficients, symbolicComputation); } bool MultiplicationNode::childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const { @@ -217,7 +217,7 @@ Expression MultiplicationNode::denominator(ReductionContext reductionContext) co /* Multiplication */ -int Multiplication::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const { +int Multiplication::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const { int deg = polynomialDegree(context, symbolName); if (deg < 0 || deg > Expression::k_maxPolynomialDegree) { return -1; @@ -232,7 +232,7 @@ int Multiplication::getPolynomialCoefficients(Context * context, const char * sy // Let's note result = a(0)+a(1)*X+a(2)*X^2+a(3)*x^3+.. for (int i = 0; i < numberOfChildren(); i++) { // childAtIndex(i) = b(0)+b(1)*X+b(2)*X^2+b(3)*x^3+... - int degI = childAtIndex(i).getPolynomialCoefficients(context, symbolName, intermediateCoefficients); + int degI = childAtIndex(i).getPolynomialCoefficients(context, symbolName, intermediateCoefficients, symbolicComputation); assert(degI <= Expression::k_maxPolynomialDegree); for (int j = deg; j > 0; j--) { // new coefficients[j] = b(0)*a(j)+b(1)*a(j-1)+b(2)*a(j-2)+... diff --git a/poincare/src/power.cpp b/poincare/src/power.cpp index 63170ad25..738d8a31e 100644 --- a/poincare/src/power.cpp +++ b/poincare/src/power.cpp @@ -81,7 +81,7 @@ int PowerNode::polynomialDegree(Context * context, const char * symbolName) cons return -1; } -int PowerNode::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const { +int PowerNode::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const { return Power(this).getPolynomialCoefficients(context, symbolName, coefficients); } diff --git a/poincare/src/symbol.cpp b/poincare/src/symbol.cpp index 6ad1e1fae..e2fe4ea1f 100644 --- a/poincare/src/symbol.cpp +++ b/poincare/src/symbol.cpp @@ -33,8 +33,8 @@ int SymbolNode::polynomialDegree(Context * context, const char * symbolName) con return 0; } -int SymbolNode::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const { - return Symbol(this).getPolynomialCoefficients(context, symbolName, coefficients); +int SymbolNode::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const { + return Symbol(this).getPolynomialCoefficients(context, symbolName, coefficients, symbolicComputation); } int SymbolNode::getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const { @@ -151,6 +151,9 @@ bool Symbol::isRegressionSymbol(const char * c, Poincare::Context * context) { } Expression Symbol::shallowReduce(ExpressionNode::ReductionContext reductionContext) { + if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions) { + return *this; + } { Expression current = *this; Expression p = parent(); @@ -177,7 +180,7 @@ Expression Symbol::shallowReduce(ExpressionNode::ReductionContext reductionConte Expression result = SymbolAbstract::Expand(*this, reductionContext.context(), true); if (result.isUninitialized()) { - if (reductionContext.symbolicComputation()) { + if (reductionContext.symbolicComputation() != ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined) { return *this; } result = Undefined::Builder(); @@ -200,7 +203,7 @@ Expression Symbol::replaceSymbolWithExpression(const SymbolAbstract & symbol, co return *this; } -int Symbol::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const { +int Symbol::getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[], ExpressionNode::SymbolicComputation symbolicComputation) const { if (strcmp(name(), symbolName) == 0) { coefficients[0] = Rational::Builder(0); coefficients[1] = Rational::Builder(1);