[sequence] Add Poincare::Symbol::SpecialSymbols::UnknownN used in

Sequence
This commit is contained in:
Émilie Feral
2019-03-11 16:40:58 +01:00
parent 3cd28aac6d
commit 653bdd6cdb
33 changed files with 88 additions and 72 deletions

View File

@@ -12,6 +12,7 @@ class StorageCartesianFunctionStore : public Shared::StorageFunctionStore {
public:
Shared::ExpiringPointer<Shared::StorageCartesianFunction> modelForRecord(Ion::Storage::Record record) const { return Shared::ExpiringPointer<Shared::StorageCartesianFunction>(static_cast<Shared::StorageCartesianFunction *>(privateModelForRecord(record))); }
char symbol() const override { return Shared::StorageCartesianFunction::Symbol(); }
char unknownSymbol() const override { return Poincare::Symbol::SpecialSymbols::UnknownX; }
private:
Ion::Storage::Record::ErrorStatus addEmptyModel() override;
const char * modelExtension() const override { return Shared::GlobalContext::funcExtension; }

View File

@@ -104,6 +104,8 @@ void ListController::editExpression(int sequenceDefinition, Ion::Events::Event e
break;
}
initialText = initialTextContent;
// Replace Poincare::Symbol::SpecialSymbols::UnknownN with 'n'
replaceUnknownSymbolWithReadableSymbol(initialText);
}
App * myApp = (App *)app();
InputViewController * inputController = myApp->inputViewController();

View File

@@ -77,7 +77,7 @@ Poincare::Layout Sequence::nameLayout() {
if (m_nameLayout.isUninitialized()) {
m_nameLayout = HorizontalLayout::Builder(
CodePointLayout::Builder(fullName()[0], KDFont::SmallFont),
VerticalOffsetLayout::Builder(CodePointLayout::Builder(symbol(), KDFont::SmallFont), VerticalOffsetLayoutNode::Type::Subscript)
VerticalOffsetLayout::Builder(CodePointLayout::Builder(Symbol(), KDFont::SmallFont), VerticalOffsetLayoutNode::Type::Subscript)
);
}
return m_nameLayout;
@@ -122,7 +122,7 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const {
if (n < initialRank() || n < 0) {
return NAN;
}
char symb[] = {symbol(), 0};
const char unknownN[2] = {Poincare::Symbol::SpecialSymbols::UnknownN, 0};
CacheContext<T> ctx = CacheContext<T>(sqctx);
T un = sqctx->valueOfSequenceAtPreviousRank<T>(0, 0);
T unm1 = sqctx->valueOfSequenceAtPreviousRank<T>(0, 1);
@@ -139,7 +139,7 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const {
{
ctx.setValueForSymbol(un, unSymbol);
ctx.setValueForSymbol(vn, vnSymbol);
return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(sqctx), symb, (T)n, ctx);
return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(sqctx), unknownN, (T)n, ctx);
}
case Type::SingleRecurrence:
{
@@ -150,7 +150,7 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const {
ctx.setValueForSymbol(unm1, unSymbol);
ctx.setValueForSymbol(vn, vn1Symbol);
ctx.setValueForSymbol(vnm1, vnSymbol);
return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(sqctx), symb, (T)(n-1), ctx);
return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(sqctx), unknownN, (T)(n-1), ctx);
}
default:
{
@@ -164,7 +164,7 @@ T Sequence::approximateToNextRank(int n, SequenceContext * sqctx) const {
ctx.setValueForSymbol(unm2, unSymbol);
ctx.setValueForSymbol(vnm1, vn1Symbol);
ctx.setValueForSymbol(vnm2, vnSymbol);
return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(sqctx), symb, (T)(n-2), ctx);
return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(sqctx), unknownN, (T)(n-2), ctx);
}
}
}

View File

