Merge branch 'Lauryy06:upsilon-dev' into upsilon-dev

This commit is contained in:
Hugo Berthet-Rambaud
2021-09-13 07:57:08 +02:00
committed by GitHub
17 changed files with 323 additions and 14 deletions

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@ epsilon.map
.vscode
.DS_Store
.gradle
.vs

View File

@@ -19,6 +19,7 @@ app_calculation_src = $(addprefix apps/calculation/,\
additional_outputs/list_controller.cpp \
additional_outputs/matrix_list_controller.cpp \
additional_outputs/rational_list_controller.cpp \
additional_outputs/second_degree_list_controller.cpp \
additional_outputs/trigonometry_graph_cell.cpp \
additional_outputs/trigonometry_list_controller.cpp \
additional_outputs/trigonometry_model.cpp \

View File

@@ -0,0 +1,190 @@
#include "../app.h"
#include <apps/global_preferences.h>
#include "../../shared/poincare_helpers.h"
#include <poincare/layout_helper.h>
#include <poincare/code_point_layout.h>
#include <poincare/rational.h>
#include <poincare/opposite.h>
#include <poincare/addition.h>
#include <poincare/parenthesis.h>
#include <poincare/equal.h>
#include <poincare/subtraction.h>
#include <poincare/multiplication.h>
#include <poincare/division.h>
#include <poincare/square_root.h>
#include <poincare/symbol.h>
#include <poincare/power.h>
#include "second_degree_list_controller.h"
using namespace Poincare;
using namespace Shared;
namespace Calculation {
void SecondDegreeListController::setExpression(Poincare::Expression e) {
ExpressionsListController::setExpression(e);
assert(!m_expression.isUninitialized());
Expression polynomialCoefficients[Expression::k_maxNumberOfPolynomialCoefficients];
Context * context = App::app()->localContext();
Preferences * preferences = Preferences::sharedPreferences();
PoincareHelpers::Reduce(&m_expression, context, ExpressionNode::ReductionTarget::SystemForAnalysis);
int degree = m_expression.getPolynomialReducedCoefficients(
"x",
polynomialCoefficients,
context,
Expression::UpdatedComplexFormatWithExpressionInput(preferences->complexFormat(), m_expression, context),
preferences->angleUnit(),
GlobalPreferences::sharedGlobalPreferences()->unitFormat(),
ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition);
assert(degree == 2);
Expression a = polynomialCoefficients[2];
Expression b = polynomialCoefficients[1];
Expression c = polynomialCoefficients[0];
bool aIsNotOne = !(a.type() == ExpressionNode::Type::Rational && static_cast<const Rational &>(a).isOne());
Expression delta = Subtraction::Builder(Power::Builder(b.clone(), Rational::Builder(2)), Multiplication::Builder(Rational::Builder(4), a.clone(), c.clone()));
PoincareHelpers::Simplify(&delta, context, ExpressionNode::ReductionTarget::SystemForApproximation);
Expression alpha = Opposite::Builder(Division::Builder(b.clone(), Multiplication::Builder(Rational::Builder(2), a.clone())));
PoincareHelpers::Simplify(&alpha, context, ExpressionNode::ReductionTarget::User);
Expression beta = Opposite::Builder(Division::Builder(delta.clone(), Multiplication::Builder(Rational::Builder(4), a.clone())));
PoincareHelpers::Simplify(&beta, context, ExpressionNode::ReductionTarget::User);
/*
* Because when can't apply reduce or simplify to keep the canonised
* we must beautify the expression manually
*/
Expression canonised;
if (alpha.type() == ExpressionNode::Type::Opposite) {
canonised = Addition::Builder(Symbol::Builder("x", strlen("x")), alpha.childAtIndex(0).clone());
}
else {
canonised = Subtraction::Builder(Symbol::Builder("x", strlen("x")), alpha.clone());
}
canonised = Power::Builder(Parenthesis::Builder(canonised.clone()), Rational::Builder(2));
if (aIsNotOne) {
canonised = Multiplication::Builder(a.clone(), canonised.clone());
}
if (beta.type() == ExpressionNode::Type::Opposite) {
canonised = Subtraction::Builder(canonised.clone(), beta.childAtIndex(0).clone());
}
else {
canonised = Addition::Builder(canonised.clone(), beta.clone());
}
Expression x0;
Expression x1;
if (delta.nullStatus(context) == ExpressionNode::NullStatus::Null) {
// x0 = x1 = -b/(2a)
x0 = Division::Builder(Opposite::Builder(b), Multiplication::Builder(Rational::Builder(2), a));
m_numberOfSolutions = 1;
PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::User);
}
else {
// x0 = (-b-sqrt(delta))/(2a)
x0 = Division::Builder(Subtraction::Builder(Opposite::Builder(b.clone()), SquareRoot::Builder(delta.clone())), Multiplication::Builder(Rational::Builder(2), a.clone()));
// x1 = (-b+sqrt(delta))/(2a)
x1 = Division::Builder(Addition::Builder(Opposite::Builder(b), SquareRoot::Builder(delta.clone())), Multiplication::Builder(Rational::Builder(2), a));
m_numberOfSolutions = 2;
PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::User);
PoincareHelpers::Simplify(&x1, context, ExpressionNode::ReductionTarget::User);
if (x0.type() == ExpressionNode::Type::Unreal) {
assert(x1.type() == ExpressionNode::Type::Unreal);
m_numberOfSolutions = 0;
}
}
Expression factorized;
if (m_numberOfSolutions == 2) {
if (x0.type() == ExpressionNode::Type::Opposite) {
factorized = Parenthesis::Builder(Addition::Builder(Symbol::Builder("x", strlen("x")), x0.childAtIndex(0).clone()));
}
else {
factorized = Parenthesis::Builder(Subtraction::Builder(Symbol::Builder("x", strlen("x")), x0.clone()));
}
if (x1.type() == ExpressionNode::Type::Opposite) {
factorized = Multiplication::Builder(factorized.clone(), Parenthesis::Builder(Addition::Builder(Symbol::Builder("x", strlen("x")), x1.childAtIndex(0).clone())));
}
else {
factorized = Multiplication::Builder(factorized.clone(), Parenthesis::Builder(Subtraction::Builder(Symbol::Builder("x", strlen("x")), x1.clone())));
}
if (aIsNotOne) {
factorized = Multiplication::Builder(a.clone(), factorized.clone());
}
}
else if (m_numberOfSolutions == 1) {
if (x0.type() == ExpressionNode::Type::Opposite) {
factorized = Power::Builder(Parenthesis::Builder(Addition::Builder(Symbol::Builder("x", strlen("x")), x0.childAtIndex(0).clone())), Rational::Builder(2));
}
else {
factorized = Power::Builder(Parenthesis::Builder(Subtraction::Builder(Symbol::Builder("x", strlen("x")), x0.clone())), Rational::Builder(2));
}
if (aIsNotOne) {
factorized = Multiplication::Builder(a.clone(), factorized.clone());
}
}
PoincareHelpers::Simplify(&delta, context, ExpressionNode::ReductionTarget::User);
m_layouts[0] = PoincareHelpers::CreateLayout(canonised);
if (m_numberOfSolutions > 0) {
m_layouts[1] = PoincareHelpers::CreateLayout(factorized);
m_layouts[2] = PoincareHelpers::CreateLayout(delta);
m_layouts[3] = PoincareHelpers::CreateLayout(x0);
if (m_numberOfSolutions > 1) {
m_layouts[4] = PoincareHelpers::CreateLayout(x1);
}
}
else {
m_layouts[1] = PoincareHelpers::CreateLayout(delta);
}
}
I18n::Message SecondDegreeListController::messageAtIndex(int index) {
if (m_numberOfSolutions > 0) {
if (index == 0) {
return I18n::Message::CanonicalForm;
}
if (index == 1) {
return I18n::Message::FactorizedForm;
}
if (index == 2) {
return I18n::Message::Discriminant;
}
if (index == 3) {
if (m_numberOfSolutions == 1) {
return I18n::Message::OnlyRoot;
}
else {
return I18n::Message::FirstRoot;
}
}
return I18n::Message::SecondRoot;
}
else {
switch (index) {
case 0:
return I18n::Message::CanonicalForm;
default:
return I18n::Message::Discriminant;
}
}
}
}

