From 745099842a91fbc2ff2f6348d158eeaedf14919a Mon Sep 17 00:00:00 2001 From: Laury Date: Sat, 30 Apr 2022 19:12:54 +0200 Subject: [PATCH] [poincare] Fixed two serious bugs in sequences simplification --- apps/shared/global_context.cpp | 15 +++++++++++---- poincare/src/sequence.cpp | 13 ++++++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/apps/shared/global_context.cpp b/apps/shared/global_context.cpp index bf8c3cdb4..0bf416175 100644 --- a/apps/shared/global_context.cpp +++ b/apps/shared/global_context.cpp @@ -128,6 +128,7 @@ const Expression GlobalContext::ExpressionForSequence(const SymbolAbstract & sym if (!rank.isUninitialized()) { bool rankIsInteger = false; double rankValue = rank.approximateToScalar(ctx, Poincare::Preferences::sharedPreferences()->complexFormat(), Poincare::Preferences::sharedPreferences()->angleUnit()); + int rankValueFloor = std::floor(rankValue); if (rank.type() == ExpressionNode::Type::Rational) { Rational n = static_cast(rank); rankIsInteger = n.isInteger(); @@ -137,11 +138,17 @@ const Expression GlobalContext::ExpressionForSequence(const SymbolAbstract & sym * approximate the rank and check if it is an integer. Unfortunately this * leads to some edge cases were, because of quantification, we have * floor(x) = x while x is not integer.*/ - rankIsInteger = std::floor(rankValue) == rankValue; + rankIsInteger = rankValueFloor == rankValue; } - if (rankIsInteger && !seq.badlyReferencesItself(ctx)) { - SequenceContext sqctx(ctx, sequenceStore()); - return Float::Builder(seq.evaluateXYAtParameter(rankValue, &sqctx).x2()); + if (rankIsInteger) { + if (rankValueFloor - seq.initialRank() < (int) seq.type()) { // Seq can reference itself but be defined explicitly for first values + assert(rankValueFloor - seq.initialRank() == 0 || rankValueFloor - seq.initialRank() == 1); + return rankValueFloor - seq.initialRank() == 0 ? seq.firstInitialConditionExpressionClone() : seq.secondInitialConditionExpressionClone(); + } + if (!seq.badlyReferencesItself(ctx)) { + SequenceContext sqctx(ctx, sequenceStore()); + return Float::Builder(seq.evaluateXYAtParameter(rankValue, &sqctx).x2()); + } } } return Float::Builder(NAN); diff --git a/poincare/src/sequence.cpp b/poincare/src/sequence.cpp index 5c24602d7..3eeae7e40 100644 --- a/poincare/src/sequence.cpp +++ b/poincare/src/sequence.cpp @@ -118,7 +118,7 @@ Expression Sequence::shallowReduce(ExpressionNode::ReductionContext reductionCon return *this; } - Expression result = replacedByDefinitionIfPossible(reductionContext.context()); + Expression result = replacedByDefinitionIfPossible(reductionContext.context()); // We don't need to check if the result is uninitialized result = Expression::ExpressionWithoutSymbols(result, reductionContext.context()); if (result.isUninitialized()) { @@ -184,6 +184,17 @@ Expression Sequence::replacedByDefinitionIfPossible(Context * context) { } Expression result = seq.expressionClone(); + + if (result.hasExpression([](Expression e, const void * context) { + if (e.type() != ExpressionNode::Type::Sequence) { + return false; + } + return strcmp(static_cast(e).name(), reinterpret_cast(context)) == 0; + }, reinterpret_cast(name()))) + { + return Expression(); + } + return result.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknown), childAtIndex(0)); }