@@ -23,7 +23,6 @@ public:
StorageFunction(record),
m_nameLayout() {}
static char Symbol() { return 'n'; }
char symbol() const override { return Symbol(); }
void tidy() override;
// MetaData getters
Type type() const;
@@ -33,6 +32,7 @@ public:
void setInitialRank(int rank);
// Definition
Poincare::Layout definitionName() { return m_definitionHandle.name(this); }
Ion::Storage::Record::ErrorStatus setContent(const char * c) override { return editableHandle()->setContent(this, c, Symbol(), Poincare::Symbol::SpecialSymbols::UnknownN); }
// First initial condition
Poincare::Layout firstInitialConditionName() { return m_firstInitialConditionHandle.name(this); }
void firstInitialConditionText(char * buffer, size_t bufferSize) const { return m_firstInitialConditionHandle.text(this, buffer, bufferSize); }

View File

@@ -13,6 +13,7 @@ class SequenceStore : public Shared::StorageFunctionStore {
public:
using Shared::StorageFunctionStore::StorageFunctionStore;
char symbol() const override { return Sequence::Symbol(); }
char unknownSymbol() const override { return Poincare::Symbol::SpecialSymbols::UnknownN; }
/* Sequence Store hold all its Sequences in an array. The Sequence pointers
* return by modelForRecord are therefore non-expirable. We choose to return
* Sequence * instead of ExpiringPointer<Sequence>. */

View File

@@ -65,8 +65,8 @@ Layout ExpressionModelHandle::layout(const Storage::Record * record) const {
return m_layout;
}
Ion::Storage::Record::ErrorStatus ExpressionModelHandle::setContent(Ion::Storage::Record * record, const char * c, char symbol) {
Expression e = ExpressionModelHandle::BuildExpressionFromText(c, symbol);
Ion::Storage::Record::ErrorStatus ExpressionModelHandle::setContent(Ion::Storage::Record * record, const char * c, char symbol, char unknownSymbol) {
Expression e = ExpressionModelHandle::BuildExpressionFromText(c, symbol, unknownSymbol);
return setExpressionContent(record, e);
}
@@ -115,14 +115,14 @@ void ExpressionModelHandle::tidy() const {
m_circular = 0;
}
Poincare::Expression ExpressionModelHandle::BuildExpressionFromText(const char * c, char symbol) {
Poincare::Expression ExpressionModelHandle::BuildExpressionFromText(const char * c, char symbol, char unknownSymbol) {
Expression expressionToStore;
// if c = "", we want to reinit the Expression
if (c && *c != 0) {
// Compute the expression to store, without replacing symbols
expressionToStore = Expression::Parse(c);
if (!expressionToStore.isUninitialized() && symbol != 0) {
expressionToStore = expressionToStore.replaceUnknown(Symbol::Builder(symbol));
expressionToStore = expressionToStore.replaceUnknown(Symbol::Builder(symbol), Symbol::Builder(unknownSymbol));
}
}
return expressionToStore;

View File

@@ -20,7 +20,7 @@ public:
Poincare::Layout layout(const Ion::Storage::Record * record) const;
// Setters
virtual Ion::Storage::Record::ErrorStatus setContent(Ion::Storage::Record * record, const char * c, char symbol = 0);
virtual Ion::Storage::Record::ErrorStatus setContent(Ion::Storage::Record * record, const char * c, char symbol = 0, char unknownSymbol = 0);
Ion::Storage::Record::ErrorStatus setExpressionContent(Ion::Storage::Record * record, Poincare::Expression & e);
// Property
@@ -30,7 +30,7 @@ public:
virtual void tidy() const;
protected:
// Setters helper
static Poincare::Expression BuildExpressionFromText(const char * c, char symbol = 0);
static Poincare::Expression BuildExpressionFromText(const char * c, char symbol = 0, char unknownSymbol = 0);
mutable Poincare::Expression m_expression;
mutable Poincare::Layout m_layout;
private:

View File

@@ -8,10 +8,9 @@ namespace Shared {
class SingleExpressionModelHandle : public Ion::Storage::Record {
public:
SingleExpressionModelHandle(Ion::Storage::Record record);
SingleExpressionModelHandle(Ion::Storage::Record record = Ion::Storage::Record());
// Property
virtual char symbol() const { return 0; };
void text(char * buffer, size_t bufferSize) const { return handle()->text(this, buffer, bufferSize); }
Poincare::Expression expressionReduced(Poincare::Context * context) const { return handle()->expressionReduced(this, context); }
Poincare::Expression expressionClone() const { return handle()->expressionClone(this); }
@@ -30,7 +29,7 @@ public:
* behaviour but it is not true for its child classes (for example, in
* Sequence). */
virtual void tidy() { handle()->tidy(); }
virtual Ion::Storage::Record::ErrorStatus setContent(const char * c) { return editableHandle()->setContent(this, c, symbol()); }
virtual Ion::Storage::Record::ErrorStatus setContent(const char * c) { return editableHandle()->setContent(this, c); }
Ion::Storage::Record::ErrorStatus setExpressionContent(Poincare::Expression & e) { return editableHandle()->setExpressionContent(this, e); }
protected:
bool isCircularlyDefined(Poincare::Context * context) const { return handle()->isCircularlyDefined(this, context); }

View File

@@ -11,11 +11,11 @@ class StorageCartesianFunction : public StorageFunction {
public:
static void DefaultName(char buffer[], size_t bufferSize);
static char Symbol() { return 'x'; }
char symbol() const override { return Symbol(); };
static StorageCartesianFunction NewModel(Ion::Storage::Record::ErrorStatus * error, const char * baseName = nullptr);
StorageCartesianFunction(Ion::Storage::Record record = Record()) :
StorageFunction(record)
{}
Ion::Storage::Record::ErrorStatus setContent(const char * c) override { return editableHandle()->setContent(this, c, Symbol(), Poincare::Symbol::SpecialSymbols::UnknownX); }
// Derivative
bool displayDerivative() const;

View File

@@ -213,6 +213,17 @@ void StorageExpressionModelListController::reinitSelectedExpression(ExpiringPoin
selectableTableView()->reloadData();
}
void StorageExpressionModelListController::replaceUnknownSymbolWithReadableSymbol(char * text) {
size_t textLength = strlen(text);
char unknownSymb = modelStore()->unknownSymbol();
char symb = modelStore()->symbol();
for (size_t i = 0; i < textLength; i++) {
if (unknownSymb != 0 && text[i] == unknownSymb) {
text[i] = symb;
}
}
}
void StorageExpressionModelListController::editExpression(Ion::Events::Event event) {
char * initialText = nullptr;
constexpr int initialTextContentMaxSize = Constant::MaxSerializedExpressionSize;
@@ -223,12 +234,7 @@ void StorageExpressionModelListController::editExpression(Ion::Events::Event eve
model->text(initialTextContent, initialTextContentMaxSize);
initialText = initialTextContent;
// Replace Poincare::Symbol::SpecialSymbols::UnknownX with 'x'
size_t initialTextLength = strlen(initialText);
for (size_t i = 0; i < initialTextLength; i++) {
if (initialTextContent[i] == Poincare::Symbol::SpecialSymbols::UnknownX) {
initialTextContent[i] = Poincare::Symbol::k_unknownXReadableChar;
}
}
replaceUnknownSymbolWithReadableSymbol(initialTextContent);
}
inputController()->edit(this, event, this, initialText,
[](void * context, void * sender){

View File

@@ -27,6 +27,7 @@ protected:
virtual void didChangeModelsList() { resetMemoization(); }
virtual void reinitSelectedExpression(ExpiringPointer<SingleExpressionModelHandle> model);
virtual void editExpression(Ion::Events::Event event);
void replaceUnknownSymbolWithReadableSymbol(char * initialText);
virtual bool editSelectedRecordWithText(const char * text);
virtual bool removeModelRow(Ion::Storage::Record record);
virtual int modelIndexForRow(int j) { return j; }

View File

@@ -14,6 +14,8 @@ class StorageExpressionModelStore {
// TODO find better name (once we remove ExpressionModelStore?)
public:
StorageExpressionModelStore();
virtual char symbol() const { return 0; }
virtual char unknownSymbol() const { return 0; }
// Getters
// By default, the number of models is not bounded

View File

@@ -1,7 +1,6 @@
#include "storage_function.h"
#include "poincare_helpers.h"
#include <poincare/serialization_helper.h>
#include <poincare/symbol.h>
#include "poincare/src/parsing/parser.h"
#include <ion/unicode/utf8_helper.h>
#include <ion/unicode/utf8_decoder.h>
@@ -76,13 +75,13 @@ int StorageFunction::nameWithArgument(char * buffer, size_t bufferSize, char arg
}
template<typename T>
T StorageFunction::templatedApproximateAtAbscissa(T x, Poincare::Context * context) const {
T StorageFunction::templatedApproximateAtAbscissa(T x, Poincare::Context * context, char unknownSymbol) const {
if (isCircularlyDefined(context)) {
return NAN;
}
constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1;
char unknownX[bufferSize];
Poincare::SerializationHelper::CodePoint(unknownX, bufferSize, Poincare::Symbol::UnknownX);
Poincare::SerializationHelper::CodePoint(unknownX, bufferSize, unknownSymbol);
return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(context), unknownX, x, *context);
}
@@ -94,5 +93,5 @@ StorageFunction::FunctionRecordData * StorageFunction::recordData() const {
}
template float Shared::StorageFunction::templatedApproximateAtAbscissa<float>(float, Poincare::Context*) const;
template double Shared::StorageFunction::templatedApproximateAtAbscissa<double>(double, Poincare::Context*) const;
template float Shared::StorageFunction::templatedApproximateAtAbscissa<float>(float, Poincare::Context*, char) const;
template double Shared::StorageFunction::templatedApproximateAtAbscissa<double>(double, Poincare::Context*, char) const;

View File

@@ -2,6 +2,7 @@
#define SHARED_STORAGE_FUNCTION_H
#include <poincare/function.h>
#include <poincare/symbol.h>
#include "single_expression_model_handle.h"
namespace Shared {
@@ -32,10 +33,10 @@ public:
// Evaluation
virtual float evaluateAtAbscissa(float x, Poincare::Context * context) const {
return templatedApproximateAtAbscissa(x, context);
return templatedApproximateAtAbscissa(x, context, Poincare::Symbol::SpecialSymbols::UnknownX);
}
virtual double evaluateAtAbscissa(double x, Poincare::Context * context) const {
return templatedApproximateAtAbscissa(x, context);
return templatedApproximateAtAbscissa(x, context, Poincare::Symbol::SpecialSymbols::UnknownX);
}
virtual double sumBetweenBounds(double start, double end, Poincare::Context * context) const = 0;
protected:
@@ -57,7 +58,7 @@ protected:
bool m_active;
};
private:
template<typename T> T templatedApproximateAtAbscissa(T x, Poincare::Context * context) const;
template<typename T> T templatedApproximateAtAbscissa(T x, Poincare::Context * context, char unknownSymbol) const;
FunctionRecordData * recordData() const;
};

View File

@@ -19,7 +19,6 @@ public:
ExpiringPointer<StorageFunction> modelForRecord(Ion::Storage::Record record) const { return ExpiringPointer<StorageFunction>(static_cast<StorageFunction *>(privateModelForRecord(record))); }
virtual char symbol() const = 0;
};
}

View File

@@ -25,7 +25,7 @@ public:
// Properties
Type type() const override { return Type::Derivative; }
int polynomialDegree(Context & context, const char * symbolName) const override;
Expression replaceUnknown(const Symbol & symbol) override;
Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) override;
private:
// Layout

View File

@@ -168,8 +168,8 @@ public:
static constexpr int k_maxNumberOfPolynomialCoefficients = k_maxPolynomialDegree+1;
int getPolynomialReducedCoefficients(const char * symbolName, Expression coefficients[], Context & context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) { return node()->replaceSymbolWithExpression(symbol, expression); }
Expression replaceUnknown(const Symbol & symbol);
Expression defaultReplaceUnknown(const Symbol & symbol);
Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol);
Expression defaultReplaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol);
/* Complex */
static bool EncounteredComplex();

View File

@@ -116,7 +116,7 @@ public:
virtual bool isNumber() const { return false; }
virtual bool isRandom() const { return false; }
/*!*/ virtual Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression);
/*!*/ virtual Expression replaceUnknown(const Symbol & symbol);
/*!*/ virtual Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol);
/*!*/ virtual Expression setSign(Sign s, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ReductionTarget target);
virtual int polynomialDegree(Context & context, const char * symbolName) const;
/*!*/ virtual int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const;

View File

@@ -21,7 +21,7 @@ public:
// ExpressionNode
Type type() const override { return Type::Integral; }
int polynomialDegree(Context & context, const char * symbolName) const override;
Expression replaceUnknown(const Symbol & symbol) override;
Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) override;
// Complex
bool isReal(Context & context) const override { return true; }

View File

@@ -20,7 +20,7 @@ namespace ParameteredExpressionHelper {
* unknowns: for instance, we want to change f(x)=diff(cos(x),x,x) into
* f(X)=diff(cos(x),x,X), X being an unknown. ReplaceUnknownInExpression does
* that. */
Expression ReplaceUnknownInExpression(Expression e, const Symbol & symbolToReplace);
Expression ReplaceUnknownInExpression(Expression e, const Symbol & symbolToReplace, const Symbol & unknownSymbols);
};
}

View File

@@ -16,7 +16,7 @@ public:
#endif
Type type() const override { return Type::Product; }
Expression replaceUnknown(const Symbol & symbol) override;
Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) override;
private:
float emptySequenceValue() const override { return 1.0f; }

