[poincare] Factorize Echelon Form classes

Change-Id: I7ec7290a4d94b9bd1224ad4c53be8b4662bd32d5
This commit is contained in:
Hugo Saint-Vignes
2020-07-01 15:42:19 +02:00
committed by Émilie Feral
parent f00c135b69
commit 3bfc0c83d8
18 changed files with 182 additions and 206 deletions

View File

@@ -56,13 +56,13 @@ void MatrixListController::setExpression(Poincare::Expression e) {
}
// 3. Matrix row echelon form
messageIndex = 2;
Expression rowEchelonForm = MatrixRef::Builder(m_expression.clone());
Expression rowEchelonForm = MatrixRowEchelonForm::Builder(m_expression.clone());
m_indexMessageMap[index] = messageIndex++;
m_layouts[index++] = getLayoutFromExpression(rowEchelonForm, context, preferences);
/* 4. Matrix reduced row echelon form
* it can be computed from row echelon form to save computation time.*/
m_indexMessageMap[index] = messageIndex++;
m_layouts[index++] = getLayoutFromExpression(MatrixRref::Builder(rowEchelonForm), context, preferences);
m_layouts[index++] = getLayoutFromExpression(MatrixReducedRowEchelonForm::Builder(rowEchelonForm), context, preferences);
// 5. Matrix trace if square matrix
if (mIsSquared) {
m_indexMessageMap[index] = messageIndex++;

View File

@@ -101,8 +101,9 @@ poincare_src += $(addprefix poincare/src/,\
matrix_inverse.cpp \
matrix_trace.cpp \
matrix_transpose.cpp \
matrix_ref.cpp \
matrix_rref.cpp \
matrix_echelon_form.cpp \
matrix_row_echelon_form.cpp \
matrix_reduced_row_echelon_form.cpp \
multiplication.cpp \
n_ary_expression.cpp \
naperian_logarithm.cpp \

View File

@@ -63,8 +63,9 @@ class Expression : public TreeHandle {
friend class MatrixInverse;
friend class MatrixTrace;
friend class MatrixTranspose;
friend class MatrixRef;
friend class MatrixRref;
friend class MatrixEchelonForm;
friend class MatrixRowEchelonForm;
friend class MatrixReducedRowEchelonForm;
friend class Multiplication;
friend class MultiplicationNode;
friend class NaperianLogarithm;

View File

@@ -103,8 +103,8 @@ public:
MatrixIdentity,
MatrixInverse,
MatrixTranspose,
MatrixRef,
MatrixRref,
MatrixRowEchelonForm,
MatrixReducedRowEchelonForm,
PredictionInterval,
Matrix,
EmptyExpression

View File

@@ -1,24 +1,17 @@
#ifndef POINCARE_MATRIX_REF_H
#define POINCARE_MATRIX_REF_H
#ifndef POINCARE_MATRIX_ECHELON_FORM_H
#define POINCARE_MATRIX_ECHELON_FORM_H
#include <poincare/expression.h>
namespace Poincare {
class MatrixRefNode final : public ExpressionNode {
class MatrixEchelonFormNode : public ExpressionNode {
public:
// TreeNode
size_t size() const override { return sizeof(MatrixRefNode); }
int numberOfChildren() const override;
#if POINCARE_TREE_LOG
void logNodeName(std::ostream & stream) const override {
stream << "MatrixRef";
}
#endif
// Properties
Type type() const override { return Type::MatrixRef; }
virtual bool isFormReduced() const = 0;
static constexpr int sNumberOfChildren = 1;
private:
// Layout
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
@@ -31,16 +24,16 @@ private:
Evaluation<float> approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<float>(context, complexFormat, angleUnit); }
Evaluation<double> approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<double>(context, complexFormat, angleUnit); }
template<typename T> Evaluation<T> templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
// Properties
virtual const char * functionHelperName() const = 0;
};
class MatrixRef final : public Expression {
class MatrixEchelonForm : public Expression {
public:
MatrixRef(const MatrixRefNode * n) : Expression(n) {}
static MatrixRef Builder(Expression child) { return TreeHandle::FixedArityBuilder<MatrixRef, MatrixRefNode>({child}); }
static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("ref", 1, &UntypedBuilderOneChild<MatrixRef>);
MatrixEchelonForm(const MatrixEchelonFormNode * n) : Expression(n) {}
Expression shallowReduce(ExpressionNode::ReductionContext reductionContext);
bool isFormReduced() const { return static_cast<MatrixEchelonFormNode *>(node())->isFormReduced(); }
};
}

View File

@@ -0,0 +1,37 @@
#ifndef POINCARE_MATRIX_REDUCED_ROW_ECHELON_FORM_H
#define POINCARE_MATRIX_REDUCED_ROW_ECHELON_FORM_H
#include <poincare/matrix_echelon_form.h>
namespace Poincare {
class MatrixReducedRowEchelonFormNode final : public MatrixEchelonFormNode {
public:
// TreeNode
size_t size() const override { return sizeof(MatrixReducedRowEchelonFormNode); }
#if POINCARE_TREE_LOG
void logNodeName(std::ostream & stream) const override {
stream << "MatrixReducedRowEchelonForm";
}
#endif
// Properties
Type type() const override { return Type::MatrixReducedRowEchelonForm; }
private:
const char * functionHelperName() const override;
bool isFormReduced() const override { return true; }
};
class MatrixReducedRowEchelonForm final : public MatrixEchelonForm {
public:
MatrixReducedRowEchelonForm(const MatrixReducedRowEchelonFormNode * n) : MatrixEchelonForm(n) {}
static MatrixReducedRowEchelonForm Builder(Expression child) { return TreeHandle::FixedArityBuilder<MatrixReducedRowEchelonForm, MatrixReducedRowEchelonFormNode>({child}); }
static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("rref", MatrixEchelonFormNode::sNumberOfChildren, &UntypedBuilderOneChild<MatrixReducedRowEchelonForm>);
};
}
#endif

View File

@@ -0,0 +1,37 @@
#ifndef POINCARE_MATRIX_ROW_ECHELON_FORM_H
#define POINCARE_MATRIX_ROW_ECHELON_FORM_H
#include <poincare/matrix_echelon_form.h>
namespace Poincare {
class MatrixRowEchelonFormNode final : public MatrixEchelonFormNode {
public:
// TreeNode
size_t size() const override { return sizeof(MatrixRowEchelonFormNode); }
#if POINCARE_TREE_LOG
void logNodeName(std::ostream & stream) const override {
stream << "MatrixRowEchelonForm";
}
#endif
// Properties
Type type() const override { return Type::MatrixRowEchelonForm; }
private:
const char * functionHelperName() const override;
bool isFormReduced() const override { return false; }
};
class MatrixRowEchelonForm final : public MatrixEchelonForm {
public:
MatrixRowEchelonForm(const MatrixRowEchelonFormNode * n) : MatrixEchelonForm(n) {}
static MatrixRowEchelonForm Builder(Expression child) { return TreeHandle::FixedArityBuilder<MatrixRowEchelonForm, MatrixRowEchelonFormNode>({child}); }
static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("ref", MatrixEchelonFormNode::sNumberOfChildren, &UntypedBuilderOneChild<MatrixRowEchelonForm>);
};
}
#endif

View File

@@ -1,48 +0,0 @@
#ifndef POINCARE_MATRIX_RREF_H
#define POINCARE_MATRIX_RREF_H
#include <poincare/expression.h>
namespace Poincare {
class MatrixRrefNode final : public ExpressionNode {
public:
// TreeNode
size_t size() const override { return sizeof(MatrixRrefNode); }
int numberOfChildren() const override;
#if POINCARE_TREE_LOG
void logNodeName(std::ostream & stream) const override {
stream << "MatrixRref";
}
#endif
// Properties
Type type() const override { return Type::MatrixRref; }
private:
// Layout
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
// Simplification
Expression shallowReduce(ReductionContext reductionContext) override;
LayoutShape leftLayoutShape() const override { return LayoutShape::MoreLetters; };
LayoutShape rightLayoutShape() const override { return LayoutShape::BoundaryPunctuation; }
// Evaluation
Evaluation<float> approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<float>(context, complexFormat, angleUnit); }
Evaluation<double> approximate(DoublePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<double>(context, complexFormat, angleUnit); }
template<typename T> Evaluation<T> templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
};
class MatrixRref final : public Expression {
public:
MatrixRref(const MatrixRrefNode * n) : Expression(n) {}
static MatrixRref Builder(Expression child) { return TreeHandle::FixedArityBuilder<MatrixRref, MatrixRrefNode>({child}); }
static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("rref", 1, &UntypedBuilderOneChild<MatrixRref>);
Expression shallowReduce(ExpressionNode::ReductionContext reductionContext);
};
}
#endif

View File

@@ -54,8 +54,8 @@
#include <poincare/matrix_inverse.h>
#include <poincare/matrix_trace.h>
#include <poincare/matrix_transpose.h>
#include <poincare/matrix_ref.h>
#include <poincare/matrix_rref.h>
#include <poincare/matrix_row_echelon_form.h>
#include <poincare/matrix_reduced_row_echelon_form.h>
#include <poincare/multiplication.h>
#include <poincare/naperian_logarithm.h>
#include <poincare/norm_cdf.h>

View File

@@ -186,8 +186,8 @@ bool Expression::IsMatrix(const Expression e, Context * context) {
|| e.type() == ExpressionNode::Type::MatrixInverse
|| e.type() == ExpressionNode::Type::MatrixIdentity
|| e.type() == ExpressionNode::Type::MatrixTranspose
|| e.type() == ExpressionNode::Type::MatrixRef
|| e.type() == ExpressionNode::Type::MatrixRref;
|| e.type() == ExpressionNode::Type::MatrixRowEchelonForm
|| e.type() == ExpressionNode::Type::MatrixReducedRowEchelonForm;
}
bool Expression::IsInfinity(const Expression e, Context * context) {

View File

@@ -0,0 +1,59 @@
#include <poincare/matrix_echelon_form.h>
#include <poincare/matrix_complex.h>
#include <poincare/layout_helper.h>
#include <poincare/matrix.h>
#include <poincare/serialization_helper.h>
namespace Poincare {
int MatrixEchelonFormNode::numberOfChildren() const { return sNumberOfChildren; }
Expression MatrixEchelonFormNode::shallowReduce(ReductionContext reductionContext) {
return MatrixEchelonForm(this).shallowReduce(reductionContext);
}
Layout MatrixEchelonFormNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
return LayoutHelper::Prefix(MatrixEchelonForm(this), floatDisplayMode, numberOfSignificantDigits, functionHelperName());
}
int MatrixEchelonFormNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, functionHelperName());
}
template<typename T>
Evaluation<T> MatrixEchelonFormNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
Evaluation<T> input = childAtIndex(0)->approximate(T(), context, complexFormat, angleUnit);
Evaluation<T> ref;
if (input.type() == EvaluationNode<T>::Type::MatrixComplex) {
ref = static_cast<MatrixComplex<T>&>(input).ref(isFormReduced());
} else {
ref = Complex<T>::Undefined();
}
assert(!ref.isUninitialized());
return ref;
}
Expression MatrixEchelonForm::shallowReduce(ExpressionNode::ReductionContext reductionContext) {
{
Expression e = Expression::defaultShallowReduce();
e = e.defaultHandleUnitsInChildren();
if (e.isUndefined()) {
return e;
}
}
Expression c = childAtIndex(0);
if (c.type() == ExpressionNode::Type::Matrix) {
bool couldComputeRef = false;
Expression result = static_cast<Matrix&>(c).createRef(reductionContext, &couldComputeRef, isFormReduced());
if (couldComputeRef) {
replaceWithInPlace(result);
return result;
}
// The matrix could not be transformed properly
return *this;
}
return replaceWithUndefinedInPlace();
}
}

