mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[calculation] Fix bug in second degree list controller
This commit is contained in:
@@ -29,6 +29,12 @@ void SecondDegreeListController::setExpression(Poincare::Expression e) {
|
||||
|
||||
Context * context = App::app()->localContext();
|
||||
Preferences * preferences = Preferences::sharedPreferences();
|
||||
Poincare::ExpressionNode::ReductionContext reductionContext = Poincare::ExpressionNode::ReductionContext(context,
|
||||
preferences->complexFormat(), preferences->angleUnit(),
|
||||
GlobalPreferences::sharedGlobalPreferences()->unitFormat(),
|
||||
ExpressionNode::ReductionTarget::SystemForApproximation,
|
||||
ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition,
|
||||
Poincare::ExpressionNode::UnitConversion::Default);
|
||||
|
||||
PoincareHelpers::Reduce(&m_expression, context, ExpressionNode::ReductionTarget::SystemForAnalysis);
|
||||
|
||||
@@ -46,60 +52,108 @@ void SecondDegreeListController::setExpression(Poincare::Expression e) {
|
||||
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);
|
||||
// Alpha is -b/2a, but because after we use -α, we immediately store -α=-(-b/2a)=b/2a.
|
||||
Expression minusAlpha = Division::Builder(b.clone(), Multiplication::Builder(Rational::Builder(2), a.clone()));
|
||||
PoincareHelpers::Reduce(&minusAlpha, context, ExpressionNode::ReductionTarget::SystemForApproximation);
|
||||
|
||||
Expression beta = Opposite::Builder(Division::Builder(delta.clone(), Multiplication::Builder(Rational::Builder(4), a.clone())));
|
||||
PoincareHelpers::Simplify(&beta, context, ExpressionNode::ReductionTarget::User);
|
||||
// Same thing for β
|
||||
Expression minusBeta = Division::Builder(delta.clone(), Multiplication::Builder(Rational::Builder(4), a.clone()));
|
||||
PoincareHelpers::Reduce(&minusBeta, context, ExpressionNode::ReductionTarget::SystemForApproximation);
|
||||
|
||||
enum MultiplicationTypeForA {
|
||||
Nothing,
|
||||
Minus,
|
||||
Parenthesis,
|
||||
Normal
|
||||
};
|
||||
|
||||
MultiplicationTypeForA multiplicationTypeForA;
|
||||
|
||||
if (a.type() == ExpressionNode::Type::Rational && static_cast<const Rational &>(a).isOne()) {
|
||||
multiplicationTypeForA = MultiplicationTypeForA::Nothing;
|
||||
}
|
||||
else if(a.type() == ExpressionNode::Type::Rational && static_cast<const Rational &>(a).isMinusOne()){
|
||||
multiplicationTypeForA = MultiplicationTypeForA::Minus;
|
||||
}
|
||||
else if (a.type() == ExpressionNode::Type::Addition) {
|
||||
multiplicationTypeForA = MultiplicationTypeForA::Parenthesis;
|
||||
}
|
||||
else {
|
||||
multiplicationTypeForA = MultiplicationTypeForA::Normal;
|
||||
}
|
||||
|
||||
PoincareHelpers::Simplify(&a, context, ExpressionNode::ReductionTarget::User);
|
||||
|
||||
/*
|
||||
* Because when can't apply reduce or simplify to keep the canonised
|
||||
* we must beautify the expression manually
|
||||
* Because when can't apply reduce or simplify to keep the
|
||||
* canonized form 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 xMinusAlphaPowerTwo;
|
||||
Expression alpha = getOppositeIfExists(minusAlpha, &reductionContext);
|
||||
|
||||
if (alpha.isUninitialized()) {
|
||||
PoincareHelpers::Simplify(&minusAlpha, context, ExpressionNode::ReductionTarget::User);
|
||||
xMinusAlphaPowerTwo = Power::Builder(Parenthesis::Builder(Addition::Builder(Symbol::Builder("x", strlen("x")), minusAlpha)), Rational::Builder(2));
|
||||
}
|
||||
else {
|
||||
PoincareHelpers::Simplify(&alpha, context, ExpressionNode::ReductionTarget::User);
|
||||
xMinusAlphaPowerTwo = Power::Builder(Parenthesis::Builder(Subtraction::Builder(Symbol::Builder("x", strlen("x")), alpha)), Rational::Builder(2));
|
||||
}
|
||||
|
||||
Expression xMinusAlphaPowerTwoWithFactor;
|
||||
|
||||
switch (multiplicationTypeForA)
|
||||
{
|
||||
case MultiplicationTypeForA::Nothing:
|
||||
xMinusAlphaPowerTwoWithFactor = xMinusAlphaPowerTwo;
|
||||
break;
|
||||
case MultiplicationTypeForA::Minus:
|
||||
xMinusAlphaPowerTwoWithFactor = Multiplication::Builder(a.clone(), xMinusAlphaPowerTwo);
|
||||
break;
|
||||
case MultiplicationTypeForA::Parenthesis:
|
||||
xMinusAlphaPowerTwoWithFactor = Multiplication::Builder(Parenthesis::Builder(a.clone()), xMinusAlphaPowerTwo);
|
||||
break;
|
||||
case MultiplicationTypeForA::Normal:
|
||||
xMinusAlphaPowerTwoWithFactor = Multiplication::Builder(a.clone(), xMinusAlphaPowerTwo);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
Expression canonized;
|
||||
Expression beta = getOppositeIfExists(minusBeta, &reductionContext);
|
||||
if (beta.isUninitialized()) {
|
||||
PoincareHelpers::Simplify(&minusBeta, context, ExpressionNode::ReductionTarget::User);
|
||||
canonized = Subtraction::Builder(xMinusAlphaPowerTwoWithFactor, minusBeta);
|
||||
}
|
||||
else {
|
||||
PoincareHelpers::Simplify(&beta, context, ExpressionNode::ReductionTarget::User);
|
||||
canonized = Addition::Builder(xMinusAlphaPowerTwoWithFactor, beta);
|
||||
}
|
||||
|
||||
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));
|
||||
x0 = Division::Builder(Opposite::Builder(b.clone()), Multiplication::Builder(Rational::Builder(2), a.clone()));
|
||||
m_numberOfSolutions = 1;
|
||||
PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::User);
|
||||
PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::SystemForApproximation);
|
||||
}
|
||||
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));
|
||||
x1 = Division::Builder(Addition::Builder(Opposite::Builder(b.clone()), SquareRoot::Builder(delta.clone())), Multiplication::Builder(Rational::Builder(2), a.clone()));
|
||||
m_numberOfSolutions = 2;
|
||||
PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::User);
|
||||
PoincareHelpers::Simplify(&x1, context, ExpressionNode::ReductionTarget::User);
|
||||
PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::SystemForApproximation);
|
||||
PoincareHelpers::Simplify(&x1, context, ExpressionNode::ReductionTarget::SystemForApproximation);
|
||||
if (x0.type() == ExpressionNode::Type::Unreal) {
|
||||
assert(x1.type() == ExpressionNode::Type::Unreal);
|
||||
m_numberOfSolutions = 0;
|
||||
@@ -109,40 +163,87 @@ void SecondDegreeListController::setExpression(Poincare::Expression e) {
|
||||
Expression factorized;
|
||||
|
||||
if (m_numberOfSolutions == 2) {
|
||||
Expression firstFactor;
|
||||
Expression secondFactor;
|
||||
|
||||
Expression x0Opposite = getOppositeIfExists(x0, &reductionContext);
|
||||
if (x0Opposite.isUninitialized()) {
|
||||
PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::User);
|
||||
firstFactor = Subtraction::Builder(Symbol::Builder("x", strlen("x")), x0);
|
||||
}
|
||||
else {
|
||||
PoincareHelpers::Simplify(&x0Opposite, context, ExpressionNode::ReductionTarget::User);
|
||||
firstFactor = Addition::Builder(Symbol::Builder("x", strlen("x")), x0Opposite);
|
||||
}
|
||||
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())));
|
||||
|
||||
Expression x1Opposite = getOppositeIfExists(x1, &reductionContext);
|
||||
if (x1Opposite.isUninitialized()) {
|
||||
PoincareHelpers::Simplify(&x1, context, ExpressionNode::ReductionTarget::User);
|
||||
secondFactor = Subtraction::Builder(Symbol::Builder("x", strlen("x")), x1);
|
||||
}
|
||||
else {
|
||||
factorized = Multiplication::Builder(factorized.clone(), Parenthesis::Builder(Subtraction::Builder(Symbol::Builder("x", strlen("x")), x1.clone())));
|
||||
PoincareHelpers::Simplify(&x1Opposite, context, ExpressionNode::ReductionTarget::User);
|
||||
secondFactor = Addition::Builder(Symbol::Builder("x", strlen("x")), x1Opposite);
|
||||
}
|
||||
|
||||
if (aIsNotOne) {
|
||||
factorized = Multiplication::Builder(a.clone(), factorized.clone());
|
||||
Expression solutionProduct = Multiplication::Builder(Parenthesis::Builder(firstFactor), Parenthesis::Builder(secondFactor));
|
||||
switch (multiplicationTypeForA)
|
||||
{
|
||||
case MultiplicationTypeForA::Nothing:
|
||||
factorized = solutionProduct;
|
||||
break;
|
||||
case MultiplicationTypeForA::Minus:
|
||||
factorized = Multiplication::Builder(a.clone(), solutionProduct);
|
||||
break;
|
||||
case MultiplicationTypeForA::Parenthesis:
|
||||
factorized = Multiplication::Builder(Parenthesis::Builder(a.clone()), solutionProduct);
|
||||
break;
|
||||
case MultiplicationTypeForA::Normal:
|
||||
factorized = Multiplication::Builder(a.clone(), solutionProduct);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
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));
|
||||
Expression x0Opposite = getOppositeIfExists(x0, &reductionContext);
|
||||
Expression factor;
|
||||
if (x0Opposite.isUninitialized()) {
|
||||
PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::User);
|
||||
factor = Subtraction::Builder(Symbol::Builder("x", strlen("x")), x0);
|
||||
}
|
||||
else {
|
||||
factorized = Power::Builder(Parenthesis::Builder(Subtraction::Builder(Symbol::Builder("x", strlen("x")), x0.clone())), Rational::Builder(2));
|
||||
PoincareHelpers::Simplify(&x0Opposite, context, ExpressionNode::ReductionTarget::User);
|
||||
factor = Addition::Builder(Symbol::Builder("x", strlen("x")), x0Opposite);
|
||||
}
|
||||
|
||||
if (aIsNotOne) {
|
||||
factorized = Multiplication::Builder(a.clone(), factorized.clone());
|
||||
Expression solutionProduct = Power::Builder(Parenthesis::Builder(factor), Rational::Builder(2));
|
||||
switch (multiplicationTypeForA)
|
||||
{
|
||||
case MultiplicationTypeForA::Nothing:
|
||||
factorized = solutionProduct;
|
||||
break;
|
||||
case MultiplicationTypeForA::Minus:
|
||||
factorized = Multiplication::Builder(a.clone(), solutionProduct);
|
||||
break;
|
||||
case MultiplicationTypeForA::Parenthesis:
|
||||
factorized = Multiplication::Builder(Parenthesis::Builder(a.clone()), solutionProduct);
|
||||
break;
|
||||
case MultiplicationTypeForA::Normal:
|
||||
factorized = Multiplication::Builder(a.clone(), solutionProduct);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PoincareHelpers::Simplify(&delta, context, ExpressionNode::ReductionTarget::User);
|
||||
|
||||
m_layouts[0] = PoincareHelpers::CreateLayout(canonised);
|
||||
m_layouts[0] = PoincareHelpers::CreateLayout(canonized);
|
||||
if (m_numberOfSolutions > 0) {
|
||||
m_layouts[1] = PoincareHelpers::CreateLayout(factorized);
|
||||
m_layouts[2] = PoincareHelpers::CreateLayout(delta);
|
||||
@@ -156,6 +257,27 @@ void SecondDegreeListController::setExpression(Poincare::Expression e) {
|
||||
}
|
||||
}
|
||||
|
||||
Expression SecondDegreeListController::getOppositeIfExists(Expression e, Poincare::ExpressionNode::ReductionContext * reductionContext) {
|
||||
if (e.isNumber() && e.sign(reductionContext->context()) == ExpressionNode::Sign::Negative) {
|
||||
Number n = static_cast<Number&>(e);
|
||||
return std::move(n.setSign(ExpressionNode::Sign::Positive));
|
||||
}
|
||||
else if (e.type() == ExpressionNode::Type::Multiplication && e.numberOfChildren() > 0 && e.childAtIndex(0).isNumber() && e.childAtIndex(0).sign(reductionContext->context()) == ExpressionNode::Sign::Negative) {
|
||||
Multiplication m = static_cast<Multiplication&>(e);
|
||||
if (m.childAtIndex(0).type() == ExpressionNode::Type::Rational && static_cast<Rational&>(e).isMinusOne()) {
|
||||
// The negative numeral factor is -1, we just remove it
|
||||
m.removeChildAtIndexInPlace(0);
|
||||
} else {
|
||||
Expression firstChild = m.childAtIndex(0);
|
||||
Number n = static_cast<Number&>(firstChild);
|
||||
m.childAtIndex(0).setChildrenInPlace(n.setSign(ExpressionNode::Sign::Positive));
|
||||
}
|
||||
PoincareHelpers::Simplify(&m, reductionContext->context(), ExpressionNode::ReductionTarget::User);
|
||||
return std::move(m);
|
||||
}
|
||||
return Expression();
|
||||
}
|
||||
|
||||
I18n::Message SecondDegreeListController::messageAtIndex(int index) {
|
||||
if (m_numberOfSolutions > 0) {
|
||||
if (index == 0) {
|
||||
|
||||
@@ -14,6 +14,7 @@ public:
|
||||
void setExpression(Poincare::Expression e) override;
|
||||
|
||||
private:
|
||||
Poincare::Expression getOppositeIfExists(Poincare::Expression e, Poincare::ExpressionNode::ReductionContext * reductionContext);
|
||||
I18n::Message messageAtIndex(int index) override;
|
||||
int m_numberOfSolutions;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user