View File

@@ -16,7 +16,7 @@ public:
#endif
Type type() const override { return Type::Sum; }
Expression replaceUnknown(const Symbol & symbol) override;
Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) override;
private:
float emptySequenceValue() const override { return 0.0f; }

View File

@@ -22,7 +22,7 @@ public:
// Expression Properties
Type type() const override { return Type::Symbol; }
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression) override;
Expression replaceUnknown(const Symbol & symbol) override;
Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) override;
int polynomialDegree(Context & context, const char * symbolName) const override;
int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const override;
int getVariables(Context & context, isVariableTest isVariable, char * variables, int maxSizeVariable) const override;
@@ -43,12 +43,12 @@ public:
Evaluation<float> approximate(SinglePrecision p, Context& context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<float>(context, complexFormat, angleUnit); }
Evaluation<double> approximate(DoublePrecision p, Context& context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<double>(context, complexFormat, angleUnit); }
bool isUnknown(char unknownSymbol) const;
private:
char m_name[0]; // MUST be the last member variable
size_t nodeSize() const override { return sizeof(SymbolNode); }
template<typename T> Evaluation<T> templatedApproximate(Context& context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
bool isUnknownX() const;
};
class Symbol final : public SymbolAbstract {
@@ -58,11 +58,11 @@ class Symbol final : public SymbolAbstract {
public:
static constexpr int k_ansLength = 3;
static constexpr char k_ans[k_ansLength+1] = "ans";
static constexpr CodePoint k_unknownXReadableChar = 'x';
enum SpecialSymbols : char {
/* We can use characters from 1 to 31 as they do not correspond to usual
* characters but events as 'end of text', 'backspace'... */
UnknownX = 1 //TODO LEA make sure there is no collision with the code points
UnknownX = 1, //TODO LEA make sure there is no collision with the code points
UnknownN = 2 //TODO LEA make sure there is no collision with the code points,
};
Symbol(const SymbolNode * node) : SymbolAbstract(node) {}
static Symbol Builder(const char * name, int length) { return SymbolAbstract::Builder<Symbol, SymbolNode>(name, length); }
@@ -71,14 +71,14 @@ public:
static Expression UntypedBuilder(const char * name, size_t length, Context * context);
// Symbol properties
bool isSystemSymbol() const { return name()[0] == SpecialSymbols::UnknownX && name()[1] == 0; }
bool isSystemSymbol() const { return node()->isUnknown(Symbol::SpecialSymbols::UnknownX) || node()->isUnknown(Symbol::SpecialSymbols::UnknownN); }
static bool isSeriesSymbol(const char * c);
static bool isRegressionSymbol(const char * c);
// Expression
Expression shallowReduce(Context & context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target);
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression);
Expression replaceUnknown(const Symbol & symbol);
Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol);
int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const;
Expression shallowReplaceReplaceableSymbols(Context & context);
private:

