[poincare] Determinant::shallowReduce computes for dimension <= 3

This commit is contained in:
Léa Saviot
2019-07-04 15:07:47 +02:00
committed by Émilie Feral
parent d0a851a77b
commit de8b124808
4 changed files with 67 additions and 9 deletions

View File

@@ -39,7 +39,7 @@ public:
static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("det", 1, &UntypedBuilderOneChild<Determinant>);
Expression shallowReduce(Context * context);
Expression shallowReduce(ExpressionNode::ReductionContext reductionContext);
};
}

View File

@@ -70,6 +70,7 @@ public:
static Multiplication Builder(Expression e1) { return Multiplication::Builder(&e1, 1); }
static Multiplication Builder(Expression e1, Expression e2) { return Multiplication::Builder(ArrayBuilder<Expression>(e1, e2).array(), 2); }
static Multiplication Builder(Expression e1, Expression e2, Expression e3) { return Multiplication::Builder(ArrayBuilder<Expression>(e1, e2, e3).array(), 3); }
static Multiplication Builder(Expression e1, Expression e2, Expression e3, Expression e4) { return Multiplication::Builder(ArrayBuilder<Expression>(e1, e2, e3, e4).array(), 4); }
static Multiplication Builder(Expression * children, size_t numberOfChildren) { return TreeHandle::NAryBuilder<Multiplication, MultiplicationNode>(children, numberOfChildren); }
template<typename T> static void computeOnArrays(T * m, T * n, T * result, int mNumberOfColumns, int mNumberOfRows, int nNumberOfColumns);

View File

@@ -1,7 +1,10 @@
#include <poincare/determinant.h>
#include <poincare/addition.h>
#include <poincare/matrix.h>
#include <poincare/layout_helper.h>
#include <poincare/rational.h>
#include <poincare/serialization_helper.h>
#include <poincare/subtraction.h>
extern "C" {
#include <assert.h>
}
@@ -21,7 +24,6 @@ int DeterminantNode::serialize(char * buffer, int bufferSize, Preferences::Print
return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, Determinant::s_functionHelper.name());
}
// TODO: handle this exactly in shallowReduce for small dimensions.
template<typename T>
Evaluation<T> DeterminantNode::templatedApproximate(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
Evaluation<T> input = childAtIndex(0)->approximate(T(), context, complexFormat, angleUnit);
@@ -29,10 +31,10 @@ Evaluation<T> DeterminantNode::templatedApproximate(Context * context, Preferenc
}
Expression DeterminantNode::shallowReduce(ReductionContext reductionContext) {
return Determinant(this).shallowReduce(reductionContext.context());
return Determinant(this).shallowReduce(reductionContext);
}
Expression Determinant::shallowReduce(Context * context) {
Expression Determinant::shallowReduce(ExpressionNode::ReductionContext reductionContext) {
{
Expression e = Expression::defaultShallowReduce();
if (e.isUndefined()) {
@@ -41,11 +43,60 @@ Expression Determinant::shallowReduce(Context * context) {
}
Expression c0 = childAtIndex(0);
// det(A) = A if A is not a matrix
if (!SortedIsMatrix(c0, context)) {
if (!SortedIsMatrix(c0, reductionContext.context())) {
replaceWithInPlace(c0);
return c0;
}
//TODO LEA for matrix
if (c0.type() == ExpressionNode::Type::Matrix) {
Matrix m0 = static_cast<Matrix &>(c0);
int dim = m0.numberOfRows();
if (dim != m0.numberOfColumns()) {
// Determinant is for square matrices
return replaceWithUndefinedInPlace();
}
Expression result;
if (dim == 1) {
// Determinant of [[a]] is a
result = m0.childAtIndex(0);
} else if (dim == 2) {
/* |a b|
* Determinant of |c d| is ad-bc */
Multiplication ad = Multiplication::Builder(m0.matrixChild(0,0), m0.matrixChild(1,1));
Multiplication bc = Multiplication::Builder(m0.matrixChild(0,1), m0.matrixChild(1,0));
result = Subtraction::Builder(ad, bc);
ad.shallowReduce(reductionContext);
bc.shallowReduce(reductionContext);
} else if (dim == 3) {
/* |a b c|
* Determinant of |d e f| is aei+bfg+cdh-ceg-bdi-afh
* |g h i| */
Expression a = m0.matrixChild(0,0);
Expression b = m0.matrixChild(0,1);
Expression c = m0.matrixChild(0,2);
Expression d = m0.matrixChild(1,0);
Expression e = m0.matrixChild(1,1);
Expression f = m0.matrixChild(1,2);
Expression g = m0.matrixChild(2,0);
Expression h = m0.matrixChild(2,1);
Expression i = m0.matrixChild(2,2);
constexpr int additionChildrenCount = 6;
Expression additionChildren[additionChildrenCount] = {
Multiplication::Builder(a.clone(), e.clone(), i.clone()),
Multiplication::Builder(b.clone(), f.clone(), g.clone()),
Multiplication::Builder(c.clone(), d.clone(), h.clone()),
Multiplication::Builder(Rational::Builder(-1), c, e, g),
Multiplication::Builder(Rational::Builder(-1), b, d, i),
Multiplication::Builder(Rational::Builder(-1), a, f, h)};
result = Addition::Builder(additionChildren, additionChildrenCount);
for (int i = 0; i < additionChildrenCount; i++) {
additionChildren[i].shallowReduce(reductionContext);
}
}
if (!result.isUninitialized()) {
replaceWithInPlace(result);
return result.shallowReduce(reductionContext);
}
}
return *this;
}

View File

@@ -33,9 +33,15 @@ QUIZ_CASE(poincare_matrix_simplify) {
assert_parsed_expression_simplify_to("[[1,2][3,4]]^(-1)", "[[-2,1][3/2,-1/2]]");
// Determinant
assert_parsed_expression_simplify_to("det([[1,2][3,4]])", "det([[1,2][3,4]])"); // TODO: implement determinant if dim < 3
assert_parsed_expression_simplify_to("det([[2,2][3,4]])", "det([[2,2][3,4]])");
assert_parsed_expression_simplify_to("det([[2,2][3,3]])", "det([[2,2][3,3]])");
assert_parsed_expression_simplify_to("det(π+π)", "2×π");
assert_parsed_expression_simplify_to("det([[π+π]])", "2×π");
assert_parsed_expression_simplify_to("det([[1,2][3,4]])", "-2");
assert_parsed_expression_simplify_to("det([[2,2][3,4]])", "2");
assert_parsed_expression_simplify_to("det([[2,2][3,4][3,4]])", Undefined::Name());
assert_parsed_expression_simplify_to("det([[2,2][3,3]])", "0");
assert_parsed_expression_simplify_to("det([[1,2,3][4,5,6][7,8,9]])", "0");
assert_parsed_expression_simplify_to("det([[1,2,3][4,5,6][7,8,9]])", "0");
assert_parsed_expression_simplify_to("det([[1,2,3][4π,5,6][7,8,9]])", "24×π-24");
// Dimension
assert_parsed_expression_simplify_to("dim(3)", "[[1,1]]");