Files
Upsilon/poincare/include/poincare/expression.h
Émilie Feral 2d44374f09 [poincare] Fix bug in TermIsARationalSquareRootOrRational: check that
the only operands of the multiplication are a rational and a square root

Change-Id: I16418363c883798eb7a4056d0fae7d29eb459936
2017-11-20 15:34:10 +01:00

271 lines
8.5 KiB
C++

#ifndef POINCARE_EXPRESSION_H
#define POINCARE_EXPRESSION_H
#include <poincare/expression_layout.h>
extern "C" {
#include <assert.h>
}
namespace Poincare {
class Context;
template<class T> class Complex;
class Rational;
class Expression {
friend class Undefined;
friend class Rational;
friend class Decimal;
friend class Multiplication;
friend class Power;
friend class Addition;
friend class Factorial;
friend class Division;
friend class Store;
friend class Sine;
friend class Cosine;
friend class Tangent;
friend class AbsoluteValue;
friend class ArcCosine;
friend class ArcSine;
friend class ArcTangent;
friend class BinomialCoefficient;
friend class Ceiling;
friend class ComplexArgument;
friend class ConfidenceInterval;
friend class Conjugate;
friend class Derivative;
friend class Determinant;
friend class DivisionQuotient;
friend class DivisionRemainder;
friend class Floor;
friend class FracPart;
friend class GreatCommonDivisor;
friend class HyperbolicArcCosine;
friend class HyperbolicArcSine;
friend class HyperbolicArcTangent;
friend class HyperbolicCosine;
friend class HyperbolicSine;
friend class HyperbolicTangent;
friend class ImaginaryPart;
friend class Integral;
friend class LeastCommonMultiple;
friend class Logarithm;
friend class MatrixDimension;
friend class MatrixInverse;
friend class MatrixTrace;
friend class MatrixTranspose;
friend class NaperianLogarithm;
friend class NthRoot;
friend class Opposite;
friend class Parenthesis;
friend class PermuteCoefficient;
friend class PredictionInterval;
friend class Product;
friend class RealPart;
friend class Round;
friend class SquareRoot;
friend class Subtraction;
friend class Sum;
friend class Symbol;
friend class Matrix;
friend class SimplificationRoot;
friend class Sequence;
friend class Trigonometry;
friend class EvaluationEngine;
friend class SimplificationEngine;
public:
enum class Type : uint8_t {
Undefined = 0,
Rational = 1,
Decimal,
Multiplication,
Power,
Addition,
Factorial,
Division,
Store,
Sine,
Cosine,
Tangent,
AbsoluteValue,
ArcCosine,
ArcSine,
ArcTangent,
BinomialCoefficient,
Ceiling,
ComplexArgument,
Conjugate,
Derivative,
Determinant,
DivisionQuotient,
DivisionRemainder,
Floor,
FracPart,
GreatCommonDivisor,
HyperbolicArcCosine,
HyperbolicArcSine,
HyperbolicArcTangent,
HyperbolicCosine,
HyperbolicSine,
HyperbolicTangent,
ImaginaryPart,
Integral,
LeastCommonMultiple,
Logarithm,
MatrixTrace,
NaperianLogarithm,
NthRoot,
Opposite,
Parenthesis,
PermuteCoefficient,
Product,
RealPart,
Round,
SquareRoot,
Subtraction,
Sum,
Symbol,
Complex,
Matrix,
ConfidenceInterval,
MatrixDimension,
MatrixInverse,
MatrixTranspose,
PredictionInterval,
SimplificationRoot,
};
enum class FloatDisplayMode {
Decimal = 0,
Scientific = 1,
Default = 2
};
enum class ComplexFormat {
Cartesian = 0,
Polar = 1,
Default = 2
};
enum class AngleUnit {
Degree = 0,
Radian = 1,
Default = 2
};
/* Constructor & Destructor */
static Expression * parse(char const * string);
virtual ~Expression() = default;
virtual Expression * clone() const = 0;
/* Poor man's RTTI */
virtual Type type() const = 0;
/* Circuit breaker */
typedef bool (*CircuitBreaker)();
static void setCircuitBreaker(CircuitBreaker cb);
static bool shouldStopProcessing();
/* Hierarchy */
virtual const Expression * operand(int i) const = 0;
Expression * editableOperand(int i) { return const_cast<Expression *>(operand(i)); }
virtual int numberOfOperands() const = 0;
Expression * parent() const { return m_parent; }
void setParent(Expression * parent) { m_parent = parent; }
bool hasAncestor(const Expression * e) const;
virtual void replaceOperand(const Expression * oldOperand, Expression * newOperand, bool deleteOldOperand = true) = 0;
Expression * replaceWith(Expression * newOperand, bool deleteAfterReplace = true);
virtual void swapOperands(int i, int j) = 0;
/* Properties */
enum class Sign {
Negative = -1,
Unknown = 0,
Positive = 1
};
virtual Sign sign() const { return Sign::Unknown; }
typedef bool (*ExpressionTest)(const Expression * e);
bool recursivelyMatches(ExpressionTest test) const;
static bool IsMatrix(const Expression * e);
/* 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 {
/* We use the simplification order only because it is a already-coded total
* order on expresssions. */
return SimplificationOrder(this, e) == 0;
}
/* Layout Engine */
ExpressionLayout * createLayout(FloatDisplayMode floatDisplayMode = FloatDisplayMode::Default, ComplexFormat complexFormat = ComplexFormat::Default) const; // Returned object must be deleted
virtual int writeTextInBuffer(char * buffer, int bufferSize) const = 0;
/* Simplification */
static void Simplify(Expression ** expressionAddress, Context & context, AngleUnit angleUnit = AngleUnit::Default);
/* Evaluation Engine
* The function evaluate creates a new expression and thus mallocs memory.
* Do not forget to delete the new expression to avoid leaking. */
template<typename T> Expression * evaluate(Context& context, AngleUnit angleUnit = AngleUnit::Default) const;
template<typename T> T approximate(Context& context, AngleUnit angleUnit = AngleUnit::Default) const;
template<typename T> static T approximate(const char * text, Context& context, AngleUnit angleUnit = AngleUnit::Default);
protected:
/* Constructor */
Expression() : m_parent(nullptr) {}
/* Evaluation Engine */
typedef float SinglePrecision;
typedef double DoublePrecision;
template<typename T> static T epsilon();
constexpr static int k_maxNumberOfSteps = 10000;
/* Simplification */
/* SimplificationOrder returns:
* 1 if e1 > e2
* -1 if e1 < e2
* 0 if e1 == e
* Following the order described in Computer Algebra and Symbolic Computation,
* Joel S. Cohen (section 3.1). The order groups like terms together to avoid
* quadratic complexity when factorizing addition or multiplication. For
* example, it groups terms with same bases together (ie Pi, Pi^3) and with
* same non-rational factors together (ie Pi, 2*Pi). */
static int SimplificationOrder(const Expression * e1, const Expression * e2);
private:
/* Properties */
virtual Expression * setSign(Sign s, Context & context, AngleUnit angleUnit) { assert(false); return nullptr; }
/* Comparison */
/* In the simplification order, most expressions are compared by only
* comparing their types. However hierarchical expressions of same type would
* compare their operands and thus need to reimplement
* simplificationOrderSameType. Besides, operations that can be simplified
* (ie +, *, ^, !) have specific rules to group like terms together and thus
* reimplement simplificationOrderGreaterType. */
virtual int simplificationOrderGreaterType(const Expression * e) const { return -1; }
//TODO: What should be the implementation for complex?
virtual int simplificationOrderSameType(const Expression * e) const { return 0; }
/* Layout Engine */
virtual ExpressionLayout * privateCreateLayout(FloatDisplayMode 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
virtual Expression * shallowReduce(Context & context, AngleUnit angleUnit);
virtual Expression * shallowBeautify(Context & context, AngleUnit angleUnit) { return this; };
// Private methods used in simplification process
virtual Expression * cloneDenominator(Context & context, AngleUnit angleUnit) const {
return nullptr;
}
/* Evaluation Engine */
virtual Expression * privateEvaluate(SinglePrecision p, Context& context, AngleUnit angleUnit) const = 0;
virtual Expression * privateEvaluate(DoublePrecision p, Context& context, AngleUnit angleUnit) const = 0;
Expression * m_parent;
};
}
#endif