[poincare] Handle functions in replaceSymbolWithExp and similar methods

This commit is contained in:
Léa Saviot
2018-10-01 14:38:38 +02:00
committed by Émilie Feral
parent 1159d65010
commit a7a719df4a
20 changed files with 76 additions and 38 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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)) {

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;
};
}

View File

@@ -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*/

View File

@@ -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;

View File

@@ -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);
};
}

View File

@@ -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:

View File

@@ -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

View File

@@ -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:

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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())) {

View File

@@ -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);
}
}