View File

@@ -0,0 +1,9 @@
#include <poincare/matrix_reduced_row_echelon_form.h>
namespace Poincare {
constexpr Expression::FunctionHelper MatrixReducedRowEchelonForm::s_functionHelper;
const char * MatrixReducedRowEchelonFormNode::functionHelperName() const { return MatrixReducedRowEchelonForm::s_functionHelper.name(); }
}

View File

@@ -1,61 +0,0 @@
#include <poincare/matrix_ref.h>
#include <poincare/matrix_complex.h>
#include <poincare/layout_helper.h>
#include <poincare/matrix.h>
#include <poincare/serialization_helper.h>
namespace Poincare {
constexpr Expression::FunctionHelper MatrixRef::s_functionHelper;
int MatrixRefNode::numberOfChildren() const { return MatrixRef::s_functionHelper.numberOfChildren(); }
Expression MatrixRefNode::shallowReduce(ReductionContext reductionContext) {
return MatrixRef(this).shallowReduce(reductionContext);
}
Layout MatrixRefNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
return LayoutHelper::Prefix(MatrixRef(this), floatDisplayMode, numberOfSignificantDigits, MatrixRef::s_functionHelper.name());
}
int MatrixRefNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, MatrixRef::s_functionHelper.name());
}
template<typename T>
Evaluation<T> MatrixRefNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
Evaluation<T> input = childAtIndex(0)->approximate(T(), context, complexFormat, angleUnit);
Evaluation<T> ref;
if (input.type() == EvaluationNode<T>::Type::MatrixComplex) {
ref = static_cast<MatrixComplex<T>&>(input).ref(false);
} else {
ref = Complex<T>::Undefined();
}
assert(!ref.isUninitialized());
return ref;
}
Expression MatrixRef::shallowReduce(ExpressionNode::ReductionContext reductionContext) {
{
Expression e = Expression::defaultShallowReduce();
e = e.defaultHandleUnitsInChildren();
if (e.isUndefined()) {
return e;
}
}
Expression c = childAtIndex(0);
if (c.type() == ExpressionNode::Type::Matrix) {
bool couldComputeRef = false;
Expression result = static_cast<Matrix&>(c).createRef(reductionContext, &couldComputeRef, false);
if (couldComputeRef) {
replaceWithInPlace(result);
return result;
}
// The matrix could not be transformed properly
return *this;
}
return replaceWithUndefinedInPlace();
}
}

