mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
Merge branch 'Lauryy06:upsilon-dev' into upsilon-dev
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@ epsilon.map
|
||||
.vscode
|
||||
.DS_Store
|
||||
.gradle
|
||||
.vs
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ public:
|
||||
None = 0,
|
||||
Integer,
|
||||
Rational,
|
||||
SecondDegree,
|
||||
Trigonometry,
|
||||
Unit,
|
||||
Matrix,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user