mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
[apps/calculation] Add additional outputs for matrix
Change-Id: Ia4b285eb0f28eaed838d32a1fdfb785d13664f65
This commit is contained in:
committed by
Émilie Feral
parent
007c38652f
commit
f00c135b69
@@ -17,6 +17,7 @@ app_calculation_src = $(addprefix apps/calculation/,\
|
||||
additional_outputs/integer_list_controller.cpp \
|
||||
additional_outputs/scrollable_three_expressions_cell.cpp \
|
||||
additional_outputs/list_controller.cpp \
|
||||
additional_outputs/matrix_list_controller.cpp \
|
||||
additional_outputs/rational_list_controller.cpp \
|
||||
additional_outputs/trigonometry_graph_cell.cpp \
|
||||
additional_outputs/trigonometry_list_controller.cpp \
|
||||
|
||||
@@ -11,7 +11,7 @@ ExpressionsListController::ExpressionsListController(EditExpressionController *
|
||||
ListController(editExpressionController),
|
||||
m_cells{}
|
||||
{
|
||||
for (int i = 0; i < k_maxNumberOfCells; i++) {
|
||||
for (int i = 0; i < k_maxNumberOfRows; i++) {
|
||||
m_cells[i].setParentResponder(m_listController.selectableTableView());
|
||||
}
|
||||
}
|
||||
@@ -21,15 +21,17 @@ void ExpressionsListController::didEnterResponderChain(Responder * previousFirst
|
||||
}
|
||||
|
||||
int ExpressionsListController::reusableCellCount(int type) {
|
||||
return k_maxNumberOfCells;
|
||||
return k_maxNumberOfRows;
|
||||
}
|
||||
|
||||
void ExpressionsListController::viewDidDisappear() {
|
||||
ListController::viewDidDisappear();
|
||||
// Reset cell memoization to avoid taking extra space in the pool
|
||||
for (int i = 0; i < k_maxNumberOfCells; i++) {
|
||||
// Reset layout and cell memoization to avoid taking extra space in the pool
|
||||
for (int i = 0; i < k_maxNumberOfRows; i++) {
|
||||
m_cells[i].setLayout(Layout());
|
||||
m_layouts[i] = Layout();
|
||||
}
|
||||
m_expression = Expression();
|
||||
}
|
||||
|
||||
HighlightCell * ExpressionsListController::reusableCell(int index, int type) {
|
||||
@@ -43,24 +45,34 @@ KDCoordinate ExpressionsListController::rowHeight(int j) {
|
||||
}
|
||||
|
||||
void ExpressionsListController::willDisplayCellForIndex(HighlightCell * cell, int index) {
|
||||
/* Note : To further optimize memoization space in the pool, layout
|
||||
* serialization could be memoized instead, and layout would be recomputed
|
||||
* here, when setting cell's layout. */
|
||||
ExpressionTableCellWithPointer * myCell = static_cast<ExpressionTableCellWithPointer *>(cell);
|
||||
myCell->setLayout(layoutAtIndex(index));
|
||||
myCell->setAccessoryMessage(messageAtIndex(index));
|
||||
myCell->reloadScroll();
|
||||
}
|
||||
|
||||
int ExpressionsListController::numberOfRows() const {
|
||||
int nbOfRows = 0;
|
||||
for (size_t i = 0; i < k_maxNumberOfRows; i++) {
|
||||
if (!m_layouts[i].isUninitialized()) {
|
||||
nbOfRows++;
|
||||
}
|
||||
}
|
||||
return nbOfRows;
|
||||
}
|
||||
|
||||
void ExpressionsListController::setExpression(Poincare::Expression e) {
|
||||
// Reinitialize memoization
|
||||
for (int i = 0; i < k_maxNumberOfCells; i++) {
|
||||
for (int i = 0; i < k_maxNumberOfRows; i++) {
|
||||
m_layouts[i] = Layout();
|
||||
}
|
||||
m_expression = e;
|
||||
}
|
||||
|
||||
Poincare::Layout ExpressionsListController::layoutAtIndex(int index) {
|
||||
if (m_layouts[index].isUninitialized()) {
|
||||
computeLayoutAtIndex(index);
|
||||
}
|
||||
assert(!m_layouts[index].isUninitialized());
|
||||
return m_layouts[index];
|
||||
}
|
||||
|
||||
@@ -22,22 +22,22 @@ public:
|
||||
KDCoordinate rowHeight(int j) override;
|
||||
int typeAtLocation(int i, int j) override { return 0; }
|
||||
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
|
||||
int numberOfRows() const override;
|
||||
|
||||
// IllustratedListController
|
||||
void setExpression(Poincare::Expression e) override;
|
||||
|
||||
protected:
|
||||
constexpr static int k_maxNumberOfCells = 4;
|
||||
constexpr static int k_maxNumberOfRows = 5;
|
||||
int textAtIndex(char * buffer, size_t bufferSize, int index) override;
|
||||
Poincare::Expression m_expression;
|
||||
// Memoization of layouts
|
||||
mutable Poincare::Layout m_layouts[k_maxNumberOfCells];
|
||||
mutable Poincare::Layout m_layouts[k_maxNumberOfRows];
|
||||
private:
|
||||
Poincare::Layout layoutAtIndex(int index);
|
||||
virtual void computeLayoutAtIndex(int index) = 0;
|
||||
virtual I18n::Message messageAtIndex(int index) = 0;
|
||||
// Cells
|
||||
ExpressionTableCellWithPointer m_cells[k_maxNumberOfCells];
|
||||
ExpressionTableCellWithPointer m_cells[k_maxNumberOfRows];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -11,10 +11,6 @@ using namespace Shared;
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
int IntegerListController::numberOfRows() const {
|
||||
return 3 + factorExpressionIsComputable();
|
||||
}
|
||||
|
||||
Integer::Base baseAtIndex(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
@@ -27,12 +23,20 @@ Integer::Base baseAtIndex(int index) {
|
||||
}
|
||||
}
|
||||
|
||||
void IntegerListController::computeLayoutAtIndex(int index) {
|
||||
assert(m_expression.type() == ExpressionNode::Type::BasedInteger);
|
||||
// For index = k_indexOfFactorExpression, the layout is assumed to be alreday memoized because it is needed to compute the numberOfRows
|
||||
assert(index < k_indexOfFactorExpression);
|
||||
Integer i = static_cast<BasedInteger &>(m_expression).integer();
|
||||
m_layouts[index] = i.createLayout(baseAtIndex(index));
|
||||
void IntegerListController::setExpression(Poincare::Expression e) {
|
||||
ExpressionsListController::setExpression(e);
|
||||
static_assert(k_maxNumberOfRows >= k_indexOfFactorExpression + 1, "k_maxNumberOfRows must be greater than k_indexOfFactorExpression");
|
||||
assert(!m_expression.isUninitialized() && m_expression.type() == ExpressionNode::Type::BasedInteger);
|
||||
Integer integer = static_cast<BasedInteger &>(m_expression).integer();
|
||||
for (int index = 0; index < k_indexOfFactorExpression; ++index) {
|
||||
m_layouts[index] = integer.createLayout(baseAtIndex(index));
|
||||
}
|
||||
// Computing factorExpression
|
||||
Expression factor = Factor::Builder(m_expression.clone());
|
||||
PoincareHelpers::Simplify(&factor, App::app()->localContext(), ExpressionNode::ReductionTarget::User);
|
||||
if (!factor.isUndefined()) {
|
||||
m_layouts[k_indexOfFactorExpression] = PoincareHelpers::CreateLayout(factor);
|
||||
}
|
||||
}
|
||||
|
||||
I18n::Message IntegerListController::messageAtIndex(int index) {
|
||||
@@ -48,20 +52,4 @@ I18n::Message IntegerListController::messageAtIndex(int index) {
|
||||
}
|
||||
}
|
||||
|
||||
bool IntegerListController::factorExpressionIsComputable() const {
|
||||
if (!m_layouts[k_indexOfFactorExpression].isUninitialized()) {
|
||||
// The factor expression is already memoized
|
||||
return !m_layouts[k_indexOfFactorExpression].isEmpty();
|
||||
}
|
||||
Poincare::Context * context = App::app()->localContext();
|
||||
Expression factor = Factor::Builder(m_expression.clone());
|
||||
PoincareHelpers::Simplify(&factor, context, ExpressionNode::ReductionTarget::User);
|
||||
if (!factor.isUndefined()) {
|
||||
m_layouts[k_indexOfFactorExpression] = PoincareHelpers::CreateLayout(factor);
|
||||
return true;
|
||||
}
|
||||
m_layouts[k_indexOfFactorExpression] = EmptyLayout::Builder();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,13 +10,11 @@ public:
|
||||
IntegerListController(EditExpressionController * editExpressionController) :
|
||||
ExpressionsListController(editExpressionController) {}
|
||||
|
||||
//ListViewDataSource
|
||||
int numberOfRows() const override;
|
||||
void setExpression(Poincare::Expression e) override;
|
||||
|
||||
private:
|
||||
static constexpr int k_indexOfFactorExpression = 3;
|
||||
void computeLayoutAtIndex(int index) override;
|
||||
I18n::Message messageAtIndex(int index) override;
|
||||
bool factorExpressionIsComputable() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
103
apps/calculation/additional_outputs/matrix_list_controller.cpp
Normal file
103
apps/calculation/additional_outputs/matrix_list_controller.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#include "matrix_list_controller.h"
|
||||
#include "../app.h"
|
||||
#include "../../shared/poincare_helpers.h"
|
||||
#include <poincare_nodes.h>
|
||||
#include <poincare/matrix.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace Poincare;
|
||||
using namespace Shared;
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
void MatrixListController::setExpression(Poincare::Expression e) {
|
||||
ExpressionsListController::setExpression(e);
|
||||
assert(!m_expression.isUninitialized());
|
||||
static_assert(k_maxNumberOfRows >= k_maxNumberOfOutputRows, "k_maxNumberOfRows must be greater than k_maxNumberOfOutputRows");
|
||||
|
||||
Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences();
|
||||
Poincare::Preferences::ComplexFormat currentComplexFormat = preferences->complexFormat();
|
||||
if (currentComplexFormat == Poincare::Preferences::ComplexFormat::Real) {
|
||||
/* Temporary change complex format to avoid all additional expressions to be
|
||||
* "unreal" (with [i] for instance). As additional results are computed from
|
||||
* the output, which is built taking ComplexFormat into account, there are
|
||||
* no risks of displaying additional results on an unreal output. */
|
||||
preferences->setComplexFormat(Poincare::Preferences::ComplexFormat::Cartesian);
|
||||
}
|
||||
|
||||
Context * context = App::app()->localContext();
|
||||
ExpressionNode::ReductionContext reductionContext(
|
||||
context,
|
||||
preferences->complexFormat(),
|
||||
preferences->angleUnit(),
|
||||
ExpressionNode::ReductionTarget::SystemForApproximation,
|
||||
ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined);
|
||||
|
||||
// The expression must be reduced to call methods such as determinant or trace
|
||||
assert(m_expression.type() == ExpressionNode::Type::Matrix);
|
||||
|
||||
bool mIsSquared = (static_cast<Matrix &>(m_expression).numberOfRows() == static_cast<Matrix &>(m_expression).numberOfColumns());
|
||||
size_t index = 0;
|
||||
size_t messageIndex = 0;
|
||||
// 1. Matrix determinant if square matrix
|
||||
if (mIsSquared) {
|
||||
/* Determinant is reduced so that a null determinant can be detected.
|
||||
* However, some exceptions remain such as cos(x)^2+sin(x)^2-1 which will
|
||||
* not be reduced to a rational, but will be null in theory. */
|
||||
Expression determinant = Determinant::Builder(m_expression.clone()).reduce(reductionContext);
|
||||
m_indexMessageMap[index] = messageIndex++;
|
||||
m_layouts[index++] = getLayoutFromExpression(determinant, context, preferences);
|
||||
// 2. Matrix inverse if invertible matrix
|
||||
// A squared matrix is invertible if and only if determinant is non null
|
||||
if (!determinant.isUndefined() && !determinant.isRationalZero()) {
|
||||
m_indexMessageMap[index] = messageIndex++;
|
||||
m_layouts[index++] = getLayoutFromExpression(MatrixInverse::Builder(m_expression.clone()), context, preferences);
|
||||
}
|
||||
}
|
||||
// 3. Matrix row echelon form
|
||||
messageIndex = 2;
|
||||
Expression rowEchelonForm = MatrixRef::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);
|
||||
// 5. Matrix trace if square matrix
|
||||
if (mIsSquared) {
|
||||
m_indexMessageMap[index] = messageIndex++;
|
||||
m_layouts[index++] = getLayoutFromExpression(MatrixTrace::Builder(m_expression.clone()), context, preferences);
|
||||
}
|
||||
// Reset complex format as before
|
||||
preferences->setComplexFormat(currentComplexFormat);
|
||||
}
|
||||
|
||||
Poincare::Layout MatrixListController::getLayoutFromExpression(Expression e, Context * context, Poincare::Preferences * preferences) {
|
||||
assert(!e.isUninitialized());
|
||||
// Simplify or approximate expression
|
||||
Expression approximateExpression;
|
||||
Expression simplifiedExpression;
|
||||
e.simplifyAndApproximate(&simplifiedExpression, &approximateExpression, context,
|
||||
preferences->complexFormat(), preferences->angleUnit(),
|
||||
ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined);
|
||||
// simplify might have been interrupted, in which case we use approximate
|
||||
if (simplifiedExpression.isUninitialized()) {
|
||||
assert(!approximateExpression.isUninitialized());
|
||||
return Shared::PoincareHelpers::CreateLayout(approximateExpression);
|
||||
}
|
||||
return Shared::PoincareHelpers::CreateLayout(simplifiedExpression);
|
||||
}
|
||||
|
||||
I18n::Message MatrixListController::messageAtIndex(int index) {
|
||||
// Message index is mapped in setExpression because it depends on the Matrix.
|
||||
assert(index < k_maxNumberOfOutputRows && index >=0);
|
||||
I18n::Message messages[k_maxNumberOfOutputRows] = {
|
||||
I18n::Message::Determinant,
|
||||
I18n::Message::Inverse,
|
||||
I18n::Message::RowEchelonForm,
|
||||
I18n::Message::ReducedRowEchelonForm,
|
||||
I18n::Message::Trace};
|
||||
return messages[m_indexMessageMap[index]];
|
||||
}
|
||||
|
||||
}
|
||||
27
apps/calculation/additional_outputs/matrix_list_controller.h
Normal file
27
apps/calculation/additional_outputs/matrix_list_controller.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef CALCULATION_ADDITIONAL_OUTPUTS_MATRIX_LIST_CONTROLLER_H
|
||||
#define CALCULATION_ADDITIONAL_OUTPUTS_MATRIX_LIST_CONTROLLER_H
|
||||
|
||||
#include "expressions_list_controller.h"
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
class MatrixListController : public ExpressionsListController {
|
||||
public:
|
||||
MatrixListController(EditExpressionController * editExpressionController) :
|
||||
ExpressionsListController(editExpressionController) {}
|
||||
|
||||
void setExpression(Poincare::Expression e) override;
|
||||
|
||||
private:
|
||||
I18n::Message messageAtIndex(int index) override;
|
||||
Poincare::Layout getLayoutFromExpression(Poincare::Expression e, Poincare::Context * context, Poincare::Preferences * preferences);
|
||||
// Map from cell index to message index
|
||||
constexpr static int k_maxNumberOfOutputRows = 5;
|
||||
int m_indexMessageMap[k_maxNumberOfOutputRows];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -9,34 +9,31 @@ using namespace Shared;
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
int RationalListController::numberOfRows() const {
|
||||
return 2;
|
||||
}
|
||||
|
||||
Integer extractInteger(const Expression e) {
|
||||
assert(e.type() == ExpressionNode::Type::BasedInteger);
|
||||
return static_cast<const BasedInteger &>(e).integer();
|
||||
}
|
||||
|
||||
void RationalListController::computeLayoutAtIndex(int index) {
|
||||
void RationalListController::setExpression(Poincare::Expression e) {
|
||||
ExpressionsListController::setExpression(e);
|
||||
assert(!m_expression.isUninitialized());
|
||||
static_assert(k_maxNumberOfRows >= 2, "k_maxNumberOfRows must be greater than 2");
|
||||
|
||||
bool negative = false;
|
||||
Expression div = m_expression;
|
||||
if (m_expression.type() == ExpressionNode::Type::Opposite) {
|
||||
negative = true;
|
||||
div = m_expression.childAtIndex(0);
|
||||
}
|
||||
|
||||
assert(div.type() == ExpressionNode::Type::Division);
|
||||
Integer numerator = extractInteger(div.childAtIndex(0));
|
||||
numerator.setNegative(negative);
|
||||
Integer denominator = extractInteger(div.childAtIndex(1));
|
||||
Expression e;
|
||||
if (index == 0) {
|
||||
e = Integer::CreateMixedFraction(numerator, denominator);
|
||||
} else {
|
||||
assert(index == 1);
|
||||
e = Integer::CreateEuclideanDivision(numerator, denominator);
|
||||
}
|
||||
m_layouts[index] = PoincareHelpers::CreateLayout(e);
|
||||
|
||||
int index = 0;
|
||||
m_layouts[index++] = PoincareHelpers::CreateLayout(Integer::CreateMixedFraction(numerator, denominator));
|
||||
m_layouts[index++] = PoincareHelpers::CreateLayout(Integer::CreateEuclideanDivision(numerator, denominator));
|
||||
}
|
||||
|
||||
I18n::Message RationalListController::messageAtIndex(int index) {
|
||||
|
||||
@@ -10,10 +10,9 @@ public:
|
||||
RationalListController(EditExpressionController * editExpressionController) :
|
||||
ExpressionsListController(editExpressionController) {}
|
||||
|
||||
//ListViewDataSource
|
||||
int numberOfRows() const override;
|
||||
void setExpression(Poincare::Expression e) override;
|
||||
|
||||
private:
|
||||
void computeLayoutAtIndex(int index) override;
|
||||
I18n::Message messageAtIndex(int index) override;
|
||||
int textAtIndex(char * buffer, size_t bufferSize, int index) override;
|
||||
};
|
||||
|
||||
@@ -15,12 +15,15 @@ namespace Calculation {
|
||||
void UnitListController::setExpression(Poincare::Expression e) {
|
||||
ExpressionsListController::setExpression(e);
|
||||
assert(!m_expression.isUninitialized());
|
||||
// Reinitialize m_memoizedExpressions
|
||||
for (size_t i = 0; i < k_maxNumberOfCells; i++) {
|
||||
m_memoizedExpressions[i] = Expression();
|
||||
static_assert(k_maxNumberOfRows >= 3, "k_maxNumberOfRows must be greater than 3");
|
||||
|
||||
Poincare::Expression expressions[k_maxNumberOfRows];
|
||||
// Initialize expressions
|
||||
for (size_t i = 0; i < k_maxNumberOfRows; i++) {
|
||||
expressions[i] = Expression();
|
||||
}
|
||||
|
||||
size_t numberOfMemoizedExpressions = 0;
|
||||
size_t numberOfExpressions = 0;
|
||||
// 1. First rows: miscellaneous classic units for some dimensions
|
||||
Expression copy = m_expression.clone();
|
||||
Expression units;
|
||||
@@ -32,7 +35,7 @@ void UnitListController::setExpression(Poincare::Expression e) {
|
||||
|
||||
if (Unit::IsSISpeed(units)) {
|
||||
// 1.a. Turn speed into km/h
|
||||
m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder(
|
||||
expressions[numberOfExpressions++] = UnitConvert::Builder(
|
||||
m_expression.clone(),
|
||||
Multiplication::Builder(
|
||||
Unit::Kilometer(),
|
||||
@@ -45,7 +48,7 @@ void UnitListController::setExpression(Poincare::Expression e) {
|
||||
requireSimplification = true; // Simplify the conversion
|
||||
} else if (Unit::IsSIVolume(units)) {
|
||||
// 1.b. Turn volume into L
|
||||
m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder(
|
||||
expressions[numberOfExpressions++] = UnitConvert::Builder(
|
||||
m_expression.clone(),
|
||||
Unit::Liter()
|
||||
);
|
||||
@@ -53,14 +56,14 @@ void UnitListController::setExpression(Poincare::Expression e) {
|
||||
canChangeUnitPrefix = true; // Pick best prefix (mL)
|
||||
} else if (Unit::IsSIEnergy(units)) {
|
||||
// 1.c. Turn energy into Wh
|
||||
m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder(
|
||||
expressions[numberOfExpressions++] = UnitConvert::Builder(
|
||||
m_expression.clone(),
|
||||
Multiplication::Builder(
|
||||
Unit::Watt(),
|
||||
Unit::Hour()
|
||||
)
|
||||
);
|
||||
m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder(
|
||||
expressions[numberOfExpressions++] = UnitConvert::Builder(
|
||||
m_expression.clone(),
|
||||
Unit::ElectronVolt()
|
||||
);
|
||||
@@ -69,21 +72,21 @@ void UnitListController::setExpression(Poincare::Expression e) {
|
||||
} else if (Unit::IsSITime(units)) {
|
||||
// Turn time into ? year + ? month + ? day + ? h + ? min + ? s
|
||||
double value = Shared::PoincareHelpers::ApproximateToScalar<double>(copy, App::app()->localContext());
|
||||
m_memoizedExpressions[numberOfMemoizedExpressions++] = Unit::BuildTimeSplit(value, App::app()->localContext(), Preferences::sharedPreferences()->complexFormat(), Preferences::sharedPreferences()->angleUnit());
|
||||
expressions[numberOfExpressions++] = Unit::BuildTimeSplit(value, App::app()->localContext(), Preferences::sharedPreferences()->complexFormat(), Preferences::sharedPreferences()->angleUnit());
|
||||
}
|
||||
// 1.d. Simplify and tune prefix of all computed expressions
|
||||
size_t currentExpressionIndex = 0;
|
||||
while (currentExpressionIndex < numberOfMemoizedExpressions) {
|
||||
assert(!m_memoizedExpressions[currentExpressionIndex].isUninitialized());
|
||||
while (currentExpressionIndex < numberOfExpressions) {
|
||||
assert(!expressions[currentExpressionIndex].isUninitialized());
|
||||
if (requireSimplification) {
|
||||
Shared::PoincareHelpers::Simplify(&m_memoizedExpressions[currentExpressionIndex], App::app()->localContext(), ExpressionNode::ReductionTarget::User);
|
||||
Shared::PoincareHelpers::Simplify(&expressions[currentExpressionIndex], App::app()->localContext(), ExpressionNode::ReductionTarget::User);
|
||||
}
|
||||
if (canChangeUnitPrefix) {
|
||||
Expression newUnits;
|
||||
// Reduce to be able to removeUnit
|
||||
PoincareHelpers::Reduce(&m_memoizedExpressions[currentExpressionIndex], App::app()->localContext(), ExpressionNode::ReductionTarget::User);
|
||||
m_memoizedExpressions[currentExpressionIndex] = m_memoizedExpressions[currentExpressionIndex].removeUnit(&newUnits);
|
||||
double value = Shared::PoincareHelpers::ApproximateToScalar<double>(m_memoizedExpressions[currentExpressionIndex], App::app()->localContext());
|
||||
PoincareHelpers::Reduce(&expressions[currentExpressionIndex], App::app()->localContext(), ExpressionNode::ReductionTarget::User);
|
||||
expressions[currentExpressionIndex] = expressions[currentExpressionIndex].removeUnit(&newUnits);
|
||||
double value = Shared::PoincareHelpers::ApproximateToScalar<double>(expressions[currentExpressionIndex], App::app()->localContext());
|
||||
ExpressionNode::ReductionContext reductionContext(
|
||||
App::app()->localContext(),
|
||||
Preferences::sharedPreferences()->complexFormat(),
|
||||
@@ -91,36 +94,36 @@ void UnitListController::setExpression(Poincare::Expression e) {
|
||||
ExpressionNode::ReductionTarget::User,
|
||||
ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined);
|
||||
Unit::ChooseBestPrefixForValue(&newUnits, &value, reductionContext);
|
||||
m_memoizedExpressions[currentExpressionIndex] = Multiplication::Builder(Number::FloatNumber(value), newUnits);
|
||||
expressions[currentExpressionIndex] = Multiplication::Builder(Number::FloatNumber(value), newUnits);
|
||||
}
|
||||
currentExpressionIndex++;
|
||||
}
|
||||
|
||||
// 2. IS units only
|
||||
assert(numberOfMemoizedExpressions < k_maxNumberOfCells - 1);
|
||||
m_memoizedExpressions[numberOfMemoizedExpressions] = m_expression.clone();
|
||||
Shared::PoincareHelpers::Simplify(&m_memoizedExpressions[numberOfMemoizedExpressions], App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::InternationalSystem);
|
||||
numberOfMemoizedExpressions++;
|
||||
assert(numberOfExpressions < k_maxNumberOfRows - 1);
|
||||
expressions[numberOfExpressions] = m_expression.clone();
|
||||
Shared::PoincareHelpers::Simplify(&expressions[numberOfExpressions], App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::InternationalSystem);
|
||||
numberOfExpressions++;
|
||||
|
||||
// 3. Get rid of duplicates
|
||||
Expression reduceExpression = m_expression.clone();
|
||||
// Make m_expression compareable to m_memoizedExpressions (turn BasedInteger into Rational for instance)
|
||||
// Make m_expression comparable to expressions (turn BasedInteger into Rational for instance)
|
||||
Shared::PoincareHelpers::Simplify(&reduceExpression, App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::None);
|
||||
currentExpressionIndex = 1;
|
||||
while (currentExpressionIndex < numberOfMemoizedExpressions) {
|
||||
while (currentExpressionIndex < numberOfExpressions) {
|
||||
bool duplicateFound = false;
|
||||
for (size_t i = 0; i < currentExpressionIndex + 1; i++) {
|
||||
// Compare the currentExpression to all previous memoized expressions and to m_expression
|
||||
Expression comparedExpression = i == currentExpressionIndex ? reduceExpression : m_memoizedExpressions[i];
|
||||
// Compare the currentExpression to all previous expressions and to m_expression
|
||||
Expression comparedExpression = i == currentExpressionIndex ? reduceExpression : expressions[i];
|
||||
assert(!comparedExpression.isUninitialized());
|
||||
if (comparedExpression.isIdenticalTo(m_memoizedExpressions[currentExpressionIndex])) {
|
||||
numberOfMemoizedExpressions--;
|
||||
if (comparedExpression.isIdenticalTo(expressions[currentExpressionIndex])) {
|
||||
numberOfExpressions--;
|
||||
// Shift next expressions
|
||||
for (size_t j = currentExpressionIndex; j < numberOfMemoizedExpressions; j++) {
|
||||
m_memoizedExpressions[j] = m_memoizedExpressions[j+1];
|
||||
for (size_t j = currentExpressionIndex; j < numberOfExpressions; j++) {
|
||||
expressions[j] = expressions[j+1];
|
||||
}
|
||||
// Remove last expression
|
||||
m_memoizedExpressions[numberOfMemoizedExpressions] = Expression();
|
||||
expressions[numberOfExpressions] = Expression();
|
||||
// The current expression has been discarded, no need to increment the current index
|
||||
duplicateFound = true;
|
||||
break;
|
||||
@@ -131,21 +134,12 @@ void UnitListController::setExpression(Poincare::Expression e) {
|
||||
currentExpressionIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int UnitListController::numberOfRows() const {
|
||||
int nbOfRows = 0;
|
||||
for (size_t i = 0; i < k_maxNumberOfCells; i++) {
|
||||
if (!m_memoizedExpressions[i].isUninitialized()) {
|
||||
nbOfRows++;
|
||||
// Memoize layouts
|
||||
for (size_t i = 0; i < k_maxNumberOfRows; i++) {
|
||||
if (!expressions[i].isUninitialized()) {
|
||||
m_layouts[i] = Shared::PoincareHelpers::CreateLayout(expressions[i]);
|
||||
}
|
||||
}
|
||||
return nbOfRows;
|
||||
}
|
||||
|
||||
void UnitListController::computeLayoutAtIndex(int index) {
|
||||
assert(!m_memoizedExpressions[index].isUninitialized());
|
||||
m_layouts[index] = Shared::PoincareHelpers::CreateLayout(m_memoizedExpressions[index]);
|
||||
}
|
||||
|
||||
I18n::Message UnitListController::messageAtIndex(int index) {
|
||||
|
||||
@@ -12,13 +12,8 @@ public:
|
||||
|
||||
void setExpression(Poincare::Expression e) override;
|
||||
|
||||
//ListViewDataSource
|
||||
int numberOfRows() const override;
|
||||
private:
|
||||
void computeLayoutAtIndex(int index) override;
|
||||
I18n::Message messageAtIndex(int index) override;
|
||||
// Memoization of expressions
|
||||
mutable Poincare::Expression m_memoizedExpressions[k_maxNumberOfCells];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -291,6 +291,9 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co
|
||||
if (o.hasDefinedComplexApproximation(context, complexFormat, preferences->angleUnit())) {
|
||||
return AdditionalInformationType::Complex;
|
||||
}
|
||||
if (o.type() == ExpressionNode::Type::Matrix) {
|
||||
return AdditionalInformationType::Matrix;
|
||||
}
|
||||
return AdditionalInformationType::None;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
Rational,
|
||||
Trigonometry,
|
||||
Unit,
|
||||
Matrix,
|
||||
Complex
|
||||
};
|
||||
static bool DisplaysExact(DisplayOutput d) { return d != DisplayOutput::ApproximateOnly; }
|
||||
|
||||
@@ -17,7 +17,8 @@ HistoryController::HistoryController(EditExpressionController * editExpressionCo
|
||||
m_integerController(editExpressionController),
|
||||
m_rationalController(editExpressionController),
|
||||
m_trigonometryController(editExpressionController),
|
||||
m_unitController(editExpressionController)
|
||||
m_unitController(editExpressionController),
|
||||
m_matrixController(editExpressionController)
|
||||
{
|
||||
for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) {
|
||||
m_calculationHistory[i].setParentResponder(&m_selectableTableView);
|
||||
@@ -110,6 +111,8 @@ bool HistoryController::handleEvent(Ion::Events::Event event) {
|
||||
vc = &m_rationalController;
|
||||
} else if (additionalInfoType == Calculation::AdditionalInformationType::Unit) {
|
||||
vc = &m_unitController;
|
||||
} else if (additionalInfoType == Calculation::AdditionalInformationType::Matrix) {
|
||||
vc = &m_matrixController;
|
||||
}
|
||||
if (vc) {
|
||||
vc->setExpression(e);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "additional_outputs/rational_list_controller.h"
|
||||
#include "additional_outputs/trigonometry_list_controller.h"
|
||||
#include "additional_outputs/unit_list_controller.h"
|
||||
#include "additional_outputs/matrix_list_controller.h"
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
@@ -48,6 +49,7 @@ private:
|
||||
RationalListController m_rationalController;
|
||||
TrigonometryListController m_trigonometryController;
|
||||
UnitListController m_unitController;
|
||||
MatrixListController m_matrixController;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
size_t size() const override;
|
||||
#if POINCARE_TREE_LOG
|
||||
void logNodeName(std::ostream & stream) const override {
|
||||
stream << "Based Integer";
|
||||
stream << "BasedInteger";
|
||||
}
|
||||
virtual void logAttributes(std::ostream & stream) const override;
|
||||
#endif
|
||||
@@ -38,6 +38,7 @@ public:
|
||||
template<typename T> T templatedApproximate() const;
|
||||
|
||||
private:
|
||||
int simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted, bool ignoreParentheses) const override;
|
||||
Expression shallowReduce(ReductionContext reductionContext) override;
|
||||
LayoutShape leftLayoutShape() const override { return m_base == Integer::Base::Decimal ? LayoutShape::Integer : LayoutShape::BinaryHexadecimal; }
|
||||
Integer::Base m_base;
|
||||
|
||||
@@ -75,6 +75,7 @@ public:
|
||||
|
||||
/* Operation on matrix */
|
||||
int rank(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, bool inPlace = false);
|
||||
Expression createTrace();
|
||||
// Inverse the array in-place. Array has to be given in the form array[row_index][column_index]
|
||||
template<typename T> static int ArrayInverse(T * array, int numberOfRows, int numberOfColumns);
|
||||
static Matrix CreateIdentity(int dim);
|
||||
|
||||
@@ -66,6 +66,15 @@ template<typename T> T BasedIntegerNode::templatedApproximate() const {
|
||||
|
||||
// Comparison
|
||||
|
||||
int BasedIntegerNode::simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted, bool ignoreParentheses) const {
|
||||
if (!ascending) {
|
||||
return e->simplificationOrderSameType(this, true, canBeInterrupted, ignoreParentheses);
|
||||
}
|
||||
assert(e->type() == ExpressionNode::Type::BasedInteger);
|
||||
const BasedIntegerNode * other = static_cast<const BasedIntegerNode *>(e);
|
||||
return Integer::NaturalOrder(integer(), other->integer());
|
||||
}
|
||||
|
||||
Expression BasedIntegerNode::shallowReduce(ReductionContext reductionContext) {
|
||||
return BasedInteger(this).shallowReduce();
|
||||
}
|
||||
|
||||
@@ -146,6 +146,16 @@ int Matrix::rank(Context * context, Preferences::ComplexFormat complexFormat, Pr
|
||||
return rank;
|
||||
}
|
||||
|
||||
Expression Matrix::createTrace() {
|
||||
assert(numberOfRows() == numberOfColumns());
|
||||
int n = numberOfRows();
|
||||
Addition a = Addition::Builder();
|
||||
for (int i = 0; i < n; i++) {
|
||||
a.addChildAtIndexInPlace(matrixChild(i,i).clone(), i, i);
|
||||
}
|
||||
return std::move(a);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int Matrix::ArrayInverse(T * array, int numberOfRows, int numberOfColumns) {
|
||||
if (numberOfRows != numberOfColumns) {
|
||||
@@ -378,6 +388,7 @@ Expression Matrix::createInverse(ExpressionNode::ReductionContext reductionConte
|
||||
}
|
||||
|
||||
Expression Matrix::determinant(ExpressionNode::ReductionContext reductionContext, bool * couldComputeDeterminant, bool inPlace) {
|
||||
// Determinant must be called on a reduced matrix only.
|
||||
*couldComputeDeterminant = true;
|
||||
Matrix m = inPlace ? *this : clone().convert<Matrix>();
|
||||
int dim = m.numberOfRows();
|
||||
|
||||
@@ -48,11 +48,7 @@ Expression MatrixTrace::shallowReduce(ExpressionNode::ReductionContext reduction
|
||||
if (matrixChild0.numberOfRows() != matrixChild0.numberOfColumns()) {
|
||||
return replaceWithUndefinedInPlace();
|
||||
}
|
||||
int n = matrixChild0.numberOfRows();
|
||||
Addition a = Addition::Builder();
|
||||
for (int i = 0; i < n; i++) {
|
||||
a.addChildAtIndexInPlace(matrixChild0.matrixChild(i,i), i, i); // No need to clone
|
||||
}
|
||||
Expression a = matrixChild0.createTrace();
|
||||
replaceWithInPlace(a);
|
||||
return a.shallowReduce(reductionContext);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user