diff --git a/apps/calculation/additional_outputs/unit_list_controller.cpp b/apps/calculation/additional_outputs/unit_list_controller.cpp index f3463b248..869826d5e 100644 --- a/apps/calculation/additional_outputs/unit_list_controller.cpp +++ b/apps/calculation/additional_outputs/unit_list_controller.cpp @@ -28,8 +28,7 @@ void UnitListController::setExpression(Poincare::Expression e) { Expression copy = m_expression.clone(); Expression units; // Reduce to be able to recognize units - PoincareHelpers::Reduce(©, App::app()->localContext(), ExpressionNode::ReductionTarget::User); - copy = copy.removeUnit(&units); + PoincareHelpers::ReduceAndRemoveUnit(©, App::app()->localContext(), ExpressionNode::ReductionTarget::User, &units); double value = Shared::PoincareHelpers::ApproximateToScalar(copy, App::app()->localContext()); ExpressionNode::ReductionContext reductionContext( App::app()->localContext(), diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index b4c898b91..c1ee3692e 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -255,8 +255,7 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co } if (o.hasUnit()) { Expression unit; - PoincareHelpers::Reduce(&o, App::app()->localContext(), ExpressionNode::ReductionTarget::User, ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined, ExpressionNode::UnitConversion::None); - o = o.removeUnit(&unit); + PoincareHelpers::ReduceAndRemoveUnit(&o, App::app()->localContext(), ExpressionNode::ReductionTarget::User, &unit, ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined, ExpressionNode::UnitConversion::None); double value = PoincareHelpers::ApproximateToScalar(o, App::app()->localContext()); return (Unit::ShouldDisplayAdditionalOutputs(value, unit, GlobalPreferences::sharedGlobalPreferences()->unitFormat())) ? AdditionalInformationType::Unit : AdditionalInformationType::None; } diff --git a/apps/shared/poincare_helpers.h b/apps/shared/poincare_helpers.h index 254217321..6c4eb0a77 100644 --- a/apps/shared/poincare_helpers.h +++ b/apps/shared/poincare_helpers.h @@ -77,6 +77,11 @@ inline void Reduce(Poincare::Expression * e, Poincare::Context * context, Poinca *e = e->reduce(Poincare::ExpressionNode::ReductionContext(context, complexFormat, preferences->angleUnit(), GlobalPreferences::sharedGlobalPreferences()->unitFormat(), target, symbolicComputation, unitConversion)); } +inline void ReduceAndRemoveUnit(Poincare::Expression * e, Poincare::Context * context, Poincare::ExpressionNode::ReductionTarget target, Poincare::Expression * unit, Poincare::ExpressionNode::SymbolicComputation symbolicComputation = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion unitConversion = Poincare::ExpressionNode::UnitConversion::Default) { + PoincareHelpers::Reduce(e, context, target, symbolicComputation, unitConversion); + *e = e->removeUnit(unit); +} + inline void ParseAndSimplifyAndApproximate(const char * text, Poincare::Expression * simplifiedExpression, Poincare::Expression * approximateExpression, Poincare::Context * context, Poincare::ExpressionNode::SymbolicComputation symbolicComputation = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition) { Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences(); Poincare::Preferences::ComplexFormat complexFormat = Poincare::Expression::UpdatedComplexFormatWithTextInput(preferences->complexFormat(), text); diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 4818643e6..d75a684cf 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -248,6 +248,7 @@ public: static void ParseAndSimplifyAndApproximate(const char * text, Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, Preferences::UnitFormat unitFormat, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, ExpressionNode::UnitConversion unitConversion = ExpressionNode::UnitConversion::Default); void simplifyAndApproximate(Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, Preferences::UnitFormat unitFormat, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, ExpressionNode::UnitConversion unitConversion = ExpressionNode::UnitConversion::Default); Expression reduce(ExpressionNode::ReductionContext context); + Expression reduceAndRemoveUnit(ExpressionNode::ReductionContext context, Expression * Unit); Expression mapOnMatrixFirstChild(ExpressionNode::ReductionContext reductionContext); /* 'ExpressionWithoutSymbols' returns an uninitialized expression if it is diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index b3377d603..051a2c3d2 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -827,6 +827,12 @@ Expression Expression::angleUnitToRadian(Preferences::AngleUnit angleUnit) { return *this; } +Expression Expression::reduceAndRemoveUnit(ExpressionNode::ReductionContext reductionContext, Expression * Unit) { + /* RemoveUnit has to be called on reduced expression. reduce method is called + * instead of deepReduce to catch interrupted simplification. */ + return reduce(reductionContext).removeUnit(Unit); +} + Expression Expression::reduce(ExpressionNode::ReductionContext reductionContext) { sSimplificationHasBeenInterrupted = false; Expression result = deepReduce(reductionContext); diff --git a/poincare/src/multiplication.cpp b/poincare/src/multiplication.cpp index 1be7fa526..bdf058e5b 100644 --- a/poincare/src/multiplication.cpp +++ b/poincare/src/multiplication.cpp @@ -425,8 +425,7 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext * re Expression units; /* removeUnit has to be called on reduced expression but we want to modify * the least the expression so we use the uninvasive reduction context. */ - self = self.reduce(ExpressionNode::ReductionContext::NonInvasiveReductionContext(*reductionContext)); - self = self.removeUnit(&units); + self = self.reduceAndRemoveUnit(ExpressionNode::ReductionContext::NonInvasiveReductionContext(*reductionContext), &units); if (self.isUndefined() || units.isUninitialized()) { // TODO: handle error "Invalid unit" @@ -500,11 +499,9 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext * re } // Apply simplifications if (unitsAccu.numberOfChildren() > 0) { - // Divide by derived units - units = Division::Builder(units, unitsAccu.clone()).reduce(*reductionContext); Expression newUnits; - // Separate units and generated values - units = units.removeUnit(&newUnits); + // Divide by derived units, separate units and generated values + units = Division::Builder(units, unitsAccu.clone()).reduceAndRemoveUnit(*reductionContext, &newUnits); // Assemble final value Multiplication m = Multiplication::Builder(units); self.replaceWithInPlace(m); diff --git a/poincare/src/unit_convert.cpp b/poincare/src/unit_convert.cpp index 76b384a16..876c33680 100644 --- a/poincare/src/unit_convert.cpp +++ b/poincare/src/unit_convert.cpp @@ -77,7 +77,7 @@ Expression UnitConvert::shallowBeautify(ExpressionNode::ReductionContext * reduc reductionContext->target(), ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined); Expression unit; - Expression childWithoutUnit = childAtIndex(1).clone().reduce(reductionContextWithUnits).removeUnit(&unit); + Expression childWithoutUnit = childAtIndex(1).clone().reduceAndRemoveUnit(reductionContextWithUnits, &unit); if (childWithoutUnit.isUndefined() || unit.isUninitialized()) { // There is no unit on the right return replaceWithUndefinedInPlace(); @@ -104,9 +104,8 @@ Expression UnitConvert::shallowBeautify(ExpressionNode::ReductionContext * reduc // Divide the left member by the new unit Expression division = Division::Builder(childAtIndex(0), unit.clone()); - division = division.reduce(*reductionContext); Expression divisionUnit; - division = division.removeUnit(&divisionUnit); + division = division.reduceAndRemoveUnit(*reductionContext, &divisionUnit); if (!divisionUnit.isUninitialized()) { // The left and right members are not homogeneous return replaceWithUndefinedInPlace(); diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index 0fdc1e493..c5883006a 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -401,13 +401,11 @@ void assert_reduced_expression_unit_is(const char * expression, const char * uni Shared::GlobalContext globalContext; ExpressionNode::ReductionContext redContext(&globalContext, Real, Degree, Metric, SystemForApproximation); Expression e = parse_expression(expression, &globalContext, false); - e = e.reduce(redContext); Expression u1; - e = e.removeUnit(&u1); + e = e.reduceAndRemoveUnit(redContext, &u1); Expression e2 = parse_expression(unit, &globalContext, false); Expression u2; - e2 = e2.reduce(redContext); - e2.removeUnit(&u2); + e2.reduceAndRemoveUnit(redContext, &u2); quiz_assert_print_if_failure(u1.isUninitialized() == u2.isUninitialized() && (u1.isUninitialized() || u1.isIdenticalTo(u2)), expression); } @@ -425,9 +423,8 @@ void assert_additional_results_compute_to(const char * expression, const char * assert(length <= maxNumberOfResults); Expression additional[maxNumberOfResults]; ExpressionNode::ReductionContext reductionContext = ExpressionNode::ReductionContext(&globalContext, Cartesian, Degree, unitFormat, User, ReplaceAllSymbolsWithUndefined, DefaultUnitConversion); - Expression e = parse_expression(expression, &globalContext, false).reduce(reductionContext); Expression units; - e = e.removeUnit(&units); + Expression e = parse_expression(expression, &globalContext, false).reduceAndRemoveUnit(reductionContext, &units); double value = e.approximateToScalar(&globalContext, Cartesian, Degree); if (!Unit::ShouldDisplayAdditionalOutputs(value, units, unitFormat)) {