View File

@@ -0,0 +1,25 @@
#ifndef CALCULATION_ADDITIONAL_OUTPUTS_SECOND_DEGREE_CONTROLLER_H
#define CALCULATION_ADDITIONAL_OUTPUTS_SECOND_DEGREE_CONTROLLER_H
#include "expressions_list_controller.h"
namespace Calculation {
class SecondDegreeListController : public ExpressionsListController {
public:
SecondDegreeListController(EditExpressionController * editExpressionController) :
ExpressionsListController(editExpressionController),
m_numberOfSolutions(0) {}
void setExpression(Poincare::Expression e) override;
private:
I18n::Message messageAtIndex(int index) override;
int m_numberOfSolutions;
};
}
#endif

View File

@@ -11,4 +11,10 @@ AdditionalDeterminant = "Determinante"
AdditionalInverse = "Inverse"
AdditionalRowEchelonForm = "Stufenform"
AdditionalReducedRowEchelonForm = "Reduzierte Stufenform"
AdditionalTrace = "Spur"
AdditionalTrace = "Spur"
CanonicalForm = "Kanonische Form"
FactorizedForm = "Factorisierte Form"
Discriminant = "Diskriminante"
OnlyRoot = "Wurzel"
FirstRoot = "Erste Wurzel"
SecondRoot = "Zweite Wurzel"

