mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[poincare] Handle functions in replaceSymbolWithExp and similar methods
This commit is contained in:
@@ -96,7 +96,10 @@ bool App::textInputIsCorrect(const char * text) {
|
||||
return false;
|
||||
}
|
||||
Expression ansExpression = static_cast<Snapshot *>(snapshot())->calculationStore()->ansExpression(localContext());
|
||||
exp = exp.replaceSymbolWithExpression(Symbol::k_ans, ansExpression);
|
||||
{
|
||||
Symbol ansSymbol = Symbol(Symbol::k_ans, 3);
|
||||
exp = exp.replaceSymbolWithExpression(ansSymbol, ansExpression);
|
||||
}
|
||||
char buffer[Calculation::k_printedExpressionSize];
|
||||
int length = PoincareHelpers::Serialize(exp, buffer, sizeof(buffer));
|
||||
/* if the buffer is totally full, it is VERY likely that writeTextInBuffer
|
||||
|
||||
@@ -35,10 +35,13 @@ void Calculation::reset() {
|
||||
|
||||
void Calculation::setContent(const char * c, Context * context, Expression ansExpression) {
|
||||
reset();
|
||||
Expression input = Expression::parse(c).replaceSymbolWithExpression(Symbol::k_ans, ansExpression);
|
||||
/* We do not store directly the text enter by the user because we do not want
|
||||
* to keep Ans symbol in the calculation store. */
|
||||
PoincareHelpers::Serialize(input, m_inputText, sizeof(m_inputText));
|
||||
{
|
||||
Symbol ansSymbol = Symbol(Symbol::k_ans, 3);
|
||||
Expression input = Expression::parse(c).replaceSymbolWithExpression(ansSymbol, ansExpression);
|
||||
/* We do not store directly the text enter by the user because we do not want
|
||||
* to keep Ans symbol in the calculation store. */
|
||||
PoincareHelpers::Serialize(input, m_inputText, sizeof(m_inputText));
|
||||
}
|
||||
Expression exactOutput = PoincareHelpers::ParseAndSimplify(m_inputText, *context);
|
||||
PoincareHelpers::Serialize(exactOutput, m_exactOutputText, sizeof(m_exactOutputText));
|
||||
Expression approximateOutput = PoincareHelpers::Approximate<double>(exactOutput, *context);
|
||||
|
||||
@@ -48,8 +48,8 @@ public:
|
||||
const Poincare::Expression expressionForSymbol(const Poincare::Symbol & symbol) override {
|
||||
return m_parentContext->expressionForSymbol(symbol);
|
||||
}
|
||||
void setExpressionForSymbolName(const Poincare::Expression & expression, const char * symbolName, Poincare::Context & context) override {
|
||||
m_parentContext->setExpressionForSymbolName(expression, symbolName, context);
|
||||
void setExpressionForSymbol(const Poincare::Expression & expression, const Poincare::Symbol & symbol, Poincare::Context & context) override {
|
||||
m_parentContext->setExpressionForSymbol(expression, symbol, context);
|
||||
}
|
||||
template<typename T> T valueOfSequenceAtPreviousRank(int sequenceIndex, int rank) const {
|
||||
if (sizeof(T) == sizeof(float)) {
|
||||
|
||||
@@ -7,8 +7,8 @@ using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
void StoreContext::setExpressionForSymbolName(const Expression & expression, const char * symbolName, Context & context) {
|
||||
m_parentContext->setExpressionForSymbolName(expression, symbolName, context);
|
||||
void StoreContext::setExpressionForSymbol(const Expression & expression, const Symbol & symbol, Context & context) {
|
||||
m_parentContext->setExpressionForSymbol(expression, symbol, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
{}
|
||||
void setParentContext(Poincare::Context * parentContext) { m_parentContext = parentContext; }
|
||||
void setSeriesPairIndex(int j) { m_seriesPairIndex = j; }
|
||||
void setExpressionForSymbolName(const Poincare::Expression & expression, const char * symbolName, Poincare::Context & context) override;
|
||||
void setExpressionForSymbol(const Poincare::Expression & expression, const Poincare::Symbol & symbol, Poincare::Context & context) override;
|
||||
protected:
|
||||
Shared::DoublePairStore * m_store;
|
||||
int m_seriesPairIndex;
|
||||
|
||||
@@ -80,11 +80,12 @@ bool VariableBoxController::ContentViewController::handleEvent(Ion::Events::Even
|
||||
if (event == Ion::Events::Backspace && m_currentPage != Page::RootMenu) {
|
||||
if (m_currentPage == Page::Scalar) {
|
||||
const char symbolName[2] = {static_cast<char>('A'+selectedRow()), 0};
|
||||
m_context->setExpressionForSymbolName(Expression(), symbolName, *m_context);
|
||||
Symbol symbol = Symbol(symbolName, 2);
|
||||
m_context->setExpressionForSymbol(Expression(), symbol, *m_context);
|
||||
}
|
||||
if (m_currentPage == Page::Matrix) {
|
||||
const Symbol symbol("M0", 2); // FIXME: dummy variable box controller
|
||||
m_context->setExpressionForSymbolName(Expression(), symbol.name(), *m_context);
|
||||
m_context->setExpressionForSymbol(Expression(), symbol, *m_context);
|
||||
m_matrixLayouts[selectedRow()] = Layout();
|
||||
}
|
||||
m_selectableTableView.reloadData();
|
||||
|
||||
@@ -9,7 +9,7 @@ class Symbol;
|
||||
class Context {
|
||||
public:
|
||||
virtual const Expression expressionForSymbol(const Symbol & symbol) = 0;
|
||||
virtual void setExpressionForSymbolName(const Expression & expression, const char * symbolName, Context & context) = 0;
|
||||
virtual void setExpressionForSymbol(const Expression & expression, const Symbol & symbol, Context & context) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace Poincare {
|
||||
|
||||
class Context;
|
||||
class Symbol;
|
||||
|
||||
class Expression : public TreeHandle {
|
||||
friend class AbsoluteValue;
|
||||
@@ -145,7 +146,7 @@ public:
|
||||
static constexpr int k_maxPolynomialDegree = 2;
|
||||
static constexpr int k_maxNumberOfPolynomialCoefficients = k_maxPolynomialDegree+1;
|
||||
int getPolynomialReducedCoefficients(const char * symbolName, Expression coefficients[], Context & context, Preferences::AngleUnit angleUnit) const;
|
||||
Expression replaceSymbolWithExpression(const char * symbol, Expression & expression) { return node()->replaceSymbolWithExpression(symbol, expression); }
|
||||
Expression replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) { return node()->replaceSymbolWithExpression(symbol, expression); }
|
||||
|
||||
/* Comparison */
|
||||
/* isIdenticalTo is the "easy" equality, it returns true if both trees have
|
||||
@@ -233,7 +234,7 @@ private:
|
||||
template<typename U> Evaluation<U> approximateToEvaluation(Context& context, Preferences::AngleUnit angleUnit) const;
|
||||
|
||||
/* Properties */
|
||||
Expression defaultReplaceSymbolWithExpression(const char * symbol, Expression expression);
|
||||
Expression defaultReplaceSymbolWithExpression(const Symbol & symbol, const Expression expression);
|
||||
int defaultGetPolynomialCoefficients(Context & context, const char * symbol, Expression expression[]) const;
|
||||
|
||||
/* Expression roots/extrema solver*/
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace Poincare {
|
||||
/* Methods preceded by '*!*' interfere with the expression pool, which can make
|
||||
* 'this' outdated. They should only be called in a wrapper on Expression. */
|
||||
|
||||
class Symbol;
|
||||
|
||||
class ExpressionNode : public TreeNode {
|
||||
friend class AdditionNode;
|
||||
friend class DivisionNode;
|
||||
@@ -99,7 +101,7 @@ public:
|
||||
};
|
||||
virtual Sign sign() const { return Sign::Unknown; }
|
||||
virtual bool isNumber() const { return false; }
|
||||
/*!*/ virtual Expression replaceSymbolWithExpression(const char * symbol, Expression & expression);
|
||||
/*!*/ virtual Expression replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression);
|
||||
/*!*/ virtual Expression setSign(Sign s, Context & context, Preferences::AngleUnit angleUnit);
|
||||
virtual int polynomialDegree(Context & context, const char * symbolName) const;
|
||||
/*!*/ virtual int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const;
|
||||
|
||||
@@ -19,6 +19,7 @@ public:
|
||||
|
||||
// Properties
|
||||
Type type() const override { return Type::Function; }
|
||||
Expression replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) 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;
|
||||
@@ -45,6 +46,7 @@ public:
|
||||
}
|
||||
|
||||
Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit);
|
||||
Expression replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
/* The expression recorded in global context is already a expression.
|
||||
* Otherwise, we would need the context and the angle unit to evaluate it */
|
||||
const Expression expressionForSymbol(const Symbol & symbol) override;
|
||||
void setExpressionForSymbolName(const Expression & expression, const char * symbolName, Context & context) override;
|
||||
void setExpressionForSymbol(const Expression & expression, const Symbol & symbol, Context & context) override;
|
||||
static bool storageMemoryFull();
|
||||
//TODO static constexpr uint16_t k_maxNumberOfSequences = 10;
|
||||
private:
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
// Expression Properties
|
||||
Type type() const override { return Type::Symbol; }
|
||||
Sign sign() const override;
|
||||
Expression replaceSymbolWithExpression(const char * symbol, Expression & expression) override;
|
||||
Expression replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) 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;
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
|
||||
// Expression
|
||||
Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit);
|
||||
Expression replaceSymbolWithExpression(const char * symbol, Expression & expression);
|
||||
Expression replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression);
|
||||
int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const;
|
||||
|
||||
// Symbol
|
||||
|
||||
@@ -13,7 +13,7 @@ public:
|
||||
void setApproximationForVariable(T value);
|
||||
|
||||
// Context
|
||||
void setExpressionForSymbolName(const Expression & expression, const char * symbolName, Context & context) override;
|
||||
void setExpressionForSymbol(const Expression & expression, const Symbol & symbol, Context & context) override;
|
||||
const Expression expressionForSymbol(const Symbol & symbol) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -200,7 +200,7 @@ Evaluation<U> Expression::approximateToEvaluation(Context& context, Preferences:
|
||||
return node()->approximate(U(), context, angleUnit);
|
||||
}
|
||||
|
||||
Expression Expression::defaultReplaceSymbolWithExpression(const char * symbol, Expression expression) {
|
||||
Expression Expression::defaultReplaceSymbolWithExpression(const Symbol & symbol, const Expression expression) {
|
||||
for (int i = 0; i < numberOfChildren(); i++) {
|
||||
childAtIndex(i).replaceSymbolWithExpression(symbol, expression);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#include <poincare/expression_node.h>
|
||||
#include <poincare/undefined.h>
|
||||
#include <poincare/expression.h>
|
||||
#include <poincare/symbol.h>
|
||||
#include <poincare/undefined.h>
|
||||
|
||||
namespace Poincare {
|
||||
|
||||
Expression ExpressionNode::replaceSymbolWithExpression(const char * symbol, Expression & expression) {
|
||||
Expression ExpressionNode::replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) {
|
||||
return Expression(this).defaultReplaceSymbolWithExpression(symbol, expression);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
#include <poincare/function.h>
|
||||
#include <poincare/layout_helper.h>
|
||||
#include <poincare/parenthesis.h>
|
||||
#include <poincare/rational.h>
|
||||
#include <poincare/serialization_helper.h>
|
||||
#include <poincare/simplification_helper.h>
|
||||
#include <poincare/rational.h>
|
||||
#include <cmath>
|
||||
|
||||
namespace Poincare {
|
||||
|
||||
Expression FunctionNode::replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) {
|
||||
return Function(this).replaceSymbolWithExpression(symbol, expression);
|
||||
}
|
||||
|
||||
int FunctionNode::polynomialDegree(Context & context, const char * symbolName) const {
|
||||
Expression e = context.expressionForSymbol(Function(this));
|
||||
if (e.isUninitialized()) {
|
||||
@@ -47,7 +52,7 @@ float FunctionNode::characteristicXRange(Context & context, Preferences::AngleUn
|
||||
VariableContext FunctionNode::xContext(Context & parentContext) const {
|
||||
const char x[] = {Symbol::SpecialSymbols::UnknownX, 0};
|
||||
VariableContext xContext = VariableContext(x, &parentContext);
|
||||
xContext.setExpressionForSymbolName(Expression(childAtIndex(0)), x, xContext);
|
||||
xContext.setExpressionForSymbol(Expression(childAtIndex(0)), Symbol(x, 1), xContext);
|
||||
return xContext;
|
||||
}
|
||||
|
||||
@@ -91,4 +96,24 @@ Expression Function::shallowReduce(Context & context, Preferences::AngleUnit ang
|
||||
return Expression::defaultShallowReduce(context, angleUnit);
|
||||
}
|
||||
|
||||
Expression Function::replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) {
|
||||
// Replace the symbol in the child
|
||||
childAtIndex(0).replaceSymbolWithExpression(symbol, expression);
|
||||
if (symbol.type() == ExpressionNode::Type::Function && strcmp(name(), symbol.name()) == 0) {
|
||||
Expression value = expression.clone();
|
||||
// Replace the unknown in the new expression by the function's child
|
||||
const char x[2] = {SpecialSymbols::UnknownX, 0};
|
||||
Symbol xSymbol = Symbol(x, 1);
|
||||
Expression xValue = childAtIndex(0);
|
||||
value.replaceSymbolWithExpression(xSymbol, xValue);
|
||||
Expression p = parent();
|
||||
if (!p.isUninitialized() && p.node()->childNeedsParenthesis(value.node())) {
|
||||
value = Parenthesis(value);
|
||||
}
|
||||
replaceWithInPlace(value);
|
||||
return value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,17 +33,17 @@ const Expression GlobalContext::expressionForSymbol(const Symbol & symbol) {
|
||||
return ExpressionForRecord(RecordWithName(symbol.name()));
|
||||
}
|
||||
|
||||
void GlobalContext::setExpressionForSymbolName(const Expression & expression, const char * symbolName, Context & context) {
|
||||
void GlobalContext::setExpressionForSymbol(const Expression & expression, const Symbol & symbol, Context & context) {
|
||||
sStorageMemoryFull = false;
|
||||
/* If the new expression contains the symbol, replace it because it will be
|
||||
* destroyed afterwards (to be able to do A+2->A) */
|
||||
Ion::Storage::Record record = RecordWithName(symbolName);
|
||||
Ion::Storage::Record record = RecordWithName(symbol.name());
|
||||
Expression e = ExpressionForRecord(record);
|
||||
Expression finalExpression = expression.clone().replaceSymbolWithExpression(symbolName, e);
|
||||
Expression finalExpression = expression.clone().replaceSymbolWithExpression(symbol, e);
|
||||
// Delete any record with same name (as it is going to be overriden)
|
||||
record.destroy();
|
||||
|
||||
Ion::Storage::Record::ErrorStatus err = Ion::Storage::sharedStorage()->createRecordWithExtension(symbolName, ExtensionForExpression(finalExpression), finalExpression.addressInPool(), finalExpression.size());
|
||||
Ion::Storage::Record::ErrorStatus err = Ion::Storage::sharedStorage()->createRecordWithExtension(symbol.name(), ExtensionForExpression(symbol), finalExpression.addressInPool(), finalExpression.size());
|
||||
if (err != Ion::Storage::Record::ErrorStatus::None) {
|
||||
assert(err == Ion::Storage::Record::ErrorStatus::NotEnoughSpaceAvailable);
|
||||
sStorageMemoryFull = true;
|
||||
|
||||
@@ -34,9 +34,9 @@ template<typename T>
|
||||
Evaluation<T> StoreNode::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const {
|
||||
/* If we are here, it means that the store node was not shallowReduced.
|
||||
* Otherwise, it would have been replaced by its symbol. We thus have to
|
||||
* setExpressionForSymbolName. */
|
||||
* setExpressionForSymbol. */
|
||||
Store s(this);
|
||||
context.setExpressionForSymbolName(s.value(), s.symbol().name(), context);
|
||||
context.setExpressionForSymbol(s.value(), s.symbol(), context);
|
||||
Expression e = context.expressionForSymbol(s.symbol());
|
||||
if (e.isUninitialized()) {
|
||||
return Complex<T>::Undefined();
|
||||
@@ -45,7 +45,7 @@ Evaluation<T> StoreNode::templatedApproximate(Context& context, Preferences::Ang
|
||||
}
|
||||
|
||||
Expression Store::shallowReduce(Context & context, Preferences::AngleUnit angleUnit) {
|
||||
context.setExpressionForSymbolName(value(), symbol().name(), context);
|
||||
context.setExpressionForSymbol(value(), symbol(), context);
|
||||
Expression c1 = childAtIndex(1);
|
||||
replaceWithInPlace(c1);
|
||||
return c1.shallowReduce(context, angleUnit);
|
||||
|
||||
@@ -43,7 +43,7 @@ ExpressionNode::Sign SymbolNode::sign() const {
|
||||
return Sign::Unknown;
|
||||
}
|
||||
|
||||
Expression SymbolNode::replaceSymbolWithExpression(const char * symbol, Expression & expression) {
|
||||
Expression SymbolNode::replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) {
|
||||
return Symbol(this).replaceSymbolWithExpression(symbol, expression);
|
||||
}
|
||||
|
||||
@@ -205,8 +205,8 @@ Expression Symbol::shallowReduce(Context & context, Preferences::AngleUnit angle
|
||||
return *this;
|
||||
}
|
||||
|
||||
Expression Symbol::replaceSymbolWithExpression(const char * symbol, Expression & expression) {
|
||||
if (strcmp(name(), symbol) == 0) {
|
||||
Expression Symbol::replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) {
|
||||
if (symbol.type() == ExpressionNode::Type::Symbol && strcmp(name(), symbol.name()) == 0) {
|
||||
Expression value = expression.clone();
|
||||
Expression p = parent();
|
||||
if (!p.isUninitialized() && p.node()->childNeedsParenthesis(value.node())) {
|
||||
|
||||
@@ -18,14 +18,14 @@ void VariableContext::setApproximationForVariable(T value) {
|
||||
m_value = Float<T>(value);
|
||||
}
|
||||
|
||||
void VariableContext::setExpressionForSymbolName(const Expression & expression, const char * symbolName, Context & context) {
|
||||
if (strcmp(symbolName, m_name) == 0) {
|
||||
void VariableContext::setExpressionForSymbol(const Expression & expression, const Symbol & symbol, Context & context) {
|
||||
if (strcmp(symbol.name(), m_name) == 0) {
|
||||
if (expression.isUninitialized()) {
|
||||
return;
|
||||
}
|
||||
m_value = expression.clone();
|
||||
} else {
|
||||
m_parentContext->setExpressionForSymbolName(expression, symbolName, context);
|
||||
m_parentContext->setExpressionForSymbol(expression, symbol, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user