[poincare] Clean recursive tests on expression (isApproximate, IsRandom,

IsMatrix etc)
This commit is contained in:
Émilie Feral
2019-05-02 16:41:36 +02:00
parent 7f373a5c3c
commit cbbb827532
10 changed files with 40 additions and 64 deletions

View File

@@ -172,7 +172,7 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) {
}
if (shouldOnlyDisplayExactOutput()) {
m_displayOutput = DisplayOutput::ExactOnly;
} else if (exactOutput().recursivelyMatches([](const Expression e, Context & c, bool replaceSymbols) {
} else if (exactOutput().recursivelyMatches([](const Expression e, Context & c) {
/* If the exact result contains one of the following types, do not
* display it. */
ExpressionNode::Type t = e.type();
@@ -192,7 +192,7 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) {
} else if (strcmp(m_exactOutputText, Undefined::Name()) == 0 || strcmp(m_approximateOutputText, Unreal::Name()) == 0) {
// If the approximate result is 'unreal' or the exact result is 'undef'
m_displayOutput = DisplayOutput::ApproximateOnly;
} else if (input().isApproximate(*context) || exactOutput().isApproximate(*context)) {
} else if (input().recursivelyMatches(Expression::IsApproximate, *context) || exactOutput().recursivelyMatches(Expression::IsApproximate, *context)) {
m_displayOutput = DisplayOutput::ExactAndApproximateToggle;
} else {
m_displayOutput = DisplayOutput::ExactAndApproximate;

View File

@@ -96,10 +96,10 @@ Expression CalculationStore::ansExpression(Context * context) {
* To avoid turning 'ans->A' in '2->A->A' or '2=A->A' (which cannot be
* parsed), ans is replaced by the approximation output when any Store or
* Equal expression appears. */
bool exactOuptutInvolvesStoreEqual = lastCalculation->exactOutput().recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) {
bool exactOuptutInvolvesStoreEqual = lastCalculation->exactOutput().recursivelyMatches([](const Expression e, Context & context) {
return e.type() == ExpressionNode::Type::Store || e.type() == ExpressionNode::Type::Equal;
}, *context, false);
if (lastCalculation->input().isApproximate(*context) || exactOuptutInvolvesStoreEqual) {
if (lastCalculation->input().recursivelyMatches(Expression::IsApproximate, *context) || exactOuptutInvolvesStoreEqual) {
return lastCalculation->approximateOutput(context);
}
return lastCalculation->exactOutput();

View File

@@ -18,7 +18,7 @@ Equation::Equation(Ion::Storage::Record record) :
}
bool Equation::containsIComplex(Context * context) const {
return expressionClone().recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { return e.type() == ExpressionNode::Type::Constant && static_cast<const Constant &>(e).isIComplex(); }, *context, true);
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 {
@@ -28,7 +28,7 @@ Expression Equation::Model::standardForm(const Storage::Record * record, Context
m_standardForm = Unreal::Builder();
return m_standardForm;
}
if (e.recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { return e.type() == ExpressionNode::Type::Undefined || e.type() == ExpressionNode::Type::Infinity || Expression::IsMatrix(e, context, replaceSymbols); }, *context, true)) {
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)) {
m_standardForm = Undefined::Builder();
return m_standardForm;
}

View File

@@ -129,13 +129,14 @@ public:
bool isRationalZero() const;
bool isRationalOne() const;
bool isRandom() const { return node()->isRandom(); }
static bool IsRandom(const Expression e, Context & context, bool replaceSymbols);
typedef bool (*ExpressionTest)(const Expression e, Context & context, bool replaceSymbols);
bool recursivelyMatches(ExpressionTest test, Context & context, bool replaceSymbols) const;
bool isApproximate(Context & context) const;
bool recursivelyMatchesInfinity(Context & context) { return recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { return e.type() == ExpressionNode::Type::Infinity; }, context, true); }
static bool IsMatrix(const Expression e, Context & context, bool replaceSymbols);
bool isParameteredExpression() const { return node()->isParameteredExpression(); }
typedef bool (*ExpressionTest)(const Expression e, Context & context);
bool recursivelyMatches(ExpressionTest test, Context & context, bool replaceSymbols = true) const;
// Set of ExpressionTest that can be used with recursivelyMatches
static bool IsApproximate(const Expression e, Context & context);
static bool IsRandom(const Expression e, Context & context);
static bool IsMatrix(const Expression e, Context & context);
static bool IsInfinity(const Expression e, Context & context);
/* 'characteristicXRange' tries to assess the range on x where the expression
* (considered as a function on x) has an interesting evolution. For example,
* the period of the function on 'x' if it is periodic. If

View File

@@ -83,9 +83,13 @@ bool Expression::isRationalOne() const {
}
bool Expression::recursivelyMatches(ExpressionTest test, Context & context, bool replaceSymbols) const {
if (test(*this, context, replaceSymbols)) {
if (test(*this, context)) {
return true;
}
ExpressionNode::Type t = type();
if (replaceSymbols && (t == ExpressionNode::Type::Symbol || t == ExpressionNode::Type::Function)) {
return SymbolAbstract::matches(convert<const SymbolAbstract>(), test, context);
}
for (int i = 0; i < this->numberOfChildren(); i++) {
if (childAtIndex(i).recursivelyMatches(test, context, replaceSymbols)) {
return true;
@@ -94,57 +98,26 @@ bool Expression::recursivelyMatches(ExpressionTest test, Context & context, bool
return false;
}
bool Expression::isApproximate(Context & context) const {
return recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) {
return e.type() == ExpressionNode::Type::Decimal
|| e.type() == ExpressionNode::Type::Float
|| ((e.type() == ExpressionNode::Type::Symbol || e.type() == ExpressionNode::Type::Function)
&& replaceSymbols
&& SymbolAbstract::matches(
static_cast<const SymbolAbstract&>(e),
[](const Expression e, Context & context, bool replaceSymbols) {
return e.isApproximate(context);
},
context));
}, context, true);
bool Expression::IsApproximate(const Expression e, Context & context) {
return e.type() == ExpressionNode::Type::Decimal || e.type() == ExpressionNode::Type::Float;
}
bool Expression::IsRandom(const Expression e, Context & context, bool replaceSymbols) {
return e.isRandom()
|| ((e.type() == ExpressionNode::Type::Symbol || e.type() == ExpressionNode::Type::Function)
&& replaceSymbols
&& SymbolAbstract::matches(
static_cast<const Symbol&>(e),
[](const Expression e, Context & context, bool replaceSymbols) {
return e.recursivelyMatches(
[](const Expression e, Context & context, bool replaceSymbols) {
return Expression::IsRandom(e, context, replaceSymbols);
},
context, replaceSymbols);
},
context));
bool Expression::IsRandom(const Expression e, Context & context) {
return e.isRandom();
}
bool Expression::IsMatrix(const Expression e, Context & context, bool replaceSymbols) {
bool Expression::IsMatrix(const Expression e, Context & context) {
return e.type() == ExpressionNode::Type::Matrix
|| e.type() == ExpressionNode::Type::ConfidenceInterval
|| e.type() == ExpressionNode::Type::MatrixDimension
|| e.type() == ExpressionNode::Type::PredictionInterval
|| e.type() == ExpressionNode::Type::MatrixInverse
|| e.type() == ExpressionNode::Type::MatrixTranspose
|| e.type() == ExpressionNode::Type::MatrixIdentity
|| ((e.type() == ExpressionNode::Type::Symbol || e.type() == ExpressionNode::Type::Function)
&& replaceSymbols
&& SymbolAbstract::matches(
static_cast<const Symbol&>(e),
[](const Expression e, Context & context, bool replaceSymbols) {
return e.recursivelyMatches(
[](const Expression e, Context & context, bool replaceSymbols) {
return Expression::IsMatrix(e, context, replaceSymbols);
},
context, replaceSymbols);
},
context));
|| e.type() == ExpressionNode::Type::MatrixTranspose;
}
bool Expression::IsInfinity(const Expression e, Context & context) {
return e.type() == ExpressionNode::Type::Infinity;
}
bool containsVariables(const Expression e, char * variables, int maxVariableSize) {
@@ -192,7 +165,7 @@ bool Expression::getLinearCoefficients(char * variables, int maxVariableSize, Ex
/* degree is supposed to be 0 or 1. Otherwise, it means that equation
* is 'undefined' due to the reduction of 0*inf for example.
* (ie, x*y*inf = 0) */
assert(!recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { return e.isUndefined(); }, context, true));
assert(!recursivelyMatches([](const Expression e, Context & context) { return e.isUndefined(); }, context, true));
return false;
}
/* The equation is can be written: a_1*x+a_0 with a_1 and a_0 x-independent.
@@ -260,7 +233,7 @@ void Expression::defaultSetChildrenInPlace(Expression other) {
}
bool Expression::hasReplaceableSymbols(Context & context) const {
return recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) {
return recursivelyMatches([](const Expression e, Context & context) {
return (e.type() == ExpressionNode::Type::Symbol
&& !static_cast<const Symbol &>(e).isSystemSymbol()
&& !context.expressionForSymbol(static_cast<const Symbol &>(e), false).isUninitialized())
@@ -366,7 +339,7 @@ Preferences::ComplexFormat Expression::UpdatedComplexFormatWithTextInput(Prefere
}
Preferences::ComplexFormat Expression::UpdatedComplexFormatWithExpressionInput(Preferences::ComplexFormat complexFormat, const Expression & exp, Context & context) {
if (complexFormat == Preferences::ComplexFormat::Real && exp.recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { return e.type() == ExpressionNode::Type::Constant && static_cast<const Constant &>(e).isIComplex(); }, context, true)) {
if (complexFormat == Preferences::ComplexFormat::Real && exp.recursivelyMatches([](const Expression e, Context & context) { return e.type() == ExpressionNode::Type::Constant && static_cast<const Constant &>(e).isIComplex(); }, context, true)) {
return Preferences::ComplexFormat::Cartesian;
}
return complexFormat;
@@ -557,10 +530,12 @@ Expression Expression::reduce(Context & context, Preferences::ComplexFormat comp
Expression Expression::deepReduce(Context & context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target, bool symbolicComputation) {
#if MATRIX_EXACT_REDUCING
#else
if (IsMatrix(*this, context, true)) {
#if 0
if (IsMatrix(*this, context)) {
sSimplificationHasBeenInterrupted = true;
return *this;
}
#endif
#endif
deepReduceChildren(context, complexFormat, angleUnit, target, symbolicComputation);

View File

@@ -223,7 +223,7 @@ Expression Logarithm::simpleShallowReduce(Context & context, Preferences::Comple
replaceWithInPlace(result);
return result;
}
bool infiniteArg = c.recursivelyMatchesInfinity(context);
bool infiniteArg = c.recursivelyMatches(Expression::IsInfinity, context);
// log(x,x)->1 with x != inf and log(inf,inf) = undef
if (c.isIdenticalTo(b)) {
Expression result = infiniteArg ? Undefined::Builder().convert<Expression>() : Rational::Builder(1).convert<Expression>();
@@ -241,7 +241,7 @@ Expression Logarithm::simpleShallowReduce(Context & context, Preferences::Comple
const Rational r = static_cast<Rational &>(c);
// log(0, x) = -inf if x > 1 && x != inf || inf x < 1 || undef if x < 0
if (r.isZero()) {
bool infiniteBase = b.recursivelyMatchesInfinity(context);
bool infiniteBase = b.recursivelyMatches(Expression::IsInfinity, context);
// Special case: log(0,inf) -> undef
if (infiniteBase) {
Expression result = Undefined::Builder();

View File

@@ -450,7 +450,7 @@ Expression Multiplication::privateShallowReduce(Context & context, Preferences::
// Check that other children don't match inf
bool infiniteFactor = false;
for (int i = 1; i < numberOfChildren(); i++) {
infiniteFactor = childAtIndex(i).recursivelyMatchesInfinity(context);
infiniteFactor = childAtIndex(i).recursivelyMatches(Expression::IsInfinity, context);
if (infiniteFactor) {
break;
}

View File

@@ -384,7 +384,7 @@ Expression Power::shallowReduce(Context & context, Preferences::ComplexFormat co
}
}
// 1^x = 1 if x != ±inf
if (a.isOne() && !childAtIndex(1).recursivelyMatchesInfinity(context)) {
if (a.isOne() && !childAtIndex(1).recursivelyMatches(Expression::IsInfinity, context)) {
Expression result = Rational::Builder(1);
replaceWithInPlace(result);
return result;

View File

@@ -17,7 +17,7 @@ namespace Poincare {
void StoreNode::deepReduceChildren(Context & context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::ReductionTarget target, bool symbolicComputation) {
// Interrupt simplification if the expression stored contains a matrix
if (Expression(childAtIndex(0)).recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) { return Expression::IsMatrix(e, context, replaceSymbols); }, context, true)) {
if (Expression(childAtIndex(0)).recursivelyMatches([](const Expression e, Context & context) { return Expression::IsMatrix(e, context); }, context, true)) {
Expression::SetInterruption(true);
}
}

View File

@@ -53,7 +53,7 @@ size_t SymbolAbstract::TruncateExtension(char * dst, const char * src, size_t le
bool SymbolAbstract::matches(const SymbolAbstract & symbol, ExpressionTest test, Context & context) {
Expression e = SymbolAbstract::Expand(symbol, context, false);
return !e.isUninitialized() && test(e, context, false);
return !e.isUninitialized() && e.recursivelyMatches(test, context, false);
}
Expression SymbolAbstract::Expand(const SymbolAbstract & symbol, Context & context, bool clone) {