View File

@@ -12,3 +12,9 @@ AdditionalInverse = "Inverse"
AdditionalRowEchelonForm = "Row echelon form"
AdditionalReducedRowEchelonForm = "Reduced row echelon form"
AdditionalTrace = "Trace"
CanonicalForm = "Canonical form"
FactorizedForm = "Factorized form"
Discriminant = "Discriminant"
OnlyRoot = "Root"
FirstRoot = "First root"
SecondRoot = "Second root"

View File

@@ -11,4 +11,10 @@ AdditionalDeterminant = "Determinante"
AdditionalInverse = "Inversa"
AdditionalRowEchelonForm = "Matriz escalonada"
AdditionalReducedRowEchelonForm = "Matriz escalonada reducida"
AdditionalTrace = "Traza"
AdditionalTrace = "Traza"
CanonicalForm = "Forma canónica"
FactorizedForm = "Forma factorizada"
Discriminant = "Discriminante"
OnlyRoot = "Raíz"
FirstRoot = "Primera raíz"
SecondRoot = "Segunda raíz"

View File

@@ -11,4 +11,10 @@ AdditionalDeterminant = "Déterminant"
AdditionalInverse = "Inverse"
AdditionalRowEchelonForm = "Forme échelonnée"
AdditionalReducedRowEchelonForm = "Forme échelonnée réduite"
AdditionalTrace = "Trace"
AdditionalTrace = "Trace"
CanonicalForm = "Forme canonique"
FactorizedForm = "Forme factorisée"
Discriminant = "Discriminant"
OnlyRoot = "Racine"
FirstRoot = "Première racine"
SecondRoot = "Seconde racine"

View File

