mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[poincare] childNeedsUserParentheses takes childIndex param
Scenario: 0+exp^0 i->b 0+exp b^0 i->b Go to VariableBox/expression -> Parentheses were not properly added when b was replaced
This commit is contained in:
committed by
EmilieNumworks
parent
1cbc40815b
commit
93832549f1
@@ -145,11 +145,11 @@ public:
|
||||
virtual bool isNumber() const { return false; }
|
||||
virtual bool isRandom() const { return false; }
|
||||
virtual bool isParameteredExpression() const { return false; }
|
||||
/* childNeedsUserParentheses checks if parentheses are required by mathematical rules:
|
||||
/* childAtIndexNeedsUserParentheses checks if parentheses are required by mathematical rules:
|
||||
* +(2,-1) --> 2+(-1)
|
||||
* *(+(2,1),3) --> (2+1)*3
|
||||
*/
|
||||
virtual bool childNeedsUserParentheses(const Expression & child) const { return false; }
|
||||
virtual bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const { return false; }
|
||||
/*!*/ virtual Expression replaceSymbolWithExpression(const SymbolAbstract & symbol, const Expression & expression);
|
||||
/*!*/ virtual Expression replaceUnknown(const Symbol & symbol, const Symbol & unknownSymbol);
|
||||
/*!*/ virtual Expression setSign(Sign s, ReductionContext reductionContext);
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
Type type() const override { return Type::Factorial; }
|
||||
Sign sign(Context * context) const override { return Sign::Positive; }
|
||||
Expression setSign(Sign s, ReductionContext reductionContext) override;
|
||||
bool childNeedsUserParentheses(const Expression & child) const override;
|
||||
bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override;
|
||||
|
||||
private:
|
||||
// Layout
|
||||
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
Sign sign(Context * context) const override;
|
||||
int polynomialDegree(Context * context, const char * symbolName) const override;
|
||||
int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const override;
|
||||
bool childNeedsUserParentheses(const Expression & child) const override;
|
||||
bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override;
|
||||
|
||||
// Approximation
|
||||
template<typename T> static Complex<T> compute(const std::complex<T> c, const std::complex<T> d, Preferences::ComplexFormat complexFormat) { return Complex<T>::Builder(c*d); }
|
||||
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
void eraseNumberOfChildren() override { m_numberOfChildren = 0; }
|
||||
|
||||
// Properties
|
||||
bool childNeedsUserParentheses(const Expression & child) const override;
|
||||
bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override;
|
||||
|
||||
// Comparison
|
||||
typedef int (*ExpressionOrder)(const ExpressionNode * e1, const ExpressionNode * e2, bool canBeInterrupted);
|
||||
|
||||
@@ -26,7 +26,7 @@ public:
|
||||
Type type() const override { return Type::Opposite; }
|
||||
int polynomialDegree(Context * context, const char * symbolName) const override;
|
||||
Sign sign(Context * context) const override;
|
||||
bool childNeedsUserParentheses(const Expression & child) const override;
|
||||
bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override;
|
||||
|
||||
// Approximation
|
||||
Evaluation<float> approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override {
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
Type type() const override { return Type::Power; }
|
||||
Sign sign(Context * context) const override;
|
||||
Expression setSign(Sign s, ReductionContext reductionContext) override;
|
||||
bool childNeedsUserParentheses(const Expression & child) const override;
|
||||
bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override;
|
||||
|
||||
int polynomialDegree(Context * context, const char * symbolName) const override;
|
||||
int getPolynomialCoefficients(Context * context, const char * symbolName, Expression coefficients[]) const override;
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
// Properties
|
||||
Type type() const override { return Type::Subtraction; }
|
||||
int polynomialDegree(Context * context, const char * symbolName) const override;
|
||||
bool childNeedsUserParentheses(const Expression & child) const override;
|
||||
bool childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const override;
|
||||
|
||||
// Approximation
|
||||
template<typename T> static Complex<T> compute(const std::complex<T> c, const std::complex<T> d, Preferences::ComplexFormat complexFormat) { return Complex<T>::Builder(c - d); }
|
||||
|
||||
@@ -250,7 +250,7 @@ void Expression::shallowAddMissingParenthesis() {
|
||||
}
|
||||
for (int i = 0; i < numberOfChildren(); i++) {
|
||||
Expression child = childAtIndex(0);
|
||||
if (node()->childNeedsUserParentheses(child)) {
|
||||
if (node()->childAtIndexNeedsUserParentheses(child, i)) {
|
||||
replaceChildAtIndexInPlace(i, Parenthesis::Builder(child));
|
||||
}
|
||||
}
|
||||
@@ -259,7 +259,7 @@ void Expression::shallowAddMissingParenthesis() {
|
||||
Expression Expression::addMissingParentheses() {
|
||||
for (int i = 0; i < numberOfChildren(); i++) {
|
||||
Expression child = childAtIndex(i).addMissingParentheses();
|
||||
if (node()->childNeedsUserParentheses(child)) {
|
||||
if (node()->childAtIndexNeedsUserParentheses(child, i)) {
|
||||
child = Parenthesis::Builder(child);
|
||||
}
|
||||
replaceChildAtIndexInPlace(i, child);
|
||||
@@ -748,7 +748,7 @@ Expression Expression::deepBeautify(ExpressionNode::ReductionContext reductionCo
|
||||
Expression child = e.childAtIndex(i);
|
||||
child = child.deepBeautify(reductionContext);
|
||||
// We add missing Parentheses after beautifying the parent and child
|
||||
if (e.node()->childNeedsUserParentheses(child)) {
|
||||
if (e.node()->childAtIndexNeedsUserParentheses(child, i)) {
|
||||
e.replaceChildAtIndexInPlace(i, Parenthesis::Builder(child));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,12 @@ Expression FactorialNode::setSign(Sign s, ReductionContext reductionContext) {
|
||||
return Factorial(this);
|
||||
}
|
||||
|
||||
bool FactorialNode::childNeedsUserParentheses(const Expression & child) const {
|
||||
bool FactorialNode::childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const {
|
||||
if (child.isNumber() && static_cast<const Number &>(child).sign() == Sign::Negative) {
|
||||
return true;
|
||||
}
|
||||
if (child.type() == Type::Conjugate) {
|
||||
return childNeedsUserParentheses(child.childAtIndex(0));
|
||||
return childAtIndexNeedsUserParentheses(child.childAtIndex(0), childIndex);
|
||||
}
|
||||
Type types[] = {Type::Subtraction, Type::Opposite, Type::Multiplication, Type::Addition};
|
||||
return child.isOfType(types, 4);
|
||||
|
||||
@@ -106,7 +106,7 @@ Expression Function::replaceSymbolWithExpression(const SymbolAbstract & symbol,
|
||||
Expression xValue = childAtIndex(0);
|
||||
value = value.replaceSymbolWithExpression(xSymbol, xValue);
|
||||
Expression p = parent();
|
||||
if (!p.isUninitialized() && p.node()->childNeedsUserParentheses(value)) {
|
||||
if (!p.isUninitialized() && p.node()->childAtIndexNeedsUserParentheses(value, p.indexOfChild(*this))) {
|
||||
value = Parenthesis::Builder(value);
|
||||
}
|
||||
replaceWithInPlace(value);
|
||||
|
||||
@@ -50,8 +50,8 @@ int MultiplicationNode::getPolynomialCoefficients(Context * context, const char
|
||||
return Multiplication(this).getPolynomialCoefficients(context, symbolName, coefficients);
|
||||
}
|
||||
|
||||
bool MultiplicationNode::childNeedsUserParentheses(const Expression & child) const {
|
||||
if (NAryExpressionNode::childNeedsUserParentheses(child)) {
|
||||
bool MultiplicationNode::childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const {
|
||||
if (NAryExpressionNode::childAtIndexNeedsUserParentheses(child, childIndex)) {
|
||||
return true;
|
||||
}
|
||||
Type types[] = {Type::Subtraction, Type::Addition};
|
||||
|
||||
@@ -7,18 +7,17 @@ extern "C" {
|
||||
|
||||
namespace Poincare {
|
||||
|
||||
bool NAryExpressionNode::childNeedsUserParentheses(const Expression & child) const {
|
||||
bool NAryExpressionNode::childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const {
|
||||
/* Expressions like "-2" require parentheses in Addition/Multiplication except
|
||||
* when they are the first operand. */
|
||||
if (((child.isNumber() && static_cast<const Number &>(child).sign() == Sign::Negative)
|
||||
|| child.type() == Type::Opposite)
|
||||
/* We use "hasAncestor" instead of "==" because child might not be the
|
||||
* direct child of the addition/multiplication [e.g. +(conj(-2), 3)] */
|
||||
&& !child.node()->hasAncestor(childAtIndex(0), true)) {
|
||||
if (childIndex != 0
|
||||
&& ((child.isNumber() && static_cast<const Number &>(child).sign() == Sign::Negative)
|
||||
|| child.type() == Type::Opposite))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (child.type() == Type::Conjugate) {
|
||||
return childNeedsUserParentheses(child.childAtIndex(0));
|
||||
return childAtIndexNeedsUserParentheses(child.childAtIndex(0), childIndex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -33,12 +33,13 @@ ExpressionNode::Sign OppositeNode::sign(Context * context) const {
|
||||
|
||||
/* Layout */
|
||||
|
||||
bool OppositeNode::childNeedsUserParentheses(const Expression & child) const {
|
||||
bool OppositeNode::childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const {
|
||||
assert(childIndex == 0);
|
||||
if (child.isNumber() && static_cast<const Number &>(child).sign() == Sign::Negative) {
|
||||
return true;
|
||||
}
|
||||
if (child.type() == Type::Conjugate) {
|
||||
return childNeedsUserParentheses(child.childAtIndex(0));
|
||||
return childAtIndexNeedsUserParentheses(child.childAtIndex(0), 0);
|
||||
}
|
||||
Type types[] = {Type::Addition, Type::Subtraction, Type::Opposite};
|
||||
return child.isOfType(types, 3);
|
||||
|
||||
@@ -99,19 +99,18 @@ bool PowerNode::isReal(Context * context) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PowerNode::childNeedsUserParentheses(const Expression & child) const {
|
||||
/* We use "hasAncestor" instead of "==" because child might not be the direct
|
||||
* child of thepower [e.g. ^(conj(+(A,B), C)] */
|
||||
if (child.node()->hasAncestor(childAtIndex(0), true)) {
|
||||
/* ^(-2.3, 4) --> (-2.3)^{4}
|
||||
* ^(2/3, 4) --> (2/3)^{4}
|
||||
*/
|
||||
bool PowerNode::childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const {
|
||||
if (childIndex == 0) {
|
||||
|
||||
if ((child.isNumber() && static_cast<const Number &>(child).sign() == Sign::Negative)
|
||||
|| (child.type() == Type::Rational && !static_cast<const Rational &>(child).isInteger())) {
|
||||
|| (child.type() == Type::Rational && !static_cast<const Rational &>(child).isInteger()))
|
||||
{
|
||||
/* ^(-2.3, 4) --> (-2.3)^{4}
|
||||
* ^(2/3, 4) --> (2/3)^{4} */
|
||||
return true;
|
||||
}
|
||||
if (child.type() == Type::Conjugate) {
|
||||
return childNeedsUserParentheses(child.childAtIndex(0));
|
||||
return childAtIndexNeedsUserParentheses(child.childAtIndex(0), childIndex);
|
||||
}
|
||||
// ^(2+3,4) --> (2+3)^{4}
|
||||
Type types[] = {Type::Power, Type::Subtraction, Type::Opposite, Type::Multiplication, Type::Division, Type::Addition};
|
||||
|
||||
@@ -23,18 +23,16 @@ int SubtractionNode::polynomialDegree(Context * context, const char * symbolName
|
||||
|
||||
// Private
|
||||
|
||||
bool SubtractionNode::childNeedsUserParentheses(const Expression & child) const {
|
||||
/* First operand of a subtraction never requires parentheses.
|
||||
* We use "hasAncestor" instead of "==" because child might not be the direct
|
||||
* child of the subtraction [e.g. 'conj(-2) - 3' ] */
|
||||
if (child.node()->hasAncestor(childAtIndex(0), true)) {
|
||||
bool SubtractionNode::childAtIndexNeedsUserParentheses(const Expression & child, int childIndex) const {
|
||||
if (childIndex == 0) {
|
||||
// First operand of a subtraction never requires parentheses
|
||||
return false;
|
||||
}
|
||||
if (child.isNumber() && static_cast<const Number &>(child).sign() == Sign::Negative) {
|
||||
return true;
|
||||
}
|
||||
if (child.type() == Type::Conjugate) {
|
||||
return childNeedsUserParentheses(child.childAtIndex(0));
|
||||
return childAtIndexNeedsUserParentheses(child.childAtIndex(0), childIndex);
|
||||
}
|
||||
Type types[] = {Type::Subtraction, Type::Opposite, Type::Addition};
|
||||
return child.isOfType(types, 3);
|
||||
|
||||
@@ -200,7 +200,7 @@ Expression Symbol::replaceSymbolWithExpression(const SymbolAbstract & symbol, co
|
||||
if (symbol.type() == ExpressionNode::Type::Symbol && strcmp(name(), symbol.name()) == 0) {
|
||||
Expression value = expression.clone();
|
||||
Expression p = parent();
|
||||
if (!p.isUninitialized() && p.node()->childNeedsUserParentheses(value)) {
|
||||
if (!p.isUninitialized() && p.node()->childAtIndexNeedsUserParentheses(value, p.indexOfChild(*this))) {
|
||||
value = Parenthesis::Builder(value);
|
||||
}
|
||||
replaceWithInPlace(value);
|
||||
|
||||
Reference in New Issue
Block a user