View File

@@ -0,0 +1,9 @@
#include <poincare/matrix_row_echelon_form.h>
namespace Poincare {
constexpr Expression::FunctionHelper MatrixRowEchelonForm::s_functionHelper;
const char * MatrixRowEchelonFormNode::functionHelperName() const { return MatrixRowEchelonForm::s_functionHelper.name(); }
}

View File

@@ -1,61 +0,0 @@
#include <poincare/matrix_rref.h>
#include <poincare/matrix_complex.h>
#include <poincare/layout_helper.h>
#include <poincare/matrix.h>
#include <poincare/serialization_helper.h>
namespace Poincare {
constexpr Expression::FunctionHelper MatrixRref::s_functionHelper;
int MatrixRrefNode::numberOfChildren() const { return MatrixRref::s_functionHelper.numberOfChildren(); }
Expression MatrixRrefNode::shallowReduce(ReductionContext reductionContext) {
return MatrixRref(this).shallowReduce(reductionContext);
}
Layout MatrixRrefNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
return LayoutHelper::Prefix(MatrixRref(this), floatDisplayMode, numberOfSignificantDigits, MatrixRref::s_functionHelper.name());
}
int MatrixRrefNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, MatrixRref::s_functionHelper.name());
}
template<typename T>
Evaluation<T> MatrixRrefNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
Evaluation<T> input = childAtIndex(0)->approximate(T(), context, complexFormat, angleUnit);
Evaluation<T> rref;
if (input.type() == EvaluationNode<T>::Type::MatrixComplex) {
rref = static_cast<MatrixComplex<T>&>(input).ref(true);
} else {
rref = Complex<T>::Undefined();
}
assert(!rref.isUninitialized());
return rref;
}
Expression MatrixRref::shallowReduce(ExpressionNode::ReductionContext reductionContext) {
{
Expression e = Expression::defaultShallowReduce();
e = e.defaultHandleUnitsInChildren();
if (e.isUndefined()) {
return e;
}
}
Expression c = childAtIndex(0);
if (c.type() == ExpressionNode::Type::Matrix) {
bool couldComputeRref = false;
Expression result = static_cast<Matrix&>(c).createRef(reductionContext, &couldComputeRref, true);
if (couldComputeRref) {
replaceWithInPlace(result);
return result;
}
// The matrix could not be transformed properly
return *this;
}
return replaceWithUndefinedInPlace();
}
}