@@ -12,3 +12,9 @@ AdditionalInverse = "inverz"
AdditionalRowEchelonForm = "Sor echelon forma"
AdditionalReducedRowEchelonForm = "Csökkentett sorú Echelon forma"
AdditionalTrace = "Nyomkövetés"
CanonicalForm = "Kanonikus forma"
FactorizedForm = "Factorizált forma"
Discriminant = "Discriminant"
OnlyRoot = "Gyökér"
FirstRoot = "Első gyökér"
SecondRoot = "Második gyökér"

View File

@@ -11,4 +11,10 @@ AdditionalDeterminant = "Determinante"
AdditionalInverse = "Inversa"
AdditionalRowEchelonForm = "Matrice a scalini"
AdditionalReducedRowEchelonForm = "Matrice ridotta a scalini"
AdditionalTrace = "Traccia"
AdditionalTrace = "Traccia"
CanonicalForm = "Forma canonica"
FactorizedForm = "Forma fattorizzata"
Discriminant = "Discriminante"
OnlyRoot = "Radice"
FirstRoot = "Prima radice"
SecondRoot = "Seconda radice"

View File

@@ -11,4 +11,10 @@ AdditionalDeterminant = "Determinant"
AdditionalInverse = "Inverse"
AdditionalRowEchelonForm = "Echelonvorm"
AdditionalReducedRowEchelonForm = "Gereduceerde echelonvorm"
AdditionalTrace = "Spoor"
AdditionalTrace = "Spoor"
CanonicalForm = "Canonische vorm"
FactorizedForm = "Factorized vorm"
Discriminant = "Discriminant"
OnlyRoot = "Wortel"
FirstRoot = "Eerste wortel"
SecondRoot = "Tweede wortel"

View File

@@ -11,4 +11,10 @@ AdditionalDeterminant = "Determinante"
AdditionalInverse = "Matriz inversa"
AdditionalRowEchelonForm = "Matriz escalonada"
AdditionalReducedRowEchelonForm = "Matriz escalonada reduzida"
AdditionalTrace = "Traço"
AdditionalTrace = "Traço"
CanonicalForm = "Forma canónica"
FactorizedForm = "Factorized form"
Discriminant = "Discriminante"
OnlyRoot = "Raiz"
FirstRoot = "Primeira raiz"
SecondRoot = "Segunda raiz"

View File

@@ -8,6 +8,7 @@
#include <poincare/undefined.h>
#include <poincare/unit.h>
#include <poincare/unreal.h>
#include <poincare/symbol_abstract.h>
#include <string.h>
#include <cmath>
#include <algorithm>
@@ -272,6 +273,9 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co
if (o.type() == ExpressionNode::Type::Matrix) {
return AdditionalInformationType::Matrix;
}
if (o.polynomialDegree(context, "x") == 2) {
return AdditionalInformationType::SecondDegree;
}
return AdditionalInformationType::None;
}

View File

@@ -39,6 +39,7 @@ public:
None = 0,
Integer,
Rational,
SecondDegree,
Trigonometry,
Unit,
Matrix,

View File

