[poincare] Allow replacement of sequences by their definition if rank is an integer

This commit is contained in:
Laury
2022-02-24 18:05:30 +01:00
parent c7516f1464
commit 23af100ed5
9 changed files with 153 additions and 10 deletions

View File

@@ -124,7 +124,7 @@ void MathVariableBoxController::willDisplayCellForIndex(HighlightCell * cell, in
symbolName,
Shared::Sequence::k_maxNameWithArgumentSize
);
Expression symbolExpression = Expression::ParseAndSimplify(symbolName, AppsContainer::sharedAppsContainer()->globalContext(), Poincare::Preferences::sharedPreferences()->complexFormat(), Poincare::Preferences::sharedPreferences()->angleUnit(), GlobalPreferences::sharedGlobalPreferences()->unitFormat());
Expression symbolExpression = Expression::Parse(symbolName, AppsContainer::sharedAppsContainer()->globalContext());
symbolLayout = symbolExpression.createLayout(Poincare::Preferences::sharedPreferences()->displayMode(), Poincare::Preferences::sharedPreferences()->numberOfSignificantDigits());
}
if (symbolLayout.isUninitialized()) {

View File

@@ -28,7 +28,7 @@ public:
static constexpr char funcExtension[] = "func";
static constexpr char seqExtension[] = "seq";
class Record {
class Record {
/* A Record is identified by the CRC32 on its fullName because:
* - A record is identified by its fullName, which is unique
* - We cannot keep the address pointing to the fullName because if another

View File

@@ -16,7 +16,8 @@ public:
None,
Function,
Sequence,
Symbol
Symbol,
Integer // Used to simplify sequences
};
virtual SymbolAbstractType expressionTypeForIdentifier(const char * identifier, int length) = 0;
virtual const Expression expressionForSymbolAbstract(const SymbolAbstract & symbol, bool clone, float unknownSymbolValue = NAN) = 0;

View File

@@ -0,0 +1,24 @@
#ifndef POINCARE_INTEGER_VARIABLE_CONTEXT_H
#define POINCARE_INTEGER_VARIABLE_CONTEXT_H
#include <poincare/context_with_parent.h>
#include <poincare/float.h>
namespace Poincare {
class IntegerVariableContext : public ContextWithParent {
public:
IntegerVariableContext(const char * name, Context * parentContext) :
ContextWithParent(parentContext),
m_name(name)
{}
SymbolAbstractType expressionTypeForIdentifier(const char * identifier, int length) override { return strcmp(m_name, identifier) == 0 ? SymbolAbstractType::Integer : ContextWithParent::expressionTypeForIdentifier(identifier, length); }
private:
const char * m_name;
};
}
#endif

View File

@@ -18,6 +18,7 @@ public:
#endif
Type type() const override { return Type::Sequence; }
virtual Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) override;
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) override;
int simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted, bool ignoreParentheses) const override;
@@ -46,6 +47,7 @@ public:
static Sequence Builder(const char * name, size_t length, Expression child = Expression());
// Simplification
Expression replacedByDefinitionIfPossible(Context * reductionContext);
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression);
Expression shallowReduce(ExpressionNode::ReductionContext reductionContext);
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount);

View File

@@ -10,6 +10,8 @@ namespace Poincare {
class SumAndProductNode : public ParameteredExpressionNode {
public:
int numberOfChildren() const override { return 4; }
virtual void deepReduceChildren(ReductionContext reductionContext) override;
virtual Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) override;
private:
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
virtual Layout createSumAndProductLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const = 0;
@@ -28,6 +30,7 @@ private:
class SumAndProduct : public Expression {
public:
SumAndProduct(const SumAndProductNode * n) : Expression(n) {}
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount);
Expression shallowReduce(Context * context);
};

View File

@@ -133,7 +133,7 @@ Expression Function::shallowReduce(ExpressionNode::ReductionContext reductionCon
Expression Function::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) {
{
// Replace replaceable symbols in child
Expression self = defaultReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly ,parameteredAncestorsCount);
Expression self = defaultReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly, parameteredAncestorsCount);
if (self.isUninitialized()) { // if the child is circularly defined, escape
return self;
}

View File

@@ -9,6 +9,10 @@
#include <poincare/parenthesis.h>
#include <poincare/complex.h>
#include <apps/shared/sequence.h>
#include <poincare/context.h>
#include <poincare/rational.h>
#include <poincare/undefined.h>
#include <ion/storage.h>
namespace Poincare {
@@ -106,19 +110,94 @@ Expression Sequence::replaceSymbolWithExpression(const SymbolAbstract & symbol,
}
Expression Sequence::shallowReduce(ExpressionNode::ReductionContext reductionContext) {
Expression e = Expression::defaultShallowReduce();
e = e.defaultHandleUnitsInChildren();
if (e.isUndefined()) {
return e;
}
if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined) {
return replaceWithUndefinedInPlace();
}
return *this;
if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::DoNotReplaceAnySymbol) {
return *this;
}
Expression result = replacedByDefinitionIfPossible(reductionContext.context());
result = Expression::ExpressionWithoutSymbols(result, reductionContext.context());
if (result.isUninitialized()) {
return *this;
}
replaceWithInPlace(result);
// We simplify the expression entered by the user
return result.deepReduce(reductionContext);
}
Expression SequenceNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) {
return Sequence(this).deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly, parameteredAncestorsCount);
}
Expression Sequence::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) {
{
// Replace replaceable symbols in child
Expression self = defaultReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly, parameteredAncestorsCount);
if (self.isUninitialized()) { // if the child is circularly defined, escape
return self;
}
assert(*this == self);
}
Expression e = replacedByDefinitionIfPossible(context);
if (e.isUninitialized()) {
return *this;
}
// If the function contains itself, return undefined
if (e.hasExpression([](Expression e, const void * context) {
if (e.type() != ExpressionNode::Type::Sequence) {
return false;
}
return strcmp(static_cast<Sequence&>(e).name(), reinterpret_cast<const char *>(context)) == 0;
}, reinterpret_cast<const void *>(name())))
{
return Expression();
}
replaceWithInPlace(e);
*didReplace = true;
return e;
return *this;
}
Expression Sequence::replacedByDefinitionIfPossible(Context * context) {
// We try to replace the sequence by his definition ONLY if the index is an integer
bool canBeReplacedByExpression = false;
if (childAtIndex(0).type() == ExpressionNode::Type::Symbol) {
const char * symbolName = (childAtIndex(0).convert<SymbolAbstract>()).name();
if (context->expressionTypeForIdentifier(symbolName, strlen(symbolName)) == Context::SymbolAbstractType::Integer) {
canBeReplacedByExpression = true;
}
} else if (childAtIndex(0).type() == ExpressionNode::Type::Rational) {
Rational r = childAtIndex(0).convert<Rational>();
if (r.isInteger()) {
canBeReplacedByExpression = true;
}
}
if (!canBeReplacedByExpression) {
return Expression();
}
Ion::Storage::Record r = Ion::Storage::sharedStorage()->recordBaseNamedWithExtension(name(), Ion::Storage::seqExtension);
if (r.isNull()) {
return Expression();
}
Shared::Sequence seq(r);
if (seq.type() != Shared::Sequence::Type::Explicit) {
return Expression();
}
Expression result = seq.expressionClone();
return result.replaceSymbolWithExpression(Symbol::Builder(UCodePointUnknown), childAtIndex(0));
}
}

View File

@@ -2,6 +2,10 @@
#include <poincare/decimal.h>
#include <poincare/undefined.h>
#include <poincare/variable_context.h>
#include <poincare/integer_variable_context.h>
#include <poincare/sum.h>
#include <poincare/product.h>
#include <poincare/symbol.h>
extern "C" {
#include <assert.h>
#include <stdlib.h>
@@ -56,6 +60,36 @@ Evaluation<T> SumAndProductNode::templatedApproximate(ApproximationContext appro
return result;
}
Expression SumAndProductNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) {
return SumAndProduct(this).deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly, parameteredAncestorsCount);
}
Expression SumAndProduct::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly, int parameteredAncestorsCount) {
int nbChildren = numberOfChildren();
for (int i = 1; i < nbChildren; i++) {
Expression c = childAtIndex(i).deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly, parameteredAncestorsCount);
if (c.isUninitialized()) {
return Expression();
}
}
Symbol symbol = childAtIndex(1).convert<Symbol>();
IntegerVariableContext newContext = IntegerVariableContext(symbol.name(), context);
Expression c = childAtIndex(0).deepReplaceReplaceableSymbols(&newContext, didReplace, replaceFunctionsOnly, parameteredAncestorsCount);
if (c.isUninitialized()) {
return Expression();
}
return *this;
}
void SumAndProductNode::deepReduceChildren(ReductionContext reductionContext) {
SymbolNode * symbol = static_cast<SymbolNode *>(childAtIndex(1));
IntegerVariableContext newContext = IntegerVariableContext(symbol->name(), reductionContext.context());
reductionContext.setContext(&newContext);
ExpressionNode::deepReduceChildren(reductionContext);
}
Expression SumAndProduct::shallowReduce(Context * context) {
{
Expression e = Expression::defaultShallowReduce();