mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
489 lines
27 KiB
C++
489 lines
27 KiB
C++
#ifndef POINCARE_EXPRESSION_REFERENCE_H
|
|
#define POINCARE_EXPRESSION_REFERENCE_H
|
|
|
|
#include <poincare/coordinate_2D.h>
|
|
#include <poincare/tree_handle.h>
|
|
#include <poincare/preferences.h>
|
|
#include <poincare/print_float.h>
|
|
#include <poincare/expression_node.h>
|
|
#include <poincare/complex.h>
|
|
#include <poincare/solver.h>
|
|
#include <ion/storage.h>
|
|
#include <utility>
|
|
|
|
namespace Poincare {
|
|
|
|
class Context;
|
|
class SymbolAbstract;
|
|
class Symbol;
|
|
|
|
class Expression : public TreeHandle {
|
|
friend class AbsoluteValue;
|
|
friend class Addition;
|
|
friend class And;
|
|
friend class ArcCosine;
|
|
friend class ArcSine;
|
|
friend class ArcTangent;
|
|
friend class Arithmetic;
|
|
friend class BasedInteger;
|
|
friend class BinaryOperation;
|
|
friend class BinomialCoefficient;
|
|
friend class BinomialDistributionFunction;
|
|
friend class BitClear;
|
|
friend class BitFlip;
|
|
friend class BitGet;
|
|
friend class BitsClear;
|
|
friend class BitsClearExplicit;
|
|
friend class BitSet;
|
|
friend class Ceiling;
|
|
friend class CeilingLog2;
|
|
friend class CommonLogarithm;
|
|
template<typename T>
|
|
friend class ComplexNode;
|
|
friend class ComplexArgument;
|
|
friend class ComplexCartesian;
|
|
friend class ComplexHelper;
|
|
friend class ConfidenceInterval;
|
|
friend class Conjugate;
|
|
friend class Cosine;
|
|
friend class Decimal;
|
|
friend class Derivative;
|
|
friend class Determinant;
|
|
friend class Division;
|
|
friend class DivisionQuotient;
|
|
friend class DivisionRemainder;
|
|
friend class Equal;
|
|
friend class Factor;
|
|
friend class Factorial;
|
|
friend class Floor;
|
|
friend class FracPart;
|
|
friend class Function;
|
|
friend class GlobalContext;
|
|
friend class GreatCommonDivisor;
|
|
friend class HyperbolicTrigonometricFunction;
|
|
friend class ImaginaryPart;
|
|
friend class Integer;
|
|
friend class Integral;
|
|
friend class InvNorm;
|
|
friend class LeastCommonMultiple;
|
|
friend class Logarithm;
|
|
friend class Matrix;
|
|
friend class MatrixDimension;
|
|
friend class MatrixIdentity;
|
|
friend class MatrixInverse;
|
|
friend class MatrixTrace;
|
|
friend class MatrixTranspose;
|
|
friend class MatrixEchelonForm;
|
|
friend class MatrixRowEchelonForm;
|
|
friend class MatrixReducedRowEchelonForm;
|
|
friend class Multiplication;
|
|
friend class MultiplicationNode;
|
|
friend class NaperianLogarithm;
|
|
friend class NormalDistributionFunction;
|
|
friend class NormCDF;
|
|
friend class NormCDF2;
|
|
friend class NormPDF;
|
|
friend class Not;
|
|
friend class NotExplicit;
|
|
friend class NthRoot;
|
|
friend class Number;
|
|
friend class Opposite;
|
|
friend class Or;
|
|
friend class ParameteredExpression;
|
|
friend class Parenthesis;
|
|
friend class PermuteCoefficient;
|
|
friend class Power;
|
|
friend class PowerNode;
|
|
friend class PredictionInterval;
|
|
friend class Product;
|
|
friend class Randint;
|
|
friend class RealPart;
|
|
friend class RotateLeft;
|
|
friend class RotateLeftExplicit;
|
|
friend class RotateRight;
|
|
friend class RotateRightExplicit;
|
|
friend class Round;
|
|
friend class Sequence;
|
|
friend class SequenceNode;
|
|
friend class ShiftArithmeticRight;
|
|
friend class ShiftArithmeticRightExplicit;
|
|
friend class ShiftLogicLeft;
|
|
friend class ShiftLogicRight;
|
|
friend class SignFunction;
|
|
friend class Sine;
|
|
friend class SquareRoot;
|
|
friend class SquareRootNode;
|
|
friend class Store;
|
|
friend class Subtraction;
|
|
friend class SubtractionNode;
|
|
friend class Sum;
|
|
friend class SumAndProduct;
|
|
friend class SumAndProductNode;
|
|
friend class Symbol;
|
|
friend class SymbolAbstractNode;
|
|
friend class Tangent;
|
|
friend class Trigonometry;
|
|
friend class TrigonometryCheatTable;
|
|
friend class TwosComplement;
|
|
friend class Unit;
|
|
friend class UnitConvert;
|
|
friend class VectorCross;
|
|
friend class VectorDot;
|
|
friend class VectorNorm;
|
|
friend class Xor;
|
|
|
|
friend class AdditionNode;
|
|
friend class DerivativeNode;
|
|
friend class EqualNode;
|
|
template<typename T>
|
|
friend class ExceptionExpressionNode;
|
|
friend class ExpressionNode;
|
|
friend class FunctionNode;
|
|
friend class IntegralNode;
|
|
template<int T>
|
|
friend class BinaryOperationNode;
|
|
template<int T>
|
|
friend class LogarithmNode;
|
|
friend class MatrixNode;
|
|
friend class NaperianLogarithmNode;
|
|
friend class NAryExpressionNode;
|
|
friend class NAryInfixExpressionNode;
|
|
friend class StoreNode;
|
|
friend class SymbolNode;
|
|
friend class UnitNode;
|
|
|
|
public:
|
|
static bool IsExpression() { return true; }
|
|
|
|
/* Constructor & Destructor */
|
|
Expression() : TreeHandle() {}
|
|
Expression clone() const;
|
|
static Expression Parse(char const * string, Context * context, bool addMissingParenthesis = true);
|
|
static Expression ExpressionFromAddress(const void * address, size_t size, const void * record=nullptr);
|
|
|
|
/* Circuit breaker */
|
|
typedef bool (*CircuitBreaker)();
|
|
static void SetCircuitBreaker(CircuitBreaker cb);
|
|
static bool ShouldStopProcessing();
|
|
static void SetInterruption(bool interrupt);
|
|
|
|
/* Hierarchy */
|
|
Expression childAtIndex(int i) const;
|
|
void setChildrenInPlace(Expression other) { node()->setChildrenInPlace(other); }
|
|
|
|
/* Properties */
|
|
ExpressionNode::Type type() const { return node()->type(); }
|
|
bool isOfType(ExpressionNode::Type * types, int length) const { return node()->isOfType(types, length); }
|
|
ExpressionNode::Sign sign(Context * context) const { return node()->sign(context); }
|
|
ExpressionNode::NullStatus nullStatus(Context * context) const { return node()->nullStatus(context); }
|
|
ExpressionNode::IntegerStatus integerStatus(Context * context) const { return node()->integerStatus(context); }
|
|
bool isStrictly(ExpressionNode::Sign s, Context * context) const { return s == node()->sign(context) && node()->nullStatus(context) == ExpressionNode::NullStatus::NonNull; }
|
|
bool isUndefined() const { return node()->type() == ExpressionNode::Type::Undefined || node()->type() == ExpressionNode::Type::Unreal; }
|
|
bool isNumber() const { return node()->isNumber(); }
|
|
bool isRationalOne() const;
|
|
bool isRandom() const { return node()->isRandom(); }
|
|
bool isParameteredExpression() const { return node()->isParameteredExpression(); }
|
|
bool isDefinedCosineOrSine(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
|
|
bool isBasedIntegerCappedBy(const char * integerString) const;
|
|
bool isDivisionOfIntegers() const;
|
|
bool hasDefinedComplexApproximation(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
|
|
typedef bool (*ExpressionTest)(const Expression e, Context * context);
|
|
bool recursivelyMatches(ExpressionTest test, Context * context, ExpressionNode::SymbolicComputation replaceSymbols = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition) const;
|
|
typedef bool (*ExpressionTypeTest)(const Expression e, const void * context);
|
|
bool hasExpression(ExpressionTypeTest test, const void * context) const;
|
|
// WARNING: this method must be called on reduced (sorted) expressions
|
|
bool deepIsMatrix(Context * context) const;
|
|
// Set of ExpressionTest that can be used with recursivelyMatches
|
|
static bool IsNAry(const Expression e, Context * context);
|
|
static bool IsApproximate(const Expression e, Context * context);
|
|
static bool IsRandom(const Expression e, Context * context);
|
|
static bool IsMatrix(const Expression e, Context * context);
|
|
static bool IsInfinity(const Expression e, Context * context);
|
|
/* polynomialDegree returns:
|
|
* - (-1) if the expression is not a polynome
|
|
* - the degree of the polynome otherwise */
|
|
int polynomialDegree(Context * context, const char * symbolName) const { return this->node()->polynomialDegree(context, symbolName); }
|
|
/* getVariables fills the matrix variables with the symbols in the expression
|
|
* that pass the test isVariable. It returns the number of entries filled in
|
|
* variables. For instance, getVariables of 'x+y+2*w/cos(4)' would result in
|
|
* variables = {"x", "y", "w"} and would return 3. If the final number of
|
|
* variables would overflow the maxNumberOfVariables, getVariables return -1.
|
|
* If one of the variable lengths overflows maxVariableLength, getVariables
|
|
* returns -2. */
|
|
static constexpr int k_maxNumberOfVariables = 6;
|
|
int getVariables(Context * context, ExpressionNode::isVariableTest isVariable, char * variables, int maxVariableLength, int nextVariableIndex = 0) const { return node()->getVariables(context, isVariable, variables, maxVariableLength, nextVariableIndex); }
|
|
/* getLinearCoefficients return false if the expression is not linear with
|
|
* 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, Preferences::UnitFormat unitFormat, 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, Preferences::UnitFormat unitFormat, ExpressionNode::SymbolicComputation symbolicComputation) const;
|
|
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) { return node()->replaceSymbolWithExpression(symbol, expression); }
|
|
|
|
/* Units */
|
|
Expression removeUnit(Expression * unit) { return node()->removeUnit(unit); }
|
|
bool hasUnit() const;
|
|
|
|
/* Complex */
|
|
static bool EncounteredComplex();
|
|
static void SetEncounteredComplex(bool encounterComplex);
|
|
static Preferences::ComplexFormat UpdatedComplexFormatWithTextInput(Preferences::ComplexFormat complexFormat, const char * textInput);
|
|
static Preferences::ComplexFormat UpdatedComplexFormatWithExpressionInput(Preferences::ComplexFormat complexFormat, const Expression & e, Context * context);
|
|
// WARNING: this methods must be called on reduced expressions
|
|
bool isReal(Context * context) const;
|
|
|
|
/* Comparison */
|
|
/* isIdenticalTo is the "easy" equality, it returns true if both trees have
|
|
* same structures and all their nodes have same types and values (ie,
|
|
* sqrt(pi^2) is NOT identical to pi). */
|
|
bool isIdenticalTo(const Expression e) const;
|
|
/* isIdenticalToWithoutParentheses behaves as isIdenticalTo, but without
|
|
* taking into account parentheses: e^(0) is identical to e^0. */
|
|
bool isIdenticalToWithoutParentheses(const Expression e) const;
|
|
static bool ParsedExpressionsAreEqual(const char * e0, const char * e1, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, Preferences::UnitFormat unitFormat);
|
|
|
|
/* Layout Helper */
|
|
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const;
|
|
/* TODO:
|
|
* - change signature to
|
|
* size_t serialize(char * buffer, size_t bufferSize...)
|
|
* - Use same convention as strlcpy: return size of the source even if the bufferSize was too small.*/
|
|
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode = Preferences::PrintFloatMode::Decimal, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const;
|
|
|
|
/* Simplification */
|
|
/* Simplification routines are divided in 2 groups:
|
|
* - ParseAndSimplify & simplify methods are used before approximating the
|
|
* expression. We simplify beforehand to avoid precision error but the
|
|
* simplified expression is never displayed. The ReductionTarget is
|
|
* therefore the System for these methods.
|
|
* - ParseAndSimplifyAndApproximate & simplifyAndApproximate methods are used
|
|
* to simplify and approximate the expression for the User. They take into
|
|
* 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, Preferences::UnitFormat unitFormat, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, ExpressionNode::UnitConversion unitConversion = ExpressionNode::UnitConversion::Default);
|
|
Expression simplify(ExpressionNode::ReductionContext reductionContext);
|
|
|
|
static void ParseAndSimplifyAndApproximate(const char * text, Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, Preferences::UnitFormat unitFormat, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, ExpressionNode::UnitConversion unitConversion = ExpressionNode::UnitConversion::Default);
|
|
void simplifyAndApproximate(Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, Preferences::UnitFormat unitFormat, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, ExpressionNode::UnitConversion unitConversion = ExpressionNode::UnitConversion::Default);
|
|
Expression reduce(ExpressionNode::ReductionContext context);
|
|
Expression reduceAndRemoveUnit(ExpressionNode::ReductionContext context, Expression * Unit);
|
|
|
|
Expression mapOnMatrixFirstChild(ExpressionNode::ReductionContext reductionContext);
|
|
/* 'ExpressionWithoutSymbols' returns an uninitialized expression if it is
|
|
* circularly defined. Same convention as for 'deepReplaceReplaceableSymbols'.*/
|
|
static Expression ExpressionWithoutSymbols(Expression expressionWithSymbols, Context * context, bool replaceFunctionsOnly = false);
|
|
|
|
Expression radianToAngleUnit(Preferences::AngleUnit angleUnit);
|
|
Expression angleUnitToRadian(Preferences::AngleUnit angleUnit);
|
|
|
|
/* Approximation Helper */
|
|
// These methods reset the sApproximationEncounteredComplex flag. They should not be use to implement node approximation
|
|
template<typename U> static U Epsilon();
|
|
template<typename U> Expression approximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool withinReduce = false) const;
|
|
template<typename U> U approximateToScalar(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool withinReduce = false) const;
|
|
template<typename U> static U ApproximateToScalar(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, Preferences::UnitFormat unitFormat, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition);
|
|
template<typename U> U approximateWithValueForSymbol(const char * symbol, U x, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
|
|
/* Expression roots/extrema solver */
|
|
Coordinate2D<double> nextMinimum(const char * symbol, double start, double step, double max, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
|
|
Coordinate2D<double> nextMaximum(const char * symbol, double start, double step, double max, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
|
|
double nextRoot(const char * symbol, double start, double step, double max, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
|
|
Coordinate2D<double> nextIntersection(const char * symbol, double start, double step, double max, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression) const;
|
|
|
|
/* This class is meant to contain data about named functions (e.g. sin, tan...)
|
|
* in one place: their name, their number of children and a pointer to a builder.
|
|
* It is used in particular by the parser. */
|
|
class FunctionHelper {
|
|
public:
|
|
constexpr FunctionHelper(const char * name, const int numberOfChildren, Expression (* const builder)(Expression)) :
|
|
m_name(name),
|
|
m_numberOfChildren(numberOfChildren),
|
|
m_untypedBuilder(builder) {}
|
|
const char * name() const { return m_name; }
|
|
int numberOfChildren() const { return m_numberOfChildren; }
|
|
Expression build(Expression children) const { return (*m_untypedBuilder)(children); }
|
|
private:
|
|
const char * m_name;
|
|
const int m_numberOfChildren;
|
|
Expression (* const m_untypedBuilder)(Expression children);
|
|
};
|
|
|
|
static void Tidy() { sSymbolReplacementsCountLock = false; }
|
|
|
|
/* Tuple */
|
|
typedef std::initializer_list<Expression> Tuple;
|
|
|
|
protected:
|
|
static bool SimplificationHasBeenInterrupted();
|
|
Expression(const ExpressionNode * n) : TreeHandle(n) {}
|
|
Expression(int nodeIdentifier) : TreeHandle(nodeIdentifier) {}
|
|
template<typename U>
|
|
static Expression UntypedBuilderOneChild(Expression children) {
|
|
assert(children.type() == ExpressionNode::Type::Matrix);
|
|
return U::Builder(children.childAtIndex(0));
|
|
}
|
|
template<typename U>
|
|
static Expression UntypedBuilderTwoChildren(Expression children) {
|
|
assert(children.type() == ExpressionNode::Type::Matrix);
|
|
return U::Builder(children.childAtIndex(0), children.childAtIndex(1));
|
|
}
|
|
template<typename U>
|
|
static Expression UntypedBuilderThreeChildren(Expression children) {
|
|
assert(children.type() == ExpressionNode::Type::Matrix);
|
|
return U::Builder(children.childAtIndex(0), children.childAtIndex(1), children.childAtIndex(2));
|
|
}
|
|
template<typename U>
|
|
static Expression UntypedBuilderFourChildren(Expression children) {
|
|
assert(children.type() == ExpressionNode::Type::Matrix);
|
|
return U::Builder(children.childAtIndex(0), children.childAtIndex(1), children.childAtIndex(2), children.childAtIndex(3));
|
|
}
|
|
template<typename U>
|
|
static Expression UntypedBuilderMultipleChildren(Expression children) {
|
|
// Only with Expression classes implementing addChildAtIndexInPlace
|
|
assert(children.type() == ExpressionNode::Type::Matrix);
|
|
int childrenNumber = children.numberOfChildren();
|
|
assert(childrenNumber > 0);
|
|
U expression = U::Builder({children.childAtIndex(0)});
|
|
for (int i = 1; i < childrenNumber; ++i) {
|
|
expression.addChildAtIndexInPlace(children.childAtIndex(i), i, i);
|
|
}
|
|
return std::move(expression);
|
|
}
|
|
|
|
template<class T> T convert() const {
|
|
/* This function allows to convert Expression to derived Expressions.
|
|
* The asserts ensure that the Expression can only be casted to another
|
|
* Expression, but this does not prevent Expression types mismatches (cast
|
|
* Float to Symbol for instance).
|
|
*
|
|
* We could have overriden the operator T(). However, even with the
|
|
* 'explicit' keyword (which prevents implicit casts), direct initialization
|
|
* are enable which can lead to weird code:
|
|
* ie, you can write: 'Rational a(2); AbsoluteValue b(a);'
|
|
* */
|
|
|
|
assert(T::IsExpression());
|
|
static_assert(sizeof(T) == sizeof(Expression), "Size mismatch");
|
|
return *reinterpret_cast<T *>(const_cast<Expression *>(this));
|
|
}
|
|
|
|
static_assert(sizeof(TreeHandle::Tuple) == sizeof(Tuple), "Size mismatch");
|
|
static const TreeHandle::Tuple & convert(const Tuple & l) {
|
|
assert(sizeof(TreeHandle) == sizeof(Expression));
|
|
return reinterpret_cast<const TreeHandle::Tuple &>(l);
|
|
}
|
|
|
|
/* Reference */
|
|
ExpressionNode * node() const {
|
|
assert(identifier() != TreeNode::NoNodeIdentifier || !TreeHandle::node()->isGhost());
|
|
return static_cast<ExpressionNode *>(TreeHandle::node());
|
|
}
|
|
|
|
/* Hierarchy */
|
|
Expression parent() const; // TODO try to inline
|
|
Expression replaceWithUndefinedInPlace();
|
|
void defaultSetChildrenInPlace(Expression other);
|
|
void addChildAtIndexInPlace(TreeHandle t, int index, int currentNumberOfChildren) = delete;
|
|
void removeChildAtIndexInPlace(int i) = delete;
|
|
void removeChildInPlace(TreeHandle t, int childNumberOfChildren) = delete;
|
|
void removeChildrenInPlace(int currentNumberOfChildren) = delete;
|
|
|
|
/* Properties */
|
|
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'.*/
|
|
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) { return node()->deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly, parameteredAncestorsCount); }
|
|
Expression defaultReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount);
|
|
|
|
/* Simplification */
|
|
void beautifyAndApproximateScalar(Expression * simplifiedExpression, Expression * approximateExpression, ExpressionNode::ReductionContext userReductionContext, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit);
|
|
/* makePositiveAnyNegativeNumeralFactor looks for:
|
|
* - a negative numeral
|
|
* - a multiplication who has one numeral child whose is negative
|
|
* and turns the negative factor into a positive one.
|
|
* The given Expression should already be reduced and the return Expression
|
|
* is reduced (only a numeral factor was potentially made positive, and if it
|
|
* was -1, it was removed from the multiplication).
|
|
* Warning: this must be called on reduced expressions
|
|
*/
|
|
Expression makePositiveAnyNegativeNumeralFactor(ExpressionNode::ReductionContext reductionContext);
|
|
Expression denominator(ExpressionNode::ReductionContext reductionContext) const { return node()->denominator(reductionContext); }
|
|
Expression shallowReduce(ExpressionNode::ReductionContext reductionContext) { return node()->shallowReduce(reductionContext); }
|
|
Expression shallowBeautify(ExpressionNode::ReductionContext * reductionContext) { return node()->shallowBeautify(reductionContext); }
|
|
Expression deepBeautify(ExpressionNode::ReductionContext reductionContext);
|
|
// WARNING: this must be called on reduced expressions
|
|
Expression setSign(ExpressionNode::Sign s, ExpressionNode::ReductionContext reductionContext);
|
|
|
|
/* Derivation */
|
|
/* This method is used for the reduction of Derivative expressions.
|
|
* It returns whether the instance is differentiable, and differentiates it if
|
|
* able. */
|
|
bool derivate(ExpressionNode::ReductionContext reductionContext, Expression symbol, Expression symbolValue) { return node()->derivate(reductionContext, symbol, symbolValue); }
|
|
Expression unaryFunctionDifferential(ExpressionNode::ReductionContext reductionContext) { return node()->unaryFunctionDifferential(reductionContext); }
|
|
|
|
private:
|
|
static constexpr int k_maxSymbolReplacementsCount = 10;
|
|
static bool sSymbolReplacementsCountLock;
|
|
|
|
/* Add missing parenthesis will add parentheses that ease the reading of the
|
|
* expression or that are required by math rules. For example:
|
|
* 2+-1 --> 2+(-1)
|
|
* *(+(2,1),3) --> (2+1)*3
|
|
*/
|
|
Expression addMissingParentheses();
|
|
void shallowAddMissingParenthesis();
|
|
|
|
/* Simplification */
|
|
/* The largest integer such that all smaller integers can be stored without
|
|
* any precision loss in IEEE754 double representation is 2E53 as the
|
|
* mantissa is stored on 53 bits (2E308 can be stored exactly in IEEE754
|
|
* representation but some smaller integers can't - like 2E308-1). */
|
|
static constexpr double k_largestExactIEEE754Integer = 9007199254740992.0;
|
|
Expression deepReduce(ExpressionNode::ReductionContext reductionContext);
|
|
void deepReduceChildren(ExpressionNode::ReductionContext reductionContext) {
|
|
return node()->deepReduceChildren(reductionContext);
|
|
}
|
|
void defaultDeepReduceChildren(ExpressionNode::ReductionContext reductionContext);
|
|
Expression defaultShallowReduce();
|
|
Expression defaultHandleUnitsInChildren(); // Children must be reduced
|
|
Expression shallowReduceUsingApproximation(ExpressionNode::ReductionContext reductionContext);
|
|
Expression defaultShallowBeautify() { return *this; }
|
|
void deepBeautifyChildren(ExpressionNode::ReductionContext reductionContext) {
|
|
node()->deepBeautifyChildren(reductionContext);
|
|
}
|
|
void defaultDeepBeautifyChildren(ExpressionNode::ReductionContext reductionContext);
|
|
bool defaultDidDerivate() { return false; }
|
|
Expression defaultUnaryFunctionDifferential() { return *this; }
|
|
|
|
/* Approximation */
|
|
template<typename U> Evaluation<U> approximateToEvaluation(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool withinReduce = false) const;
|
|
|
|
/* Properties */
|
|
int defaultGetPolynomialCoefficients(Context * context, const char * symbol, Expression expression[]) const;
|
|
|
|
/* Builder */
|
|
static bool IsZero(const Expression e);
|
|
static bool IsOne(const Expression e);
|
|
static bool IsMinusOne(const Expression e);
|
|
static Expression CreateComplexExpression(Expression ra, Expression tb, Preferences::ComplexFormat complexFormat, bool undefined, bool isZeroRa, bool isOneRa, bool isZeroTb, bool isOneTb, bool isNegativeRa, bool isNegativeTb);
|
|
|
|
/* Expression roots/extrema solver*/
|
|
constexpr static double k_solverPrecision = 1.0E-5;
|
|
constexpr static double k_maxFloat = 1e100;
|
|
Coordinate2D<double> nextMinimumOfExpression(const char * symbol, double start, double step, double max, Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression = Expression(), bool lookForRootMinimum = false) const;
|
|
void bracketMinimum(const char * symbol, double start, double step, double max, double result[3], Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression = Expression()) const;
|
|
double nextIntersectionWithExpression(const char * symbol, double start, double step, double max, Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression) const;
|
|
void bracketRoot(const char * symbol, double start, double step, double max, double result[2], Solver::ValueAtAbscissa evaluation, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, const Expression expression) const;
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|