mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-20 22:30:30 +01:00
[poincare] Clean recursive tests on expression (isApproximate, IsRandom,
IsMatrix etc)
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user