[apps/solver] Do not use symbol context if no solution found

Still replace the functions
This commit is contained in:
Léa Saviot
2020-01-17 11:10:49 +01:00
parent 844a28db7b
commit 0e64e89496
20 changed files with 97 additions and 68 deletions

View File

@@ -41,6 +41,7 @@ public:
InputViewController * inputViewController() { return &m_inputViewController; }
ViewController * solutionsControllerStack() { return &m_alternateEmptyViewController; }
ViewController * intervalController() { return &m_intervalController; }
SolutionsController * solutionsController() { return &m_solutionsController; }
void willBecomeInactive() override;
private:
App(Snapshot * snapshot);

View File

@@ -1,5 +1,7 @@
#include "equation.h"
#include <apps/shared/poincare_helpers.h>
#include <poincare/constant.h>
#include <poincare/empty_context.h>
#include <poincare/equal.h>
#include <poincare/undefined.h>
#include <poincare/unreal.h>
@@ -16,22 +18,40 @@ bool Equation::containsIComplex(Context * context) const {
return expressionClone().recursivelyMatches([](const Expression e, Context * context) { return e.type() == ExpressionNode::Type::Constant && static_cast<const Constant &>(e).isIComplex(); }, context, true);
}
Expression Equation::Model::standardForm(const Storage::Record * record, Context * context) const {
Expression Equation::Model::standardForm(const Storage::Record * record, Context * context, bool replaceFunctionsButNotSymbols) const {
if (m_standardForm.isUninitialized()) {
const Expression e = expressionReduced(record, context);
if (e.type() == ExpressionNode::Type::Unreal) {
const Expression expressionInputWithoutFunctions = Expression::ExpressionWithoutSymbols(expressionClone(record), context, replaceFunctionsButNotSymbols);
EmptyContext emptyContext;
Context * contextToUse = replaceFunctionsButNotSymbols ? &emptyContext : context;
// Reduce the expression
Expression expressionRed = expressionInputWithoutFunctions.clone();
PoincareHelpers::Simplify(&expressionRed, contextToUse, ExpressionNode::ReductionTarget::SystemForApproximation);
// simplify might return an uninitialized Expression if interrupted
if (expressionRed.isUninitialized()) {
expressionRed = expressionInputWithoutFunctions;
}
if (expressionRed.type() == ExpressionNode::Type::Unreal) {
m_standardForm = Unreal::Builder();
return m_standardForm;
}
if (e.recursivelyMatches([](const Expression e, Context * context) { return e.type() == ExpressionNode::Type::Undefined || e.type() == ExpressionNode::Type::Infinity || Expression::IsMatrix(e, context); }, context, true)) {
if (expressionRed.recursivelyMatches(
[](const Expression e, Context * context) {
return e.type() == ExpressionNode::Type::Undefined || e.type() == ExpressionNode::Type::Infinity || Expression::IsMatrix(e, context);
},
contextToUse,
true))
{
m_standardForm = Undefined::Builder();
return m_standardForm;
}
if (e.type() == ExpressionNode::Type::Equal) {
if (expressionRed.type() == ExpressionNode::Type::Equal) {
Preferences * preferences = Preferences::sharedPreferences();
m_standardForm = static_cast<const Equal&>(e).standardEquation(context, Expression::UpdatedComplexFormatWithExpressionInput(preferences->complexFormat(), expressionClone(record), context), preferences->angleUnit());
m_standardForm = static_cast<const Equal&>(expressionRed).standardEquation(contextToUse, Expression::UpdatedComplexFormatWithExpressionInput(preferences->complexFormat(), expressionInputWithoutFunctions, contextToUse), preferences->angleUnit());
} else {
assert(e.type() == ExpressionNode::Type::Rational && static_cast<const Rational&>(e).isOne());
assert(expressionRed.type() == ExpressionNode::Type::Rational && static_cast<const Rational&>(expressionRed).isOne());
// The equality was reduced which means the equality was always true.
m_standardForm = Rational::Builder(0);
}

View File

@@ -11,13 +11,13 @@ public:
bool shouldBeClearedBeforeRemove() override {
return false;
}
Poincare::Expression standardForm(Poincare::Context * context) const { return m_model.standardForm(this, context); }
Poincare::Expression standardForm(Poincare::Context * context, bool replaceFunctionsButNotSymbols) const { return m_model.standardForm(this, context, replaceFunctionsButNotSymbols); }
bool containsIComplex(Poincare::Context * context) const;
private:
class Model : public Shared::ExpressionModel {
public:
Poincare::Expression standardForm(const Ion::Storage::Record * record, Poincare::Context * context) const;
Poincare::Expression standardForm(const Ion::Storage::Record * record, Poincare::Context * context, bool replaceFunctionsButNotSymbols) const;
void tidy() const override;
private:
void * expressionAddress(const Ion::Storage::Record * record) const override;

View File

@@ -92,22 +92,22 @@ double EquationStore::approximateSolutionAtIndex(int i) {
return m_approximateSolutions[i];
}
bool EquationStore::haveMoreApproximationSolutions(Context * context) {
bool EquationStore::haveMoreApproximationSolutions(Context * context, bool solveWithoutContext) {
if (m_numberOfSolutions < k_maxNumberOfEquations) {
return false;
}
double step = (m_intervalApproximateSolutions[1]-m_intervalApproximateSolutions[0])*k_precision;
return !std::isnan(PoincareHelpers::NextRoot(modelForRecord(definedRecordAtIndex(0))->standardForm(context), m_variables[0], m_approximateSolutions[m_numberOfSolutions-1], step, m_intervalApproximateSolutions[1], context));
return !std::isnan(PoincareHelpers::NextRoot(modelForRecord(definedRecordAtIndex(0))->standardForm(context, solveWithoutContext), m_variables[0], m_approximateSolutions[m_numberOfSolutions-1], step, m_intervalApproximateSolutions[1], context));
}
void EquationStore::approximateSolve(Poincare::Context * context) {
void EquationStore::approximateSolve(Poincare::Context * context, bool shouldReplaceFuncionsButNotSymbols) {
assert(m_variables[0][0] != 0 && m_variables[1][0] == 0);
assert(m_type == Type::Monovariable);
m_numberOfSolutions = 0;
double start = m_intervalApproximateSolutions[0];
double step = (m_intervalApproximateSolutions[1]-m_intervalApproximateSolutions[0])*k_precision;
for (int i = 0; i < k_maxNumberOfApproximateSolutions; i++) {
m_approximateSolutions[i] = PoincareHelpers::NextRoot(modelForRecord(definedRecordAtIndex(0))->standardForm(context), m_variables[0], start, step, m_intervalApproximateSolutions[1], context);
m_approximateSolutions[i] = PoincareHelpers::NextRoot(modelForRecord(definedRecordAtIndex(0))->standardForm(context, shouldReplaceFuncionsButNotSymbols), m_variables[0], start, step, m_intervalApproximateSolutions[1], context);
if (std::isnan(m_approximateSolutions[i])) {
break;
} else {
@@ -117,14 +117,14 @@ void EquationStore::approximateSolve(Poincare::Context * context) {
}
}
EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) {
EquationStore::Error EquationStore::exactSolve(Poincare::Context * context, bool replaceFunctionsButNotSymbols) {
tidySolution();
// Step 0. Get unknown variables
m_variables[0][0] = 0;
int numberOfVariables = 0;
for (int i = 0; i < numberOfDefinedModels(); i++) {
const Expression e = modelForRecord(definedRecordAtIndex(i))->standardForm(context);
const Expression e = modelForRecord(definedRecordAtIndex(i))->standardForm(context, replaceFunctionsButNotSymbols);
if (e.isUninitialized() || e.type() == ExpressionNode::Type::Undefined) {
return Error::EquationUndefined;
}
@@ -149,7 +149,7 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) {
bool isLinear = true; // Invalid the linear system if one equation is non-linear
Preferences * preferences = Preferences::sharedPreferences();
for (int i = 0; i < numberOfDefinedModels(); i++) {
isLinear = isLinear && modelForRecord(definedRecordAtIndex(i))->standardForm(context).getLinearCoefficients((char *)m_variables, Poincare::SymbolAbstract::k_maxNameSize, coefficients[i], &constants[i], context, updatedComplexFormat(context), preferences->angleUnit());
isLinear = isLinear && modelForRecord(definedRecordAtIndex(i))->standardForm(context, replaceFunctionsButNotSymbols).getLinearCoefficients((char *)m_variables, Poincare::SymbolAbstract::k_maxNameSize, coefficients[i], &constants[i], context, updatedComplexFormat(context), preferences->angleUnit());
if (!isLinear) {
// TODO: should we clean pool allocated memory if the system is not linear
#if 0
@@ -180,7 +180,7 @@ EquationStore::Error EquationStore::exactSolve(Poincare::Context * context) {
// Step 2. Polynomial & Monovariable?
assert(numberOfVariables == 1 && numberOfDefinedModels() == 1);
Expression polynomialCoefficients[Expression::k_maxNumberOfPolynomialCoefficients];
int degree = modelForRecord(definedRecordAtIndex(0))->standardForm(context).getPolynomialReducedCoefficients(m_variables[0], polynomialCoefficients, context, updatedComplexFormat(context), preferences->angleUnit());
int degree = modelForRecord(definedRecordAtIndex(0))->standardForm(context, replaceFunctionsButNotSymbols).getPolynomialReducedCoefficients(m_variables[0], polynomialCoefficients, context, updatedComplexFormat(context), preferences->angleUnit());
if (degree == 2) {
// Polynomial degree <= 2
m_type = Type::PolynomialMonovariable;

View File

@@ -42,7 +42,7 @@ public:
return m_numberOfSolutions;
}
/* Exact resolution */
Error exactSolve(Poincare::Context * context);
Error exactSolve(Poincare::Context * context, bool replaceFunctionsButNotSymbols);
/* The exact solutions are displayed in a table with 2 layouts: an exact
* Layout and an approximate layout. For example, 'sqrt(2)' and '1.414213'.
* The boolean exactLayout indicates if we want the exact layout or the
@@ -65,8 +65,8 @@ public:
double intervalBound(int index) const;
void setIntervalBound(int index, double value);
double approximateSolutionAtIndex(int i);
void approximateSolve(Poincare::Context * context);
bool haveMoreApproximationSolutions(Poincare::Context * context);
void approximateSolve(Poincare::Context * context, bool shouldReplaceFuncionsButNotSymbols);
bool haveMoreApproximationSolutions(Poincare::Context * context, bool solveWithoutContext);
void tidy() override;

View File

@@ -102,7 +102,7 @@ bool IntervalController::textFieldDidFinishEditing(TextField * textField, const
void IntervalController::buttonAction() {
StackViewController * stack = stackController();
m_equationStore->approximateSolve(textFieldDelegateApp()->localContext());
m_equationStore->approximateSolve(textFieldDelegateApp()->localContext(), App::app()->solutionsController()->shouldReplaceFuncionsButNotSymbols());
stack->push(App::app()->solutionsControllerStack(), KDColorWhite, Palette::SubTab, Palette::SubTab);
}

View File

@@ -1,6 +1,7 @@
#include "list_controller.h"
#include "app.h"
#include <poincare/code_point_layout.h>
#include <poincare/variable_context.h>
#include <assert.h>
using namespace Shared;
@@ -166,12 +167,12 @@ bool ListController::layoutFieldDidFinishEditing(LayoutField * layoutField, Poin
return true;
}
void ListController::resolveEquations() {
void ListController::resolveEquations(bool secondTry) {
if (modelStore()->numberOfDefinedModels() == 0) {
Container::activeApp()->displayWarning(I18n::Message::EnterEquation);
return;
}
EquationStore::Error e = modelStore()->exactSolve(textFieldDelegateApp()->localContext());
EquationStore::Error e = modelStore()->exactSolve(textFieldDelegateApp()->localContext(), secondTry);
switch (e) {
case EquationStore::Error::EquationUndefined:
Container::activeApp()->displayWarning(I18n::Message::UndefinedEquation);
@@ -187,14 +188,20 @@ void ListController::resolveEquations() {
return;
case EquationStore::Error::RequireApproximateSolution:
{
StackViewController * stack = stackController();
stack->push(App::app()->intervalController(), KDColorWhite, Palette::PurpleBright, Palette::PurpleBright);
App::app()->solutionsController()->setShouldReplaceFuncionsButNotSymbols(secondTry);
stackController()->push(App::app()->intervalController(), KDColorWhite, Palette::PurpleBright, Palette::PurpleBright);
return;
}
default:
{
assert(e == EquationStore::Error::NoError);
if (modelStore()->numberOfSolutions() == 0 && !secondTry) {
modelStore()->tidy();
resolveEquations(true);
return;
}
StackViewController * stack = stackController();
App::app()->solutionsController()->setShouldReplaceFuncionsButNotSymbols(secondTry);
stack->push(App::app()->solutionsControllerStack(), KDColorWhite, Palette::PurpleBright, Palette::PurpleBright);
}
}

View File

@@ -43,7 +43,7 @@ public:
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
bool layoutFieldDidFinishEditing(LayoutField * layoutField, Poincare::Layout layout, Ion::Events::Event event) override;
/* Specific to Solver */
void resolveEquations();
void resolveEquations(bool secondTry = false);
private:
constexpr static int k_maxNumberOfRows = 5; // Ion::Display::Height / Metric::StoreRowHeight = 4.8;
SelectableTableView * selectableTableView() override;

View File

@@ -75,7 +75,8 @@ SolutionsController::SolutionsController(Responder * parentResponder, EquationSt
m_equationStore(equationStore),
m_deltaCell(0.5f, 0.5f),
m_delta2Layout(),
m_contentView(this)
m_contentView(this),
m_shouldReplaceFuncionsButNotSymbols(false)
{
m_delta2Layout = HorizontalLayout::Builder(VerticalOffsetLayout::Builder(CodePointLayout::Builder('2', KDFont::SmallFont), VerticalOffsetLayoutNode::Position::Superscript), LayoutHelper::String("-4ac", 4, KDFont::SmallFont));
const char * deltaB = "Δ=b";
@@ -108,7 +109,7 @@ void SolutionsController::viewWillAppear() {
bool requireWarning = false;
if (m_equationStore->type() == EquationStore::Type::Monovariable) {
m_contentView.setWarningMessages(I18n::Message::OnlyFirstSolutionsDisplayed0, I18n::Message::OnlyFirstSolutionsDisplayed1);
requireWarning = m_equationStore->haveMoreApproximationSolutions(App::app()->localContext());
requireWarning = m_equationStore->haveMoreApproximationSolutions(App::app()->localContext(), m_shouldReplaceFuncionsButNotSymbols);
} else if (m_equationStore->type() == EquationStore::Type::PolynomialMonovariable && m_equationStore->numberOfSolutions() == 1) {
assert(Preferences::sharedPreferences()->complexFormat() == Preferences::ComplexFormat::Real);
m_contentView.setWarningMessages(I18n::Message::PolynomeHasNoRealSolution0, I18n::Message::PolynomeHasNoRealSolution1);

View File

@@ -11,6 +11,8 @@ namespace Solver {
class SolutionsController : public ViewController, public AlternateEmptyViewDefaultDelegate, public SelectableTableViewDataSource, public TableViewDataSource {
public:
SolutionsController(Responder * parentResponder, EquationStore * equationStore);
void setShouldReplaceFuncionsButNotSymbols(bool shouldReplaceFuncionsButNotSymbols) { m_shouldReplaceFuncionsButNotSymbols = shouldReplaceFuncionsButNotSymbols; }
bool shouldReplaceFuncionsButNotSymbols() const { return m_shouldReplaceFuncionsButNotSymbols; }
/* ViewController */
const char * title() override;
View * view() override;
@@ -64,6 +66,7 @@ private:
Shared::ScrollableTwoExpressionsCell m_exactValueCells[EquationStore::k_maxNumberOfExactSolutions];
EvenOddBufferTextCell m_approximateValueCells[EquationStore::k_maxNumberOfApproximateSolutions];
ContentView m_contentView;
bool m_shouldReplaceFuncionsButNotSymbols;
};
}

View File

@@ -241,7 +241,7 @@ public:
Expression mapOnMatrixFirstChild(ExpressionNode::ReductionContext reductionContext);
/* 'ExpressionWithoutSymbols' returns an uninitialized expression if it is
* circularly defined. Same convention as for 'deepReplaceReplaceableSymbols'.*/
static Expression ExpressionWithoutSymbols(Expression expressionWithSymbols, Context * context);
static Expression ExpressionWithoutSymbols(Expression expressionWithSymbols, Context * context, bool replaceFunctionsOnly = false);
Expression radianToAngleUnit(Preferences::AngleUnit angleUnit);
Expression angleUnitToRadian(Preferences::AngleUnit angleUnit);
@@ -341,8 +341,8 @@ protected:
Expression defaultReplaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression expression);
/* 'deepReplaceReplaceableSymbols' returns an uninitialized expression if it
* is circularly defined. Same convention as for 'ExpressionWithoutSymbols'.*/
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace) { return node()->deepReplaceReplaceableSymbols(context, didReplace); }
Expression defaultReplaceReplaceableSymbols(Context * context, bool * didReplace);
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) { return node()->deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly); }
Expression defaultReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly);
/* Simplification */
void beautifyAndApproximateScalar(Expression * simplifiedExpression, Expression * approximateExpression, ExpressionNode::ReductionContext userReductionContext, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit);

View File

@@ -164,7 +164,7 @@ public:
/*!*/ virtual Expression setSign(Sign s, ReductionContext reductionContext);
virtual int polynomialDegree(Context * context, const char * symbolName) const;
/*!*/ virtual int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const;
/*!*/ virtual Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace);
/*!*/ virtual Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly);
typedef bool (*isVariableTest)(const char * c);
virtual int getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const;
virtual float characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const;

View File

@@ -38,7 +38,7 @@ private:
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
// Simplification
Expression shallowReduce(ReductionContext reductionContext) override;
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace) override;
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) override;
LayoutShape leftLayoutShape() const override { return strlen(m_name) > 1 ? LayoutShape::MoreLetters : LayoutShape::OneLetter; };
LayoutShape rightLayoutShape() const override { return LayoutShape::BoundaryPunctuation; }
@@ -57,7 +57,7 @@ public:
// Simplification
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression);
Expression shallowReduce(ExpressionNode::ReductionContext reductionContext);
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace);
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly);
};
}

View File

@@ -32,7 +32,7 @@ public:
/* Simplification */
Expression shallowReduce(ReductionContext reductionContext) override;
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace) override;
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) override;
LayoutShape leftLayoutShape() const override;
/* Approximation */
@@ -68,7 +68,7 @@ public:
Expression shallowReduce(ExpressionNode::ReductionContext reductionContext);
Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression);
int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const;
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace);
Expression deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly);
private:
SymbolNode * node() const { return static_cast<SymbolNode *>(Expression::node()); }
};

