mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[poincare] Add NullStatus for expressions
Change-Id: Ibaba72e3e3589ba259c7b22d402e2b27937f27c1
This commit is contained in:
committed by
Émilie Feral
parent
b2945c3f8b
commit
4a3f749cc6
@@ -51,7 +51,7 @@ void MatrixListController::setExpression(Poincare::Expression e) {
|
|||||||
m_layouts[index++] = getLayoutFromExpression(determinant, context, preferences);
|
m_layouts[index++] = getLayoutFromExpression(determinant, context, preferences);
|
||||||
// 2. Matrix inverse if invertible matrix
|
// 2. Matrix inverse if invertible matrix
|
||||||
// A squared matrix is invertible if and only if determinant is non null
|
// A squared matrix is invertible if and only if determinant is non null
|
||||||
if (!determinant.isUndefined() && !determinant.isNumberZero()) {
|
if (!determinant.isUndefined() && determinant.nullStatus(context) != ExpressionNode::NullStatus::Null) {
|
||||||
m_indexMessageMap[index] = messageIndex++;
|
m_indexMessageMap[index] = messageIndex++;
|
||||||
m_layouts[index++] = getLayoutFromExpression(MatrixInverse::Builder(m_expression.clone()), context, preferences);
|
m_layouts[index++] = getLayoutFromExpression(MatrixInverse::Builder(m_expression.clone()), context, preferences);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -316,12 +316,13 @@ EquationStore::Error EquationStore::resolveLinearSystem(Expression exactSolution
|
|||||||
for (int j = m-1; j >= 0; j--) {
|
for (int j = m-1; j >= 0; j--) {
|
||||||
bool rowWithNullCoefficients = true;
|
bool rowWithNullCoefficients = true;
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
if (!Ab.matrixChild(j, i).isNumberZero()) {
|
if (Ab.matrixChild(j, i).nullStatus(context) != ExpressionNode::NullStatus::Null) {
|
||||||
rowWithNullCoefficients = false;
|
rowWithNullCoefficients = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rowWithNullCoefficients && !Ab.matrixChild(j, n).isNumberZero()) {
|
if (rowWithNullCoefficients && Ab.matrixChild(j, n).nullStatus(context) != ExpressionNode::NullStatus::Null) {
|
||||||
|
// TODO: Handle ExpressionNode::NullStatus::Unknown
|
||||||
m_numberOfSolutions = 0;
|
m_numberOfSolutions = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -348,11 +349,12 @@ EquationStore::Error EquationStore::oneDimensialPolynomialSolve(Expression exact
|
|||||||
if (delta.isUninitialized()) {
|
if (delta.isUninitialized()) {
|
||||||
delta = Poincare::Undefined::Builder();
|
delta = Poincare::Undefined::Builder();
|
||||||
}
|
}
|
||||||
if (delta.isNumberZero()) {
|
if (delta.nullStatus(context) == ExpressionNode::NullStatus::Null) {
|
||||||
// if delta = 0, x0=x1= -b/(2a)
|
// if delta = 0, x0=x1= -b/(2a)
|
||||||
exactSolutions[0] = Division::Builder(Opposite::Builder(coefficients[1]), Multiplication::Builder(Rational::Builder(2), coefficients[2]));
|
exactSolutions[0] = Division::Builder(Opposite::Builder(coefficients[1]), Multiplication::Builder(Rational::Builder(2), coefficients[2]));
|
||||||
m_numberOfSolutions = 2;
|
m_numberOfSolutions = 2;
|
||||||
} else {
|
} else {
|
||||||
|
// TODO: Handle ExpressionNode::NullStatus::Unknown
|
||||||
// x0 = (-b-sqrt(delta))/(2a)
|
// x0 = (-b-sqrt(delta))/(2a)
|
||||||
exactSolutions[0] = Division::Builder(Subtraction::Builder(Opposite::Builder(coefficients[1].clone()), SquareRoot::Builder(delta.clone())), Multiplication::Builder(Rational::Builder(2), coefficients[2].clone()));
|
exactSolutions[0] = Division::Builder(Subtraction::Builder(Opposite::Builder(coefficients[1].clone()), SquareRoot::Builder(delta.clone())), Multiplication::Builder(Rational::Builder(2), coefficients[2].clone()));
|
||||||
// x1 = (-b+sqrt(delta))/(2a)
|
// x1 = (-b+sqrt(delta))/(2a)
|
||||||
@@ -383,8 +385,8 @@ EquationStore::Error EquationStore::oneDimensialPolynomialSolve(Expression exact
|
|||||||
Expression * mult5Operands[3] = {new Rational::Builder(3), a->clone(), c->clone()};
|
Expression * mult5Operands[3] = {new Rational::Builder(3), a->clone(), c->clone()};
|
||||||
Expression * delta0 = new Subtraction::Builder(new Power::Builder(b->clone(), new Rational::Builder(2), false), new Multiplication::Builder(mult5Operands, 3, false), false);
|
Expression * delta0 = new Subtraction::Builder(new Power::Builder(b->clone(), new Rational::Builder(2), false), new Multiplication::Builder(mult5Operands, 3, false), false);
|
||||||
Reduce(&delta0, *context);
|
Reduce(&delta0, *context);
|
||||||
if (delta->isNumberZero()) {
|
if (delta->nullStatus(context) == ExpressionNode::NullStatus::Null) {
|
||||||
if (delta0->isNumberZero()) {
|
if (delta0->nullStatus(context) == ExpressionNode::NullStatus::Null) {
|
||||||
// delta0 = 0 && delta = 0 --> x0 = -b/(3a)
|
// delta0 = 0 && delta = 0 --> x0 = -b/(3a)
|
||||||
delete delta0;
|
delete delta0;
|
||||||
m_exactSolutions[0] = new Opposite::Builder(new Division::Builder(b, new Multiplication::Builder(new Rational::Builder(3), a, false), false), false);
|
m_exactSolutions[0] = new Opposite::Builder(new Division::Builder(b, new Multiplication::Builder(new Rational::Builder(3), a, false), false), false);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public:
|
|||||||
// Expression subclassing
|
// Expression subclassing
|
||||||
Type type() const override { return Type::BasedInteger; }
|
Type type() const override { return Type::BasedInteger; }
|
||||||
Sign sign(Context * context) const override { return Sign::Positive; }
|
Sign sign(Context * context) const override { return Sign::Positive; }
|
||||||
bool isNumberZero() const override { return integer().isZero(); }
|
NullStatus nullStatus(Context * context) const override { return integer().isZero() ? NullStatus::Null : NullStatus::NonNull; }
|
||||||
|
|
||||||
// Layout
|
// Layout
|
||||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public:
|
|||||||
// Expression Properties
|
// Expression Properties
|
||||||
Type type() const override { return Type::Constant; }
|
Type type() const override { return Type::Constant; }
|
||||||
Sign sign(Context * context) const override;
|
Sign sign(Context * context) const override;
|
||||||
|
NullStatus nullStatus(Context * context) const override { return NullStatus::NonNull; }
|
||||||
|
|
||||||
/* Layout */
|
/* Layout */
|
||||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ public:
|
|||||||
// Properties
|
// Properties
|
||||||
Type type() const override { return Type::Decimal; }
|
Type type() const override { return Type::Decimal; }
|
||||||
Sign sign(Context * context) const override { return m_negative ? Sign::Negative : Sign::Positive; }
|
Sign sign(Context * context) const override { return m_negative ? Sign::Negative : Sign::Positive; }
|
||||||
|
NullStatus nullStatus(Context * context) const override { return unsignedMantissa().isZero() ? NullStatus::Null : NullStatus::NonNull; }
|
||||||
Expression setSign(Sign s, ReductionContext reductionContext) override;
|
Expression setSign(Sign s, ReductionContext reductionContext) override;
|
||||||
bool isNumberZero() const override { return unsignedMantissa().isZero(); }
|
|
||||||
|
|
||||||
// Approximation
|
// Approximation
|
||||||
Evaluation<float> approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override {
|
Evaluation<float> approximate(SinglePrecision p, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const override {
|
||||||
|
|||||||
@@ -151,9 +151,10 @@ public:
|
|||||||
ExpressionNode::Type type() const { return node()->type(); }
|
ExpressionNode::Type type() const { return node()->type(); }
|
||||||
bool isOfType(ExpressionNode::Type * types, int length) const { return node()->isOfType(types, length); }
|
bool isOfType(ExpressionNode::Type * types, int length) const { return node()->isOfType(types, length); }
|
||||||
ExpressionNode::Sign sign(Context * context) const { return node()->sign(context); }
|
ExpressionNode::Sign sign(Context * context) const { return node()->sign(context); }
|
||||||
|
ExpressionNode::NullStatus nullStatus(Context * context) const { return node()->nullStatus(context); }
|
||||||
|
bool isStrictly(ExpressionNode::Sign s, Context * context) const { return s == node()->sign(context) && node()->nullStatus(context) == ExpressionNode::NullStatus::NonNull; }
|
||||||
bool isUndefined() const { return node()->type() == ExpressionNode::Type::Undefined || node()->type() == ExpressionNode::Type::Unreal; }
|
bool isUndefined() const { return node()->type() == ExpressionNode::Type::Undefined || node()->type() == ExpressionNode::Type::Unreal; }
|
||||||
bool isNumber() const { return node()->isNumber(); }
|
bool isNumber() const { return node()->isNumber(); }
|
||||||
bool isNumberZero() const { return node()->isNumberZero(); }
|
|
||||||
bool isRationalOne() const;
|
bool isRationalOne() const;
|
||||||
bool isRandom() const { return node()->isRandom(); }
|
bool isRandom() const { return node()->isRandom(); }
|
||||||
bool isParameteredExpression() const { return node()->isParameteredExpression(); }
|
bool isParameteredExpression() const { return node()->isParameteredExpression(); }
|
||||||
|
|||||||
@@ -156,6 +156,11 @@ public:
|
|||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
Positive = 1
|
Positive = 1
|
||||||
};
|
};
|
||||||
|
enum class NullStatus {
|
||||||
|
Unknown = -1,
|
||||||
|
NonNull = 0,
|
||||||
|
Null = 1,
|
||||||
|
};
|
||||||
|
|
||||||
class ReductionContext {
|
class ReductionContext {
|
||||||
public:
|
public:
|
||||||
@@ -186,8 +191,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
virtual Sign sign(Context * context) const { return Sign::Unknown; }
|
virtual Sign sign(Context * context) const { return Sign::Unknown; }
|
||||||
|
virtual NullStatus nullStatus(Context * context) const { return NullStatus::Unknown; }
|
||||||
virtual bool isNumber() const { return false; }
|
virtual bool isNumber() const { return false; }
|
||||||
virtual bool isNumberZero() const { return false; }
|
|
||||||
virtual bool isRandom() const { return false; }
|
virtual bool isRandom() const { return false; }
|
||||||
virtual bool isParameteredExpression() const { return false; }
|
virtual bool isParameteredExpression() const { return false; }
|
||||||
/* childAtIndexNeedsUserParentheses checks if parentheses are required by mathematical rules:
|
/* childAtIndexNeedsUserParentheses checks if parentheses are required by mathematical rules:
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ public:
|
|||||||
// Properties
|
// Properties
|
||||||
Type type() const override { return (sizeof(T) == sizeof(float)) ? Type::Float : Type::Double; }
|
Type type() const override { return (sizeof(T) == sizeof(float)) ? Type::Float : Type::Double; }
|
||||||
Sign sign(Context * context) const override { return m_value < 0 ? Sign::Negative : Sign::Positive; }
|
Sign sign(Context * context) const override { return m_value < 0 ? Sign::Negative : Sign::Positive; }
|
||||||
|
NullStatus nullStatus(Context * context) const override { return m_value == 0.0 ? NullStatus::Null : NullStatus::NonNull; }
|
||||||
Expression setSign(Sign s, ReductionContext reductionContext) override;
|
Expression setSign(Sign s, ReductionContext reductionContext) override;
|
||||||
int simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted, bool ignoreParentheses) const override;
|
int simplificationOrderSameType(const ExpressionNode * e, bool ascending, bool canBeInterrupted, bool ignoreParentheses) const override;
|
||||||
bool isNumberZero() const override { return m_value == 0.0; }
|
|
||||||
|
|
||||||
// Layout
|
// Layout
|
||||||
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public:
|
|||||||
Type type() const override { return Type::HyperbolicArcCosine; }
|
Type type() const override { return Type::HyperbolicArcCosine; }
|
||||||
private:
|
private:
|
||||||
// Simplification
|
// Simplification
|
||||||
bool isNotableValue(Expression e) const override { return e.isRationalOne(); }
|
bool isNotableValue(Expression e, Context * context) const override { return e.isRationalOne(); }
|
||||||
// Layout
|
// Layout
|
||||||
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||||
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ private:
|
|||||||
LayoutShape leftLayoutShape() const override { return LayoutShape::MoreLetters; };
|
LayoutShape leftLayoutShape() const override { return LayoutShape::MoreLetters; };
|
||||||
LayoutShape rightLayoutShape() const override { return LayoutShape::BoundaryPunctuation; }
|
LayoutShape rightLayoutShape() const override { return LayoutShape::BoundaryPunctuation; }
|
||||||
Expression shallowReduce(ReductionContext reductionContext) override;
|
Expression shallowReduce(ReductionContext reductionContext) override;
|
||||||
virtual bool isNotableValue(Expression e) const { return e.isNumberZero(); }
|
virtual bool isNotableValue(Expression e, Context * context) const { return e.nullStatus(context) == ExpressionNode::NullStatus::Null; }
|
||||||
virtual Expression imageOfNotableValue() const { return Rational::Builder(0); }
|
virtual Expression imageOfNotableValue() const { return Rational::Builder(0); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ public:
|
|||||||
// Properties
|
// Properties
|
||||||
Type type() const override { return Type::Infinity; }
|
Type type() const override { return Type::Infinity; }
|
||||||
Sign sign(Context * context) const override { return m_negative ? Sign::Negative : Sign::Positive; }
|
Sign sign(Context * context) const override { return m_negative ? Sign::Negative : Sign::Positive; }
|
||||||
|
NullStatus nullStatus(Context * context) const override { return NullStatus::NonNull; }
|
||||||
Expression setSign(Sign s, ReductionContext reductionContext) override;
|
Expression setSign(Sign s, ReductionContext reductionContext) override;
|
||||||
|
|
||||||
// Approximation
|
// Approximation
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public:
|
|||||||
bool isNegative() const { return m_negative; }
|
bool isNegative() const { return m_negative; }
|
||||||
void setNegative(bool negative) { m_negative = negative; }
|
void setNegative(bool negative) { m_negative = negative; }
|
||||||
bool isInteger() const { return denominator().isOne(); }
|
bool isInteger() const { return denominator().isOne(); }
|
||||||
bool isNumberZero() const override { return isZero(); }
|
NullStatus nullStatus(Context * context) const override { return isZero() ? NullStatus::Null : NullStatus::NonNull; }
|
||||||
|
|
||||||
// TreeNode
|
// TreeNode
|
||||||
size_t size() const override;
|
size_t size() const override;
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ Expression ComplexCartesian::shallowReduce() {
|
|||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (imag().isNumberZero()) {
|
if (imag().nullStatus(nullptr) == ExpressionNode::NullStatus::Null) {
|
||||||
Expression r = real();
|
Expression r = real();
|
||||||
replaceWithInPlace(r);
|
replaceWithInPlace(r);
|
||||||
return r;
|
return r;
|
||||||
@@ -128,9 +128,9 @@ Expression ComplexCartesian::squareNorm(ExpressionNode::ReductionContext reducti
|
|||||||
Expression ComplexCartesian::norm(ExpressionNode::ReductionContext reductionContext) {
|
Expression ComplexCartesian::norm(ExpressionNode::ReductionContext reductionContext) {
|
||||||
Expression a;
|
Expression a;
|
||||||
// Special case for pure real or pure imaginary cartesian
|
// Special case for pure real or pure imaginary cartesian
|
||||||
if (imag().isNumberZero()) {
|
if (imag().nullStatus(nullptr) == ExpressionNode::NullStatus::Null) {
|
||||||
a = real();
|
a = real();
|
||||||
} else if (real().isNumberZero()) {
|
} else if (real().nullStatus(nullptr) == ExpressionNode::NullStatus::Null) {
|
||||||
a = imag();
|
a = imag();
|
||||||
}
|
}
|
||||||
if (!a.isUninitialized()) {
|
if (!a.isUninitialized()) {
|
||||||
@@ -149,7 +149,8 @@ Expression ComplexCartesian::norm(ExpressionNode::ReductionContext reductionCont
|
|||||||
Expression ComplexCartesian::argument(ExpressionNode::ReductionContext reductionContext) {
|
Expression ComplexCartesian::argument(ExpressionNode::ReductionContext reductionContext) {
|
||||||
Expression a = real();
|
Expression a = real();
|
||||||
Expression b = imag();
|
Expression b = imag();
|
||||||
if (!b.isNumberZero()) {
|
if (b.nullStatus(reductionContext.context()) != ExpressionNode::NullStatus::Null) {
|
||||||
|
// TODO: Handle ExpressionNode::NullStatus::Unknown
|
||||||
// if b != 0, argument = sign(b) * π/2 - atan(a/b)
|
// if b != 0, argument = sign(b) * π/2 - atan(a/b)
|
||||||
// First, compute atan(a/b) or (π/180)*atan(a/b)
|
// First, compute atan(a/b) or (π/180)*atan(a/b)
|
||||||
Expression divab = Division::Builder(a, b.clone());
|
Expression divab = Division::Builder(a, b.clone());
|
||||||
@@ -242,11 +243,11 @@ ComplexCartesian ComplexCartesian::powerInteger(int n, ExpressionNode::Reduction
|
|||||||
Expression a = real();
|
Expression a = real();
|
||||||
Expression b = imag();
|
Expression b = imag();
|
||||||
assert(n > 0);
|
assert(n > 0);
|
||||||
assert(!b.isNumberZero());
|
assert(b.nullStatus(reductionContext.context()) != ExpressionNode::NullStatus::Null);
|
||||||
|
|
||||||
// Special case: a == 0 (otherwise, we are going to introduce undefined expressions - a^0 = NAN)
|
// Special case: a == 0 (otherwise, we are going to introduce undefined expressions - a^0 = NAN)
|
||||||
// (b*i)^n = b^n*i^n with i^n == i, -i, 1 or -1
|
// (b*i)^n = b^n*i^n with i^n == i, -i, 1 or -1
|
||||||
if (a.isNumberZero()) {
|
if (a.nullStatus(reductionContext.context()) == ExpressionNode::NullStatus::Null) {
|
||||||
ComplexCartesian result;
|
ComplexCartesian result;
|
||||||
Expression bpow = Power::Builder(b, Rational::Builder(n));
|
Expression bpow = Power::Builder(b, Rational::Builder(n));
|
||||||
if (n/2%2 == 1) {
|
if (n/2%2 == 1) {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ Expression HyperbolicTrigonometricFunction::shallowReduce(ExpressionNode::Reduct
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 1. Notable values
|
// Step 1. Notable values
|
||||||
if (node()->isNotableValue(c)) {
|
if (node()->isNotableValue(c, reductionContext.context())) {
|
||||||
Expression result = node()->imageOfNotableValue();
|
Expression result = node()->imageOfNotableValue();
|
||||||
replaceWithInPlace(result);
|
replaceWithInPlace(result);
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -136,7 +136,8 @@ int Matrix::rank(Context * context, Preferences::ComplexFormat complexFormat, Pr
|
|||||||
int i = rank-1;
|
int i = rank-1;
|
||||||
while (i >= 0) {
|
while (i >= 0) {
|
||||||
int j = m.numberOfColumns()-1;
|
int j = m.numberOfColumns()-1;
|
||||||
while (j >= i && matrixChild(i,j).isNumberZero()) {
|
while (j >= i && matrixChild(i,j).nullStatus(context) == ExpressionNode::NullStatus::Null) {
|
||||||
|
// TODO: Handle ExpressionNode::NullStatus::Unknown
|
||||||
j--;
|
j--;
|
||||||
}
|
}
|
||||||
if (j == i-1) {
|
if (j == i-1) {
|
||||||
@@ -225,7 +226,7 @@ Matrix Matrix::rowCanonize(ExpressionNode::ReductionContext reductionContext, Ex
|
|||||||
// Using float to find the biggest pivot is sufficient.
|
// Using float to find the biggest pivot is sufficient.
|
||||||
float pivot = AbsoluteValue::Builder(matrixChild(iPivot_temp, k).clone()).approximateToScalar<float>(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit());
|
float pivot = AbsoluteValue::Builder(matrixChild(iPivot_temp, k).clone()).approximateToScalar<float>(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit());
|
||||||
// Handle very low pivots
|
// Handle very low pivots
|
||||||
if (pivot == 0.0f && !matrixChild(iPivot_temp, k).isNumberZero()) {
|
if (pivot == 0.0f && matrixChild(iPivot_temp, k).nullStatus(reductionContext.context()) != ExpressionNode::NullStatus::Null) {
|
||||||
pivot = FLT_MIN;
|
pivot = FLT_MIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +242,8 @@ Matrix Matrix::rowCanonize(ExpressionNode::ReductionContext reductionContext, Ex
|
|||||||
}
|
}
|
||||||
iPivot_temp++;
|
iPivot_temp++;
|
||||||
}
|
}
|
||||||
if (matrixChild(iPivot, k).isNumberZero()) {
|
if (matrixChild(iPivot, k).nullStatus(reductionContext.context()) == ExpressionNode::NullStatus::Null) {
|
||||||
|
// TODO: Handle ExpressionNode::NullStatus::Unknown
|
||||||
// No non-null coefficient in this column, skip
|
// No non-null coefficient in this column, skip
|
||||||
k++;
|
k++;
|
||||||
if (determinant) {
|
if (determinant) {
|
||||||
|
|||||||
@@ -1122,27 +1122,27 @@ bool Multiplication::TermsCanSafelyCombineExponents(const Expression & e1, const
|
|||||||
|
|
||||||
Expression base = Base(e1);
|
Expression base = Base(e1);
|
||||||
ExpressionNode::Sign baseSign = base.sign(reductionContext.context());
|
ExpressionNode::Sign baseSign = base.sign(reductionContext.context());
|
||||||
|
ExpressionNode::NullStatus baseNullStatus = base.nullStatus(reductionContext.context());
|
||||||
|
|
||||||
if (baseSign != ExpressionNode::Sign::Unknown && !base.isNumberZero()) {
|
if (baseSign != ExpressionNode::Sign::Unknown && baseNullStatus == ExpressionNode::NullStatus::NonNull) {
|
||||||
// x cannot be null
|
// x cannot be null
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression exponent1 = CreateExponent(e1);
|
Expression exponent1 = CreateExponent(e1);
|
||||||
ExpressionNode::Sign exponentSign1 = exponent1.sign(reductionContext.context());
|
|
||||||
Expression exponent2 = CreateExponent(e2);
|
Expression exponent2 = CreateExponent(e2);
|
||||||
ExpressionNode::Sign exponentSign2 = exponent2.sign(reductionContext.context());
|
|
||||||
|
|
||||||
if (exponentSign1 == ExpressionNode::Sign::Positive && !exponent1.isNumberZero()
|
if (exponent1.isStrictly(ExpressionNode::Sign::Positive, reductionContext.context())
|
||||||
&& exponentSign2 == ExpressionNode::Sign::Positive && !exponent2.isNumberZero()) {
|
&& exponent2.isStrictly(ExpressionNode::Sign::Positive, reductionContext.context())) {
|
||||||
// a and b are strictly positive
|
// a and b are strictly positive
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression sum = Addition::Builder(exponent1, exponent2).shallowReduce(reductionContext);
|
Expression sum = Addition::Builder(exponent1, exponent2).shallowReduce(reductionContext);
|
||||||
ExpressionNode::Sign sumSign = sum.sign(reductionContext.context());
|
ExpressionNode::Sign sumSign = sum.sign(reductionContext.context());
|
||||||
|
ExpressionNode::NullStatus sumNullStatus = sum.nullStatus(reductionContext.context());
|
||||||
|
|
||||||
if (sumSign == ExpressionNode::Sign::Negative || sum.isNumberZero()) {
|
if (sumSign == ExpressionNode::Sign::Negative || sumNullStatus == ExpressionNode::NullStatus::Null) {
|
||||||
// a+b is negative or null
|
// a+b is negative or null
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -501,7 +501,7 @@ Expression Power::shallowReduce(ExpressionNode::ReductionContext reductionContex
|
|||||||
// x^0
|
// x^0
|
||||||
if (rationalIndex.isZero()) {
|
if (rationalIndex.isZero()) {
|
||||||
// 0^0 = undef or (±inf)^0 = undef
|
// 0^0 = undef or (±inf)^0 = undef
|
||||||
if (base.isNumberZero() || baseType == ExpressionNode::Type::Infinity) {
|
if (base.nullStatus(reductionContext.context()) == ExpressionNode::NullStatus::Null || baseType == ExpressionNode::Type::Infinity) {
|
||||||
return replaceWithUndefinedInPlace();
|
return replaceWithUndefinedInPlace();
|
||||||
}
|
}
|
||||||
// x^0
|
// x^0
|
||||||
|
|||||||
@@ -18,23 +18,24 @@ QUIZ_CASE(poincare_properties_is_number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QUIZ_CASE(poincare_properties_is_number_zero) {
|
QUIZ_CASE(poincare_properties_is_number_zero) {
|
||||||
quiz_assert(!BasedInteger::Builder("2",Integer::Base::Binary).isNumberZero());
|
Shared::GlobalContext context;
|
||||||
quiz_assert(!BasedInteger::Builder("2",Integer::Base::Decimal).isNumberZero());
|
quiz_assert(BasedInteger::Builder("2",Integer::Base::Binary).nullStatus(&context) == ExpressionNode::NullStatus::NonNull );
|
||||||
quiz_assert(!BasedInteger::Builder("2",Integer::Base::Hexadecimal).isNumberZero());
|
quiz_assert(BasedInteger::Builder("2",Integer::Base::Decimal).nullStatus(&context) == ExpressionNode::NullStatus::NonNull );
|
||||||
quiz_assert(BasedInteger::Builder("0",Integer::Base::Binary).isNumberZero());
|
quiz_assert(BasedInteger::Builder("2",Integer::Base::Hexadecimal).nullStatus(&context) == ExpressionNode::NullStatus::NonNull );
|
||||||
quiz_assert(BasedInteger::Builder("0",Integer::Base::Decimal).isNumberZero());
|
quiz_assert(BasedInteger::Builder("0",Integer::Base::Binary).nullStatus(&context) == ExpressionNode::NullStatus::Null );
|
||||||
quiz_assert(BasedInteger::Builder("0",Integer::Base::Hexadecimal).isNumberZero());
|
quiz_assert(BasedInteger::Builder("0",Integer::Base::Decimal).nullStatus(&context) == ExpressionNode::NullStatus::Null );
|
||||||
quiz_assert(!Decimal::Builder("2",3).isNumberZero());
|
quiz_assert(BasedInteger::Builder("0",Integer::Base::Hexadecimal).nullStatus(&context) == ExpressionNode::NullStatus::Null );
|
||||||
quiz_assert(Decimal::Builder("0",0).isNumberZero());
|
quiz_assert(Decimal::Builder("2",3).nullStatus(&context) == ExpressionNode::NullStatus::NonNull );
|
||||||
quiz_assert(!Float<float>::Builder(1.0f).isNumberZero());
|
quiz_assert(Decimal::Builder("0",0).nullStatus(&context) == ExpressionNode::NullStatus::Null );
|
||||||
quiz_assert(Float<float>::Builder(0.0f).isNumberZero());
|
quiz_assert(Float<float>::Builder(1.0f).nullStatus(&context) == ExpressionNode::NullStatus::NonNull );
|
||||||
quiz_assert(!Infinity::Builder(true).isNumberZero());
|
quiz_assert(Float<float>::Builder(0.0f).nullStatus(&context) == ExpressionNode::NullStatus::Null );
|
||||||
quiz_assert(!Undefined::Builder().isNumberZero());
|
quiz_assert(Infinity::Builder(true).nullStatus(&context) == ExpressionNode::NullStatus::NonNull );
|
||||||
quiz_assert(!Rational::Builder(2,3).isNumberZero());
|
quiz_assert(Undefined::Builder().nullStatus(&context) == ExpressionNode::NullStatus::Unknown);
|
||||||
quiz_assert(Rational::Builder(0,1).isNumberZero());
|
quiz_assert(Rational::Builder(2,3).nullStatus(&context) == ExpressionNode::NullStatus::NonNull );
|
||||||
quiz_assert(!Symbol::Builder('a').isNumberZero());
|
quiz_assert(Rational::Builder(0,1).nullStatus(&context) == ExpressionNode::NullStatus::Null );
|
||||||
quiz_assert(!Multiplication::Builder(Rational::Builder(1), Rational::Builder(0)).isNumberZero());
|
quiz_assert(Symbol::Builder('a').nullStatus(&context) == ExpressionNode::NullStatus::Unknown);
|
||||||
quiz_assert(!Addition::Builder(Rational::Builder(1), Rational::Builder(-1)).isNumberZero());
|
quiz_assert(Multiplication::Builder(Rational::Builder(1), Rational::Builder(0)).nullStatus(&context) == ExpressionNode::NullStatus::Unknown);
|
||||||
|
quiz_assert(Addition::Builder(Rational::Builder(1), Rational::Builder(-1)).nullStatus(&context) == ExpressionNode::NullStatus::Unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
QUIZ_CASE(poincare_properties_is_random) {
|
QUIZ_CASE(poincare_properties_is_random) {
|
||||||
|
|||||||
Reference in New Issue
Block a user