View File

@@ -138,11 +138,11 @@ private:
&Randint::s_functionHelper,
&Random::s_functionHelper,
&RealPart::s_functionHelper,
&MatrixRef::s_functionHelper,
&MatrixRowEchelonForm::s_functionHelper,
&DivisionRemainder::s_functionHelper,
&NthRoot::s_functionHelper,
&Round::s_functionHelper,
&MatrixRref::s_functionHelper,
&MatrixReducedRowEchelonForm::s_functionHelper,
&SignFunction::s_functionHelper,
&Sine::s_functionHelper,
&HyperbolicSine::s_functionHelper,

View File

@@ -336,8 +336,8 @@ template MatrixIdentity TreeHandle::FixedArityBuilder<MatrixIdentity, MatrixIden
template MatrixInverse TreeHandle::FixedArityBuilder<MatrixInverse, MatrixInverseNode>(const Tuple &);
template MatrixTrace TreeHandle::FixedArityBuilder<MatrixTrace, MatrixTraceNode>(const Tuple &);
template MatrixTranspose TreeHandle::FixedArityBuilder<MatrixTranspose, MatrixTransposeNode>(const Tuple &);
template MatrixRef TreeHandle::FixedArityBuilder<MatrixRef, MatrixRefNode>(const Tuple &);
template MatrixRref TreeHandle::FixedArityBuilder<MatrixRref, MatrixRrefNode>(const Tuple &);
template MatrixRowEchelonForm TreeHandle::FixedArityBuilder<MatrixRowEchelonForm, MatrixRowEchelonFormNode>(const Tuple &);
template MatrixReducedRowEchelonForm TreeHandle::FixedArityBuilder<MatrixReducedRowEchelonForm, MatrixReducedRowEchelonFormNode>(const Tuple &);
template Multiplication TreeHandle::NAryBuilder<Multiplication, MultiplicationNode>(const Tuple &);
template NaperianLogarithm TreeHandle::FixedArityBuilder<NaperianLogarithm, NaperianLogarithmNode>(const Tuple &);
template NormCDF TreeHandle::FixedArityBuilder<NormCDF, NormCDFNode>(const Tuple &);

View File

@@ -410,8 +410,8 @@ QUIZ_CASE(poincare_parsing_identifiers) {
assert_parsed_expression_is("tanh(1)", HyperbolicTangent::Builder(BasedInteger::Builder(1)));
assert_parsed_expression_is("trace(1)", MatrixTrace::Builder(BasedInteger::Builder(1)));
assert_parsed_expression_is("transpose(1)", MatrixTranspose::Builder(BasedInteger::Builder(1)));
assert_parsed_expression_is("ref(1)", MatrixRef::Builder(BasedInteger::Builder(1)));
assert_parsed_expression_is("rref(1)", MatrixRref::Builder(BasedInteger::Builder(1)));
assert_parsed_expression_is("ref(1)", MatrixRowEchelonForm::Builder(BasedInteger::Builder(1)));
assert_parsed_expression_is("rref(1)", MatrixReducedRowEchelonForm::Builder(BasedInteger::Builder(1)));
assert_parsed_expression_is("√(1)", SquareRoot::Builder(BasedInteger::Builder(1)));
assert_text_not_parsable("cos(1,2)");
assert_text_not_parsable("log(1,2,3)");