View File

@@ -8,7 +8,11 @@ namespace Poincare {
class VariableContext : public ContextWithParent {
public:
VariableContext(const char * name, Context * parentContext);
VariableContext(const char * name, Context * parentContext) :
ContextWithParent(parentContext),
m_name(name),
m_value()
{}
template<typename T>
void setApproximationForVariable(T value);

View File

@@ -379,10 +379,10 @@ void Expression::defaultSetChildrenInPlace(Expression other) {
}
}
Expression Expression::defaultReplaceReplaceableSymbols(Context * context, bool * didReplace) {
Expression Expression::defaultReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) {
int nbChildren = numberOfChildren();
for (int i = 0; i < nbChildren; i++) {
Expression c = childAtIndex(i).deepReplaceReplaceableSymbols(context, didReplace);
Expression c = childAtIndex(i).deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly);
if (c.isUninitialized()) { // the expression is circularly defined, escape
return Expression();
}
@@ -692,7 +692,7 @@ void Expression::simplifyAndApproximate(Expression * simplifiedExpression, Expre
}
}
Expression Expression::ExpressionWithoutSymbols(Expression e, Context * context) {
Expression Expression::ExpressionWithoutSymbols(Expression e, Context * context, bool replaceFunctionsOnly) {
if (e.isUninitialized()) {
return e;
}
@@ -717,7 +717,7 @@ Expression Expression::ExpressionWithoutSymbols(Expression e, Context * context)
break;
}
didReplace = false;
e = e.deepReplaceReplaceableSymbols(context, &didReplace);
e = e.deepReplaceReplaceableSymbols(context, &didReplace, replaceFunctionsOnly);
if (e.isUninitialized()) { // the expression is circularly defined, escape
replacementCount = k_maxSymbolReplacementsCount;
}

View File

@@ -36,20 +36,20 @@ int ExpressionNode::getPolynomialCoefficients(Context * context, const char * sy
return Expression(this).defaultGetPolynomialCoefficients(context, symbolName, coefficients);
}
Expression ExpressionNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace) {
return Expression(this).defaultReplaceReplaceableSymbols(context, didReplace);
Expression ExpressionNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) {
return Expression(this).defaultReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly);
}
int ExpressionNode::getVariables(Context * context, isVariableTest isVariable, char * variables, int maxSizeVariable) const {
int numberOfVariables = 0;
int numberOfVariables = 0;
for (ExpressionNode * c : children()) {
int n = c->getVariables(context, isVariable, variables, maxSizeVariable);
if (n < 0) {
return n;
}
numberOfVariables = n > numberOfVariables ? n : numberOfVariables;
}
return numberOfVariables;
int n = c->getVariables(context, isVariable, variables, maxSizeVariable);
if (n < 0) {
return n;
}
numberOfVariables = n > numberOfVariables ? n : numberOfVariables;
}
return numberOfVariables;
}
float ExpressionNode::characteristicXRange(Context * context, Preferences::AngleUnit angleUnit) const {

View File

@@ -65,8 +65,8 @@ Expression FunctionNode::shallowReduce(ReductionContext reductionContext) {
return Function(this).shallowReduce(reductionContext); // This uses Symbol::shallowReduce
}
Expression FunctionNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace) {
return Function(this).deepReplaceReplaceableSymbols(context, didReplace);
Expression FunctionNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) {
return Function(this).deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly);
}
Evaluation<float> FunctionNode::approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const {
@@ -130,9 +130,9 @@ Expression Function::shallowReduce(ExpressionNode::ReductionContext reductionCon
return result.deepReduce(reductionContext);
}
Expression Function::deepReplaceReplaceableSymbols(Context * context, bool * didReplace) {
Expression Function::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) {
// Replace replaceable symbols in child
Expression self = defaultReplaceReplaceableSymbols(context, didReplace);
Expression self = defaultReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly);
if (self.isUninitialized()) { // if the child is circularly defined, escape
return self;
}

View File

@@ -94,8 +94,8 @@ Expression SymbolNode::shallowReduce(ReductionContext reductionContext) {
return Symbol(this).shallowReduce(reductionContext);
}
Expression SymbolNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace) {
return Symbol(this).deepReplaceReplaceableSymbols(context, didReplace);
Expression SymbolNode::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) {
return Symbol(this).deepReplaceReplaceableSymbols(context, didReplace, replaceFunctionsOnly);
}
ExpressionNode::LayoutShape SymbolNode::leftLayoutShape() const {
@@ -210,8 +210,8 @@ int Symbol::getPolynomialCoefficients(Context * context, const char * symbolName
return 0;
}
Expression Symbol::deepReplaceReplaceableSymbols(Context * context, bool * didReplace) {
if (isSystemSymbol()) {
Expression Symbol::deepReplaceReplaceableSymbols(Context * context, bool * didReplace, bool replaceFunctionsOnly) {
if (replaceFunctionsOnly || isSystemSymbol()) {
return *this;
}
Expression e = context->expressionForSymbolAbstract(*this, true);

View File

@@ -7,20 +7,13 @@
namespace Poincare {
VariableContext::VariableContext(const char * name, Context * parentContext) :
ContextWithParent(parentContext),
m_name(name),
m_value()
{
}
template<typename T>
void VariableContext::setApproximationForVariable(T value) {
m_value = Float<T>::Builder(value);
}
void VariableContext::setExpressionForSymbolAbstract(const Expression & expression, const SymbolAbstract & symbol) {
if (strcmp(symbol.name(), m_name) == 0) {
if (m_name != nullptr && strcmp(symbol.name(), m_name) == 0) {
assert(symbol.type() == ExpressionNode::Type::Symbol);
if (expression.isUninitialized()) {
return;
@@ -32,7 +25,7 @@ void VariableContext::setExpressionForSymbolAbstract(const Expression & expressi
}
const Expression VariableContext::expressionForSymbolAbstract(const SymbolAbstract & symbol, bool clone) {
if (strcmp(symbol.name(), m_name) == 0) {
if (m_name != nullptr && strcmp(symbol.name(), m_name) == 0) {
if (symbol.type() == ExpressionNode::Type::Symbol) {
return clone ? m_value.clone() : m_value;
}