View File

@@ -27,8 +27,8 @@ int DerivativeNode::polynomialDegree(Context & context, const char * symbolName)
return ExpressionNode::polynomialDegree(context, symbolName);
}
Expression DerivativeNode::replaceUnknown(const Symbol & symbol) {
return ParameteredExpressionHelper::ReplaceUnknownInExpression(Derivative(this), symbol);
Expression DerivativeNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) {
return ParameteredExpressionHelper::ReplaceUnknownInExpression(Derivative(this), symbol, unknownSymbol);
}
Layout DerivativeNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {

View File

@@ -336,14 +336,14 @@ int Expression::getPolynomialReducedCoefficients(const char * symbolName, Expres
return degree;
}
Expression Expression::replaceUnknown(const Symbol & symbol) {
return node()->replaceUnknown(symbol);
Expression Expression::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) {
return node()->replaceUnknown(symbol, unknownSymbol);
}
Expression Expression::defaultReplaceUnknown(const Symbol & symbol) {
Expression Expression::defaultReplaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) {
int nbChildren = numberOfChildren();
for (int i = 0; i < nbChildren; i++) {
childAtIndex(i).replaceUnknown(symbol);
childAtIndex(i).replaceUnknown(symbol, unknownSymbol);
}
return *this;
}

View File

@@ -18,8 +18,8 @@ Expression ExpressionNode::replaceSymbolWithExpression(const SymbolAbstract & sy
return Expression(this).defaultReplaceSymbolWithExpression(symbol, expression);
}
Expression ExpressionNode::replaceUnknown(const Symbol & symbol) {
return Expression(this).defaultReplaceUnknown(symbol);
Expression ExpressionNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) {
return Expression(this).defaultReplaceUnknown(symbol, unknownSymbol);
}
Expression ExpressionNode::setSign(Sign s, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ReductionTarget target) {

View File

@@ -29,8 +29,8 @@ int IntegralNode::polynomialDegree(Context & context, const char * symbolName) c
return ExpressionNode::polynomialDegree(context, symbolName);
}
Expression IntegralNode::replaceUnknown(const Symbol & symbol) {
return ParameteredExpressionHelper::ReplaceUnknownInExpression(Integral(this), symbol);
Expression IntegralNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) {
return ParameteredExpressionHelper::ReplaceUnknownInExpression(Integral(this), symbol, unknownSymbol);
}
Layout IntegralNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {

View File

@@ -5,7 +5,7 @@
namespace Poincare {
Expression ParameteredExpressionHelper::ReplaceUnknownInExpression(Expression e, const Symbol & symbolToReplace) {
Expression ParameteredExpressionHelper::ReplaceUnknownInExpression(Expression e, const Symbol & symbolToReplace, const Symbol & unknownSymbol) {
assert(!e.isUninitialized());
assert(e.type() == ExpressionNode::Type::Integral
|| e.type() == ExpressionNode::Type::Derivative
@@ -22,10 +22,10 @@ Expression ParameteredExpressionHelper::ReplaceUnknownInExpression(Expression e,
Symbol& parameterChild = static_cast<Symbol &>(child1);
if (strcmp(parameterChild.name(), symbolToReplace.name()) != 0) {
return e.defaultReplaceUnknown(symbolToReplace);
return e.defaultReplaceUnknown(symbolToReplace, unknownSymbol);
}
for (int i = 2; i < numberOfChildren; i++) {
e.childAtIndex(i).replaceUnknown(symbolToReplace);
e.childAtIndex(i).replaceUnknown(symbolToReplace, unknownSymbol);
}
return e;
}

View File

@@ -14,8 +14,8 @@ namespace Poincare {
constexpr Expression::FunctionHelper Product::s_functionHelper;
Expression ProductNode::replaceUnknown(const Symbol & symbol) {
return ParameteredExpressionHelper::ReplaceUnknownInExpression(Product(this), symbol);
Expression ProductNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) {
return ParameteredExpressionHelper::ReplaceUnknownInExpression(Product(this), symbol, unknownSymbol);
}
Layout ProductNode::createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const {

View File

@@ -14,8 +14,8 @@ namespace Poincare {
constexpr Expression::FunctionHelper Sum::s_functionHelper;
Expression SumNode::replaceUnknown(const Symbol & symbol) {
return ParameteredExpressionHelper::ReplaceUnknownInExpression(Sum(this), symbol);
Expression SumNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) {
return ParameteredExpressionHelper::ReplaceUnknownInExpression(Sum(this), symbol, unknownSymbol);
}
Layout SumNode::createSequenceLayout(Layout argumentLayout, Layout symbolLayout, Layout subscriptLayout, Layout superscriptLayout) const {

View File

@@ -14,7 +14,6 @@
namespace Poincare {
constexpr char Symbol::k_ans[];
constexpr CodePoint Symbol::k_unknownXReadableChar;
SymbolNode::SymbolNode(const char * newName, int length) : SymbolAbstractNode() {
strlcpy(const_cast<char*>(name()), newName, length+1);
@@ -24,8 +23,8 @@ Expression SymbolNode::replaceSymbolWithExpression(const SymbolAbstract & symbol
return Symbol(this).replaceSymbolWithExpression(symbol, expression);
}
Expression SymbolNode::replaceUnknown(const Symbol & symbol) {
return Symbol(this).replaceUnknown(symbol);
Expression SymbolNode::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) {
return Symbol(this).replaceUnknown(symbol, unknownSymbol);
}
int SymbolNode::polynomialDegree(Context & context, const char * symbolName) const {
@@ -67,7 +66,7 @@ int SymbolNode::getVariables(Context & context, isVariableTest isVariable, char
}
float SymbolNode::characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const {
return isUnknownX() ? NAN : 0.0f;
return isUnknown(Symbol::SpecialSymbols::UnknownX) ? NAN : 0.0f;
}
bool SymbolNode::isReal(Context & context) const {
@@ -76,8 +75,11 @@ bool SymbolNode::isReal(Context & context) const {
}
Layout SymbolNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
if (isUnknownX()) {
return CodePointLayout::Builder(Symbol::k_unknownXReadableChar);
if (isUnknown(Symbol::SpecialSymbols::UnknownX)) {
return CodePointLayout::Builder('x');
}
if (isUnknown(Symbol::SpecialSymbols::UnknownN)) {
return CodePointLayout::Builder('n');
}
// TODO return Parse(m_name).createLayout() ?
if (strcmp(m_name, "u(n)") == 0) {
@@ -145,8 +147,8 @@ Expression Symbol::UntypedBuilder(const char * name, size_t length, Context * co
return Expression();
}
bool SymbolNode::isUnknownX() const {
bool result = UTF8Helper::CodePointIs(m_name, Symbol::SpecialSymbols::UnknownX);
bool SymbolNode::isUnknown(char unknownSymbol) const {
bool result = UTF8Helper::CodePointIs(m_name, unknownSymbol);
if (result) {
assert(m_name[1] == 0);
}
@@ -193,10 +195,11 @@ Expression Symbol::replaceSymbolWithExpression(const SymbolAbstract & symbol, co
return *this;
}
Expression Symbol::replaceUnknown(const Symbol & symbol) {
Expression Symbol::replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol) {
assert(!symbol.isUninitialized());
assert(symbol.type() == ExpressionNode::Type::Symbol);
return replaceSymbolWithExpression(symbol, Symbol::Builder(SpecialSymbols::UnknownX));
assert(unknownSymbol.type() == ExpressionNode::Type::Symbol);
return replaceSymbolWithExpression(symbol, unknownSymbol);
}
int Symbol::getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const {

View File

@@ -65,6 +65,7 @@ Expression SymbolAbstract::Expand(const SymbolAbstract & symbol, Context & conte
* symbols are defined circularly. */
e = Expression::ExpressionWithoutSymbols(e, context);
if (!e.isUninitialized() && isFunction) {
// TODO: when SequenceFunction is created, we want to specify which unknown variable to replace (UnknownX or UnknownN)
e = e.replaceSymbolWithExpression(Symbol::Builder(Symbol::SpecialSymbols::UnknownX), symbol.childAtIndex(0));
}
return e;

View File

@@ -350,6 +350,7 @@ QUIZ_CASE(poincare_parser_parse_store) {
assert_raises_parsing_error("1→𝐢");
assert_raises_parsing_error("1→");
assert_raises_parsing_error("1→\1"); // UnknownX
assert_raises_parsing_error("1→\2"); // UnknownN
assert_raises_parsing_error("1→acos");
assert_raises_parsing_error("1→f(2)");
assert_raises_parsing_error("1→f(f)");