@@ -16,6 +16,7 @@ HistoryController::HistoryController(EditExpressionController * editExpressionCo
m_complexController(editExpressionController),
m_integerController(editExpressionController),
m_rationalController(editExpressionController),
m_secondDegreeController(editExpressionController),
m_trigonometryController(editExpressionController),
m_unitController(editExpressionController),
m_matrixController(editExpressionController)
@@ -100,6 +101,8 @@ bool HistoryController::handleEvent(Ion::Events::Event event) {
Expression e = calculationAtIndex(focusRow)->exactOutput();
if (additionalInfoType == Calculation::AdditionalInformationType::Complex) {
vc = &m_complexController;
} else if (additionalInfoType == Calculation::AdditionalInformationType::SecondDegree) {
vc = &m_secondDegreeController;
} else if (additionalInfoType == Calculation::AdditionalInformationType::Trigonometry) {
vc = &m_trigonometryController;
// Find which of the input or output is the cosine/sine

View File

@@ -8,6 +8,7 @@
#include "additional_outputs/complex_list_controller.h"
#include "additional_outputs/integer_list_controller.h"
#include "additional_outputs/rational_list_controller.h"
#include "additional_outputs/second_degree_list_controller.h"
#include "additional_outputs/trigonometry_list_controller.h"
#include "additional_outputs/unit_list_controller.h"
#include "additional_outputs/matrix_list_controller.h"
@@ -47,6 +48,7 @@ private:
ComplexListController m_complexController;
IntegerListController m_integerController;
RationalListController m_rationalController;
SecondDegreeListController m_secondDegreeController;
TrigonometryListController m_trigonometryController;
UnitListController m_unitController;
MatrixListController m_matrixController;

View File

@@ -1,6 +1,7 @@
#include <poincare/power.h>
#include <poincare/addition.h>
#include <poincare/arithmetic.h>
#include <poincare/based_integer.h>
#include <poincare/binomial_coefficient.h>
#include <poincare/constant.h>
#include <poincare/cosine.h>
@@ -68,18 +69,33 @@ int PowerNode::polynomialDegree(Context * context, const char * symbolName) cons
if (op0Deg < 0) {
return -1;
}
Integer i;
bool foundInteger = false;
if (childAtIndex(1)->type() == ExpressionNode::Type::Rational) {
RationalNode * r = static_cast<RationalNode *>(childAtIndex(1));
if (!r->isInteger() || Number(r).sign() == Sign::Negative) {
return -1;
}
Integer numeratorInt = r->signedNumerator();
if (!numeratorInt.isExtractable()) {
foundInteger = true;
i = r->signedNumerator();
}
else if(childAtIndex(1)->type() == ExpressionNode::Type::BasedInteger) {
BasedIntegerNode * b = static_cast<BasedIntegerNode *>(childAtIndex(1));
if (Number(b).sign() == Sign::Negative) {
return -1;
}
op0Deg *= numeratorInt.extractedInt();
foundInteger = true;
i = b->integer();
}
if (foundInteger) {
if (!i.isExtractable()) {
return -1;
}
op0Deg *= i.extractedInt();
return op0Deg;
}
return -1;
}
@@ -356,10 +372,9 @@ int Power::getPolynomialCoefficients(Context * context, const char * symbolName,
}
/* Here we only consider the case x^4 as privateGetPolynomialCoefficients is
* supposed to be called after reducing the expression. */
if (childAtIndex(0).type() == ExpressionNode::Type::Symbol
&& strcmp(childAtIndex(0).convert<Symbol>().name(), symbolName) == 0
&& childAtIndex(1).type() == ExpressionNode::Type::Rational)
{
int n;
bool foundInteger = false;
if (childAtIndex(1).type() == ExpressionNode::Type::Rational) {
Rational r = childAtIndex(1).convert<Rational>();
if (!r.isInteger() || r.sign() == ExpressionNode::Sign::Negative) {
return -1;
@@ -368,7 +383,26 @@ int Power::getPolynomialCoefficients(Context * context, const char * symbolName,
if (!num.isExtractable()) {
return -1;
}
int n = num.extractedInt();
foundInteger = true;
n = num.extractedInt();
}
else if(childAtIndex(1).type() == ExpressionNode::Type::BasedInteger) {
BasedInteger b = childAtIndex(1).convert<BasedInteger>();
if (Number(b).sign() == ExpressionNode::Sign::Negative) {
return -1;
}
foundInteger = true;
Integer i = b.integer();
if (!i.isExtractable()) {
return -1;
}
n = i.extractedInt();
}
if (childAtIndex(0).type() == ExpressionNode::Type::Symbol
&& strcmp(childAtIndex(0).convert<Symbol>().name(), symbolName) == 0
&& foundInteger)
{
if (n <= k_maxPolynomialDegree) {
for (int i = 0; i < n; i++) {
coefficients[i] = Rational::Builder(0);