mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[Sequences] Fixed a few crashes
Change-Id: Ib929bbae0f9ca06409706336ff799075e1288694
This commit is contained in:
committed by
Émilie Feral
parent
26bbdead7d
commit
960335c330
@@ -12,9 +12,10 @@ using namespace Poincare;
|
||||
namespace Shared {
|
||||
|
||||
template<typename T>
|
||||
CacheContext<T>::CacheContext(Context * parentContext) :
|
||||
ContextWithParent(parentContext),
|
||||
m_values{{NAN, NAN},{NAN, NAN},{NAN,NAN}}
|
||||
CacheContext<T>::CacheContext(SequenceContext * sequenceContext) :
|
||||
ContextWithParent(sequenceContext),
|
||||
m_values{{NAN, NAN},{NAN, NAN},{NAN,NAN}},
|
||||
m_sequenceContext(sequenceContext)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -34,9 +35,14 @@ const Expression CacheContext<T>::expressionForSymbolAbstract(const Poincare::Sy
|
||||
Sequence * seq = m_sequenceContext->sequenceStore()->modelForRecord(record);
|
||||
rank.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknown), Float<T>::Builder(m_nValue));
|
||||
T n = PoincareHelpers::ApproximateToScalar<T>(rank, this);
|
||||
// In case the rank is not int or sequence referenced is not defined, return NAN
|
||||
if (std::floor(n) == n && seq->fullName() != nullptr) {
|
||||
return Float<T>::Builder(seq->valueAtRank<T>(n, m_sequenceContext));
|
||||
// In case the sequence referenced is not defined or if the rank is not an int, return NAN
|
||||
if (seq->fullName() != nullptr) {
|
||||
if (std::floor(n) == n) {
|
||||
Expression sequenceExpression = seq->expressionReduced(this);
|
||||
if (seq->hasValidExpression(this)) {
|
||||
return Float<T>::Builder(seq->valueAtRank<T>(n, m_sequenceContext));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Float<T>::Builder(NAN);
|
||||
|
||||
@@ -11,11 +11,10 @@ namespace Shared {
|
||||
template<typename T>
|
||||
class CacheContext : public Poincare::ContextWithParent {
|
||||
public:
|
||||
CacheContext(Poincare::Context * parentContext);
|
||||
CacheContext(SequenceContext * sequenceContext);
|
||||
const Poincare::Expression expressionForSymbolAbstract(const Poincare::SymbolAbstract & symbol, bool clone, float unknownSymbolValue = NAN) override;
|
||||
void setValueForSymbol(T value, const Poincare::Symbol & symbol);
|
||||
void setNValue(int n) { m_nValue = n; }
|
||||
void setSequenceContext(SequenceContext * sequenceContext) { m_sequenceContext = sequenceContext;}
|
||||
private:
|
||||
int nameIndexForSymbol(const Poincare::Symbol & symbol);
|
||||
int rankIndexForSymbol(const Poincare::Symbol & symbol);
|
||||
|
||||
@@ -127,7 +127,7 @@ const Expression GlobalContext::ExpressionForSequence(const SymbolAbstract & sym
|
||||
char unknownN[bufferSize];
|
||||
Poincare::SerializationHelper::CodePoint(unknownN, bufferSize, UCodePointUnknown);
|
||||
float rank = symbol.childAtIndex(0).approximateWithValueForSymbol<float>(unknownN, unknownSymbolValue, ctx, Preferences::sharedPreferences()->complexFormat(),Preferences::sharedPreferences()->angleUnit());
|
||||
if (std::floor(rank) == rank && seq.hasValidExpression()) {
|
||||
if (std::floor(rank) == rank) {
|
||||
SequenceContext sqctx(ctx, sequenceStore());
|
||||
return Float<double>::Builder(seq.evaluateXYAtParameter(rank, &sqctx).x2());
|
||||
} else {
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <poincare/sum.h>
|
||||
#include <poincare/vertical_offset_layout.h>
|
||||
#include <poincare/integer.h>
|
||||
#include <poincare/rational.h>
|
||||
#include <poincare/addition.h>
|
||||
#include "../shared/poincare_helpers.h"
|
||||
#include <string.h>
|
||||
#include <apps/i18n.h>
|
||||
@@ -131,6 +133,40 @@ bool Sequence::isEmpty() {
|
||||
(type == Type::SingleRecurrence || data->initialConditionSize(1) == 0)));
|
||||
}
|
||||
|
||||
bool Sequence::badlyReferencesItself(Context * context) {
|
||||
Expression e = expressionReduced(context);
|
||||
bool value = e.hasExpression([](Expression e, const void * sequencePointer) {
|
||||
if (e.type() != ExpressionNode::Type::Sequence) {
|
||||
return false;
|
||||
}
|
||||
Sequence * seq = (Sequence *)(sequencePointer);
|
||||
const char * symbolName = static_cast<Symbol&>(e).name();
|
||||
/* symbolName is either u, v or w while seq->fullName has the extention .seq
|
||||
* at the end. Therefore we cannot use strcmp on the two strings. We just
|
||||
* want to check if the first char are identical*/
|
||||
if (strncmp(symbolName, seq->fullName(), strlen(symbolName)) == 0) {
|
||||
/* The expression of the sequence contains a reference to itself.
|
||||
* We must check if the sequence can be calculated before continuing
|
||||
* If the sequence is of explicit type, it cannot reference itself.
|
||||
* If the sequence is of SingleRecurrent type, it can be defined by:
|
||||
* u(initialRank and u(n).
|
||||
* If the sequence is of DoubleRecurrent type, it can be defined by:
|
||||
* u(initialRank), u(initialRank+1), u(n) and u(n+1).
|
||||
* In any other case, the value of the sequence cannot be computed.
|
||||
* We therefore return NAN. */
|
||||
Expression rank = e.childAtIndex(0);
|
||||
if (seq->type() == Sequence::Type::Explicit ||
|
||||
(!(rank.isIdenticalTo(Rational::Builder(seq->initialRank())) || rank.isIdenticalTo(Symbol::Builder(UCodePointUnknown))) &&
|
||||
(seq->type() == Sequence::Type::SingleRecurrence || (seq->type() == Sequence::Type::DoubleRecurrence && !(rank.isIdenticalTo(Rational::Builder(seq->initialRank()+1)) || rank.isIdenticalTo(Addition::Builder(Symbol::Builder(UCodePointUnknown), Rational::Builder(1))))))))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}, reinterpret_cast<const void *>(this));
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T Sequence::templatedApproximateAtAbscissa(T x, SequenceContext * sqctx) const {
|
||||
T n = std::round(x);
|
||||
@@ -143,7 +179,7 @@ T Sequence::templatedApproximateAtAbscissa(T x, SequenceContext * sqctx) const {
|
||||
|
||||
template<typename T>
|
||||
T Sequence::valueAtRank(int n, SequenceContext *sqctx) {
|
||||
if (n < 0) {
|
||||
if (n < 0 || badlyReferencesItself(sqctx)) {
|
||||
return NAN;
|
||||
}
|
||||
int sequenceIndex = SequenceStore::sequenceIndexForName(fullName()[0]);
|
||||
@@ -174,7 +210,6 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx, int sequenceIn
|
||||
Poincare::SerializationHelper::CodePoint(unknownN, bufferSize, UCodePointUnknown);
|
||||
|
||||
CacheContext<T> ctx = CacheContext<T>(sqctx);
|
||||
ctx.setSequenceContext(sqctx);
|
||||
// Hold values u(n), u(n-1), u(n-2), v(n), v(n-1), v(n-2)...
|
||||
T values[MaxNumberOfSequences][MaxRecurrenceDepth+1];
|
||||
|
||||
|
||||
@@ -59,7 +59,8 @@ public:
|
||||
Poincare::Layout nameLayout();
|
||||
bool isDefined() override;
|
||||
bool isEmpty() override;
|
||||
bool hasValidExpression() { return m_definition.hasValidExpression(); }
|
||||
bool hasValidExpression(Poincare::Context * context) { return m_definition.hasValidExpression() && !badlyReferencesItself(context); }
|
||||
bool badlyReferencesItself(Poincare::Context * context);
|
||||
// Approximation
|
||||
Poincare::Coordinate2D<float> evaluateXYAtParameter(float x, Poincare::Context * context) const override {
|
||||
return Poincare::Coordinate2D<float>(x, templatedApproximateAtAbscissa(x, static_cast<SequenceContext *>(context)));
|
||||
|
||||
@@ -102,7 +102,7 @@ void EquationStore::approximateSolve(Poincare::Context * context, bool shouldRep
|
||||
for (int i = 0; i <= k_maxNumberOfApproximateSolutions; i++) {
|
||||
root = PoincareHelpers::NextRoot(undevelopedExpression, m_variables[0], start, step, m_intervalApproximateSolutions[1], context);
|
||||
if (i == k_maxNumberOfApproximateSolutions) {
|
||||
m_hasMoreThanMaxNumberOfApproximateSolution = !isnan(root);
|
||||
m_hasMoreThanMaxNumberOfApproximateSolution = !std::isnan(root);
|
||||
break;
|
||||
}
|
||||
m_approximateSolutions[i] = root;
|
||||
|
||||
@@ -97,9 +97,12 @@ Expression Sequence::replaceSymbolWithExpression(const SymbolAbstract & symbol,
|
||||
}
|
||||
|
||||
Expression Sequence::shallowReduce(ExpressionNode::ReductionContext reductionContext) {
|
||||
if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined
|
||||
|| childAtIndex(0).isUndefined())
|
||||
{
|
||||
Expression e = Expression::defaultShallowReduce();
|
||||
e = e.defaultHandleUnitsInChildren();
|
||||
if (e.isUndefined()) {
|
||||
return e;
|
||||
}
|
||||
if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined) {
|
||||
return replaceWithUndefinedInPlace();
|
||||
}
|
||||
return *this;
|
||||
|
||||
Reference in New Issue
Block a user