mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-19 05:40:38 +01:00
[sequence] Add Poincare::Symbol::SpecialSymbols::UnknownN used in
Sequence
This commit is contained in:
@@ -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; }
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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>. */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)");
|
||||
|
||||
Reference in New Issue
Block a user