mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-18 21:30:38 +01:00
[poincare] Enable to choose the "UnitConversion" mode at simplification
between: only SI, none, default...
This commit is contained in:
@@ -239,11 +239,11 @@ public:
|
||||
* account the complex format required in the expression they return.
|
||||
* (For instance, in Polar mode, they return an expression of the form
|
||||
* r*e^(i*th) reduced and approximated.) */
|
||||
static Expression ParseAndSimplify(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition);
|
||||
static Expression ParseAndSimplify(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, ExpressionNode::UnitConversion unitConversion = ExpressionNode::UnitConversion::Default);
|
||||
Expression simplify(ExpressionNode::ReductionContext reductionContext);
|
||||
|
||||
static void ParseAndSimplifyAndApproximate(const char * text, Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition);
|
||||
void simplifyAndApproximate(Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition);
|
||||
static void ParseAndSimplifyAndApproximate(const char * text, Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, ExpressionNode::UnitConversion unitConversion = ExpressionNode::UnitConversion::Default);
|
||||
void simplifyAndApproximate(Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation = ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, ExpressionNode::UnitConversion unitConversion = ExpressionNode::UnitConversion::Default);
|
||||
Expression reduce(ExpressionNode::ReductionContext context);
|
||||
|
||||
Expression mapOnMatrixFirstChild(ExpressionNode::ReductionContext reductionContext);
|
||||
|
||||
@@ -128,8 +128,13 @@ public:
|
||||
ReplaceAllSymbolsWithDefinitionsOrUndefined = 0,
|
||||
ReplaceAllDefinedSymbolsWithDefinition = 1,
|
||||
ReplaceDefinedFunctionsWithDefinitions = 2,
|
||||
ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits = 3, // Used in UnitConvert::shallowReduce
|
||||
ReplaceAllSymbolsWithUndefinedAndReplaceUnits = 4 // Used in UnitConvert::shallowReduce
|
||||
ReplaceAllSymbolsWithUndefined = 3 // Used in UnitConvert::shallowReduce
|
||||
};
|
||||
enum class UnitConversion {
|
||||
None = 0,
|
||||
Default,
|
||||
InternationalSystem,
|
||||
Classic // km/h, days + hours + minute
|
||||
};
|
||||
enum class Sign {
|
||||
Negative = -1,
|
||||
@@ -139,24 +144,27 @@ public:
|
||||
|
||||
class ReductionContext {
|
||||
public:
|
||||
ReductionContext(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ReductionTarget target, SymbolicComputation symbolicComputation = SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition) :
|
||||
ReductionContext(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ReductionTarget target, SymbolicComputation symbolicComputation = SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, UnitConversion unitConversion = UnitConversion::Default) :
|
||||
m_context(context),
|
||||
m_complexFormat(complexFormat),
|
||||
m_angleUnit(angleUnit),
|
||||
m_target(target),
|
||||
m_symbolicComputation(symbolicComputation)
|
||||
m_symbolicComputation(symbolicComputation),
|
||||
m_unitConversion(unitConversion)
|
||||
{}
|
||||
Context * context() { return m_context; }
|
||||
Preferences::ComplexFormat complexFormat() const { return m_complexFormat; }
|
||||
Preferences::AngleUnit angleUnit() const { return m_angleUnit; }
|
||||
ReductionTarget target() const { return m_target; }
|
||||
SymbolicComputation symbolicComputation() const { return m_symbolicComputation; }
|
||||
UnitConversion unitConversion() const { return m_unitConversion; }
|
||||
private:
|
||||
Context * m_context;
|
||||
Preferences::ComplexFormat m_complexFormat;
|
||||
Preferences::AngleUnit m_angleUnit;
|
||||
ReductionTarget m_target;
|
||||
SymbolicComputation m_symbolicComputation;
|
||||
UnitConversion m_unitConversion;
|
||||
};
|
||||
|
||||
virtual Sign sign(Context * context) const { return Sign::Unknown; }
|
||||
|
||||
@@ -571,12 +571,12 @@ int Expression::serialize(char * buffer, int bufferSize, Preferences::PrintFloat
|
||||
|
||||
/* Simplification */
|
||||
|
||||
Expression Expression::ParseAndSimplify(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation) {
|
||||
Expression Expression::ParseAndSimplify(const char * text, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation, ExpressionNode::UnitConversion unitConversion) {
|
||||
Expression exp = Parse(text, context, false);
|
||||
if (exp.isUninitialized()) {
|
||||
return Undefined::Builder();
|
||||
}
|
||||
exp = exp.simplify(ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User, symbolicComputation));
|
||||
exp = exp.simplify(ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User, symbolicComputation, unitConversion));
|
||||
/* simplify might have been interrupted, in which case the resulting
|
||||
* expression is uninitialized, so we need to check that. */
|
||||
if (exp.isUninitialized()) {
|
||||
@@ -585,7 +585,7 @@ Expression Expression::ParseAndSimplify(const char * text, Context * context, Pr
|
||||
return exp;
|
||||
}
|
||||
|
||||
void Expression::ParseAndSimplifyAndApproximate(const char * text, Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation) {
|
||||
void Expression::ParseAndSimplifyAndApproximate(const char * text, Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation, ExpressionNode::UnitConversion unitConversion) {
|
||||
assert(simplifiedExpression);
|
||||
Expression exp = Parse(text, context, false);
|
||||
if (exp.isUninitialized()) {
|
||||
@@ -593,7 +593,7 @@ void Expression::ParseAndSimplifyAndApproximate(const char * text, Expression *
|
||||
*approximateExpression = Undefined::Builder();
|
||||
return;
|
||||
}
|
||||
exp.simplifyAndApproximate(simplifiedExpression, approximateExpression, context, complexFormat, angleUnit, symbolicComputation);
|
||||
exp.simplifyAndApproximate(simplifiedExpression, approximateExpression, context, complexFormat, angleUnit, symbolicComputation, unitConversion);
|
||||
/* simplify might have been interrupted, in which case the resulting
|
||||
* expression is uninitialized, so we need to check that. */
|
||||
if (simplifiedExpression->isUninitialized()) {
|
||||
@@ -675,16 +675,16 @@ void Expression::beautifyAndApproximateScalar(Expression * simplifiedExpression,
|
||||
}
|
||||
}
|
||||
|
||||
void Expression::simplifyAndApproximate(Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation) {
|
||||
void Expression::simplifyAndApproximate(Expression * simplifiedExpression, Expression * approximateExpression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ExpressionNode::SymbolicComputation symbolicComputation, ExpressionNode::UnitConversion unitConversion) {
|
||||
assert(simplifiedExpression);
|
||||
sSimplificationHasBeenInterrupted = false;
|
||||
// Step 1: we reduce the expression
|
||||
ExpressionNode::ReductionContext userReductionContext = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User, symbolicComputation);
|
||||
ExpressionNode::ReductionContext userReductionContext = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User, symbolicComputation, unitConversion);
|
||||
const bool isUnitConvert = type() == ExpressionNode::Type::UnitConvert;
|
||||
Expression e = clone().reduce(userReductionContext);
|
||||
if (sSimplificationHasBeenInterrupted) {
|
||||
sSimplificationHasBeenInterrupted = false;
|
||||
ExpressionNode::ReductionContext systemReductionContext = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::SystemForApproximation, symbolicComputation);
|
||||
ExpressionNode::ReductionContext systemReductionContext = ExpressionNode::ReductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::SystemForApproximation, symbolicComputation, unitConversion);
|
||||
e = reduce(systemReductionContext);
|
||||
}
|
||||
*simplifiedExpression = Expression();
|
||||
|
||||
@@ -115,8 +115,7 @@ Expression Function::replaceSymbolWithExpression(const SymbolAbstract & symbol,
|
||||
}
|
||||
|
||||
Expression Function::shallowReduce(ExpressionNode::ReductionContext reductionContext) {
|
||||
if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits
|
||||
|| reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndReplaceUnits
|
||||
if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined
|
||||
|| childAtIndex(0).isUndefined())
|
||||
{
|
||||
return replaceWithUndefinedInPlace();
|
||||
|
||||
@@ -355,75 +355,77 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu
|
||||
return std::move(o);
|
||||
}
|
||||
|
||||
// Step 2: Handle the units
|
||||
Expression self = *this;
|
||||
Expression units;
|
||||
self = removeUnit(&units);
|
||||
|
||||
Expression result;
|
||||
if (!units.isUninitialized()) {
|
||||
/* Step 2: Handle the units
|
||||
*
|
||||
* Recognize derived units
|
||||
* - Look up in the table of derived units, the one which itself or its inverse simplifies 'units' the most.
|
||||
* - If an entry is found, simplify 'units' and add the corresponding unit or its inverse in 'unitsAccu'.
|
||||
* - Repeat those steps until no more simplification is possible.
|
||||
*/
|
||||
Multiplication unitsAccu = Multiplication::Builder();
|
||||
Unit::Dimension::Vector<Integer> unitsExponents = Unit::Dimension::Vector<Integer>::FromBaseUnits(units);
|
||||
Unit::Dimension::Vector<Integer>::Metrics unitsMetrics = unitsExponents.metrics();
|
||||
Unit::Dimension::Vector<Integer> bestRemainderExponents;
|
||||
Unit::Dimension::Vector<Integer>::Metrics bestRemainderMetrics;
|
||||
while (unitsMetrics.supportSize > 1) {
|
||||
const Unit::Dimension * bestDim = nullptr;
|
||||
int8_t bestUnitExponent = 0;
|
||||
for (const Unit::Dimension * dim = Unit::DimensionTable + Unit::NumberOfBaseUnits; dim < Unit::DimensionTableUpperBound; dim++) {
|
||||
const Unit::Dimension::Vector<int8_t> * entryUnitExponents = dim->vector();
|
||||
int8_t entryUnitNorm = entryUnitExponents->metrics().norm;
|
||||
if (CanSimplifyUnitProduct(
|
||||
unitsExponents, unitsMetrics,
|
||||
entryUnitExponents, entryUnitNorm, 1,
|
||||
bestUnitExponent, bestRemainderExponents, bestRemainderMetrics
|
||||
)
|
||||
||
|
||||
CanSimplifyUnitProduct(
|
||||
unitsExponents, unitsMetrics,
|
||||
entryUnitExponents, entryUnitNorm, -1,
|
||||
bestUnitExponent, bestRemainderExponents, bestRemainderMetrics
|
||||
))
|
||||
{
|
||||
bestDim = dim;
|
||||
ExpressionNode::UnitConversion unitConversionMode = reductionContext.unitConversion();
|
||||
if (unitConversionMode == ExpressionNode::UnitConversion::Default || unitConversionMode == ExpressionNode::UnitConversion::Classic) {
|
||||
/* Step 2a: Recognize derived units
|
||||
* - Look up in the table of derived units, the one which itself or its inverse simplifies 'units' the most.
|
||||
* - If an entry is found, simplify 'units' and add the corresponding unit or its inverse in 'unitsAccu'.
|
||||
* - Repeat those steps until no more simplification is possible.
|
||||
*/
|
||||
Multiplication unitsAccu = Multiplication::Builder();
|
||||
Unit::Dimension::Vector<Integer> unitsExponents = Unit::Dimension::Vector<Integer>::FromBaseUnits(units);
|
||||
Unit::Dimension::Vector<Integer>::Metrics unitsMetrics = unitsExponents.metrics();
|
||||
Unit::Dimension::Vector<Integer> bestRemainderExponents;
|
||||
Unit::Dimension::Vector<Integer>::Metrics bestRemainderMetrics;
|
||||
while (unitsMetrics.supportSize > 1) {
|
||||
const Unit::Dimension * bestDim = nullptr;
|
||||
int8_t bestUnitExponent = 0;
|
||||
for (const Unit::Dimension * dim = Unit::DimensionTable + Unit::NumberOfBaseUnits; dim < Unit::DimensionTableUpperBound; dim++) {
|
||||
const Unit::Dimension::Vector<int8_t> * entryUnitExponents = dim->vector();
|
||||
int8_t entryUnitNorm = entryUnitExponents->metrics().norm;
|
||||
if (CanSimplifyUnitProduct(
|
||||
unitsExponents, unitsMetrics,
|
||||
entryUnitExponents, entryUnitNorm, 1,
|
||||
bestUnitExponent, bestRemainderExponents, bestRemainderMetrics
|
||||
)
|
||||
||
|
||||
CanSimplifyUnitProduct(
|
||||
unitsExponents, unitsMetrics,
|
||||
entryUnitExponents, entryUnitNorm, -1,
|
||||
bestUnitExponent, bestRemainderExponents, bestRemainderMetrics
|
||||
))
|
||||
{
|
||||
bestDim = dim;
|
||||
}
|
||||
}
|
||||
if (bestDim == nullptr) {
|
||||
break;
|
||||
}
|
||||
Expression derivedUnit = Unit::Builder(bestDim, bestDim->stdRepresentative(), bestDim->stdRepresentativePrefix());
|
||||
assert(bestUnitExponent == 1 || bestUnitExponent == -1);
|
||||
if (bestUnitExponent == -1) {
|
||||
derivedUnit = Power::Builder(derivedUnit, Rational::Builder(-1));
|
||||
}
|
||||
const int position = unitsAccu.numberOfChildren();
|
||||
unitsAccu.addChildAtIndexInPlace(derivedUnit, position, position);
|
||||
unitsExponents = bestRemainderExponents;
|
||||
unitsMetrics = bestRemainderMetrics;
|
||||
}
|
||||
if (bestDim == nullptr) {
|
||||
break;
|
||||
}
|
||||
Expression derivedUnit = Unit::Builder(bestDim, bestDim->stdRepresentative(), bestDim->stdRepresentativePrefix());
|
||||
assert(bestUnitExponent == 1 || bestUnitExponent == -1);
|
||||
if (bestUnitExponent == -1) {
|
||||
derivedUnit = Power::Builder(derivedUnit, Rational::Builder(-1));
|
||||
}
|
||||
const int position = unitsAccu.numberOfChildren();
|
||||
unitsAccu.addChildAtIndexInPlace(derivedUnit, position, position);
|
||||
unitsExponents = bestRemainderExponents;
|
||||
unitsMetrics = bestRemainderMetrics;
|
||||
}
|
||||
if (unitsAccu.numberOfChildren() > 0) {
|
||||
units = Division::Builder(units, unitsAccu.clone()).deepReduce(reductionContext);
|
||||
Expression newUnits;
|
||||
units = units.removeUnit(&newUnits);
|
||||
Multiplication m = Multiplication::Builder(units);
|
||||
self.replaceWithInPlace(m);
|
||||
m.addChildAtIndexInPlace(self, 0, 1);
|
||||
self = m;
|
||||
if (newUnits.isUninitialized()) {
|
||||
units = unitsAccu;
|
||||
} else {
|
||||
units = Multiplication::Builder(unitsAccu, newUnits);
|
||||
static_cast<Multiplication &>(units).mergeSameTypeChildrenInPlace();
|
||||
if (unitsAccu.numberOfChildren() > 0) {
|
||||
units = Division::Builder(units, unitsAccu.clone()).deepReduce(reductionContext);
|
||||
Expression newUnits;
|
||||
units = units.removeUnit(&newUnits);
|
||||
Multiplication m = Multiplication::Builder(units);
|
||||
self.replaceWithInPlace(m);
|
||||
m.addChildAtIndexInPlace(self, 0, 1);
|
||||
self = m;
|
||||
if (newUnits.isUninitialized()) {
|
||||
units = unitsAccu;
|
||||
} else {
|
||||
units = Multiplication::Builder(unitsAccu, newUnits);
|
||||
static_cast<Multiplication &>(units).mergeSameTypeChildrenInPlace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn into 'Float x units'.
|
||||
/* Step 2b: Turn into 'Float x units'.
|
||||
* Choose a unit multiple adequate for the numerical value.
|
||||
* An exhaustive exploration of all possible multiples would have
|
||||
* exponential complexity with respect to the number of factors. Instead,
|
||||
@@ -436,41 +438,46 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu
|
||||
// If the value is undefined, return "undef" without any unit
|
||||
result = Undefined::Builder();
|
||||
} else {
|
||||
Expression resultWithoutUnit;
|
||||
if (std::isinf(value)) {
|
||||
resultWithoutUnit = Infinity::Builder(value < 0.0);
|
||||
if (unitConversionMode == ExpressionNode::UnitConversion::Classic) {
|
||||
// TODO create new result 1h 23min 24secondes ?
|
||||
// Utiliser store ?
|
||||
} else {
|
||||
// Find the right unit prefix when the value ≠ 0
|
||||
if (value != 0.0 && value != 1.0) {
|
||||
// Identify the first Unit factor and its exponent
|
||||
Expression firstFactor = units;
|
||||
int exponent = 1;
|
||||
if (firstFactor.type() == ExpressionNode::Type::Multiplication) {
|
||||
firstFactor = firstFactor.childAtIndex(0);
|
||||
}
|
||||
if (firstFactor.type() == ExpressionNode::Type::Power) {
|
||||
Expression exp = firstFactor.childAtIndex(1);
|
||||
firstFactor = firstFactor.childAtIndex(0);
|
||||
assert(exp.type() == ExpressionNode::Type::Rational && static_cast<Rational &>(exp).isInteger());
|
||||
Integer expInt = static_cast<Rational &>(exp).signedIntegerNumerator();
|
||||
if (expInt.isLowerThan(Integer(Integer::k_maxExtractableInteger))) {
|
||||
exponent = expInt.extractedInt();
|
||||
} else {
|
||||
// The exponent is too large to be extracted, so do not try to use it.
|
||||
exponent = 0;
|
||||
Expression resultWithoutUnit;
|
||||
if (std::isinf(value)) {
|
||||
resultWithoutUnit = Infinity::Builder(value < 0.0);
|
||||
} else {
|
||||
// Find the right unit prefix when the value ≠ 0
|
||||
if (unitConversionMode == ExpressionNode::UnitConversion::Default && value != 0.0 && value != 1.0) {
|
||||
// Identify the first Unit factor and its exponent
|
||||
Expression firstFactor = units;
|
||||
int exponent = 1;
|
||||
if (firstFactor.type() == ExpressionNode::Type::Multiplication) {
|
||||
firstFactor = firstFactor.childAtIndex(0);
|
||||
}
|
||||
if (firstFactor.type() == ExpressionNode::Type::Power) {
|
||||
Expression exp = firstFactor.childAtIndex(1);
|
||||
firstFactor = firstFactor.childAtIndex(0);
|
||||
assert(exp.type() == ExpressionNode::Type::Rational && static_cast<Rational &>(exp).isInteger());
|
||||
Integer expInt = static_cast<Rational &>(exp).signedIntegerNumerator();
|
||||
if (expInt.isLowerThan(Integer(Integer::k_maxExtractableInteger))) {
|
||||
exponent = expInt.extractedInt();
|
||||
} else {
|
||||
// The exponent is too large to be extracted, so do not try to use it.
|
||||
exponent = 0;
|
||||
}
|
||||
}
|
||||
assert(firstFactor.type() == ExpressionNode::Type::Unit);
|
||||
// Choose its multiple and update value accordingly
|
||||
if (exponent != 0) {
|
||||
static_cast<Unit&>(firstFactor).chooseBestMultipleForValue(value, exponent, reductionContext);
|
||||
}
|
||||
}
|
||||
assert(firstFactor.type() == ExpressionNode::Type::Unit);
|
||||
// Choose its multiple and update value accordingly
|
||||
if (exponent != 0) {
|
||||
static_cast<Unit&>(firstFactor).chooseBestMultipleForValue(value, exponent, reductionContext);
|
||||
}
|
||||
resultWithoutUnit = Float<double>::Builder(value);
|
||||
}
|
||||
resultWithoutUnit = Float<double>::Builder(value);
|
||||
// Build final Expression
|
||||
result = Multiplication::Builder(resultWithoutUnit, units);
|
||||
static_cast<Multiplication &>(result).mergeSameTypeChildrenInPlace();
|
||||
}
|
||||
// Build final Expression
|
||||
result = Multiplication::Builder(resultWithoutUnit, units);
|
||||
static_cast<Multiplication &>(result).mergeSameTypeChildrenInPlace();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -154,9 +154,7 @@ Expression Symbol::shallowReduce(ExpressionNode::ReductionContext reductionConte
|
||||
if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions) {
|
||||
return *this;
|
||||
}
|
||||
if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits
|
||||
|| reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndReplaceUnits)
|
||||
{
|
||||
if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined) {
|
||||
return replaceWithUndefinedInPlace();
|
||||
}
|
||||
{
|
||||
|
||||
@@ -282,7 +282,7 @@ Unit Unit::Builder(const Dimension * dimension, const Representative * represent
|
||||
}
|
||||
|
||||
Expression Unit::shallowReduce(ExpressionNode::ReductionContext reductionContext) {
|
||||
if (reductionContext.symbolicComputation() == ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits) {
|
||||
if (reductionContext.unitConversion() == ExpressionNode::UnitConversion::None) {
|
||||
return *this;
|
||||
}
|
||||
UnitNode * unitNode = static_cast<UnitNode *>(node());
|
||||
|
||||
@@ -35,12 +35,13 @@ Expression UnitConvert::shallowReduce(ExpressionNode::ReductionContext reduction
|
||||
|
||||
// Find the unit
|
||||
{
|
||||
//
|
||||
ExpressionNode::ReductionContext reductionContextWithUnits = ExpressionNode::ReductionContext(
|
||||
reductionContext.context(),
|
||||
reductionContext.complexFormat(),
|
||||
reductionContext.angleUnit(),
|
||||
reductionContext.target(),
|
||||
ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndReplaceUnits);
|
||||
ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined);
|
||||
Expression unit;
|
||||
childAtIndex(1).clone().reduce(reductionContextWithUnits).removeUnit(&unit);
|
||||
if (unit.isUninitialized()) {
|
||||
@@ -54,7 +55,8 @@ Expression UnitConvert::shallowReduce(ExpressionNode::ReductionContext reduction
|
||||
reductionContext.complexFormat(),
|
||||
reductionContext.angleUnit(),
|
||||
reductionContext.target(),
|
||||
ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits);
|
||||
ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined,
|
||||
ExpressionNode::UnitConversion::None);
|
||||
Expression finalUnit;
|
||||
childAtIndex(1).reduce(reductionContextWithoutUnits).removeUnit(&finalUnit);
|
||||
|
||||
|
||||
@@ -368,9 +368,9 @@ QUIZ_CASE(poincare_properties_get_polynomial_coefficients) {
|
||||
Ion::Storage::sharedStorage()->recordNamed("x.exp").destroy();
|
||||
}
|
||||
|
||||
void assert_reduced_expression_unit(const char * expression, const char * unit, ExpressionNode::SymbolicComputation symbolicComutation) {
|
||||
void assert_reduced_expression_unit_is(const char * expression, const char * unit) {
|
||||
Shared::GlobalContext globalContext;
|
||||
ExpressionNode::ReductionContext redContext(&globalContext, Real, Degree, SystemForApproximation, symbolicComutation);
|
||||
ExpressionNode::ReductionContext redContext(&globalContext, Real, Degree, SystemForApproximation);
|
||||
Expression e = parse_expression(expression, &globalContext, false);
|
||||
e = e.reduce(redContext);
|
||||
Expression u1;
|
||||
@@ -383,15 +383,9 @@ void assert_reduced_expression_unit(const char * expression, const char * unit,
|
||||
}
|
||||
|
||||
QUIZ_CASE(poincare_properties_get_unit) {
|
||||
assert_reduced_expression_unit("_km", "_km", ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits);
|
||||
assert_reduced_expression_unit("_min/_km", "_km^(-1)×_min", ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits);
|
||||
assert_reduced_expression_unit("_km^3", "_km^3", ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits);
|
||||
assert_reduced_expression_unit("1_m+_km", Undefined::Name(), ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits);
|
||||
assert_reduced_expression_unit("_L^2×3×_s", "_L^2×_s", ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits);
|
||||
|
||||
assert_reduced_expression_unit("_km", "_m", ReplaceAllSymbolsWithDefinitionsOrUndefined);
|
||||
assert_reduced_expression_unit("_min/_km", "_m^(-1)×_s", ReplaceAllSymbolsWithDefinitionsOrUndefined);
|
||||
assert_reduced_expression_unit("_km^3", "_m^3", ReplaceAllSymbolsWithDefinitionsOrUndefined);
|
||||
assert_reduced_expression_unit("1_m+_km", "_m", ReplaceAllSymbolsWithDefinitionsOrUndefined);
|
||||
assert_reduced_expression_unit("_L^2×3×_s", "_m^6×_s", ReplaceAllSymbolsWithDefinitionsOrUndefined);
|
||||
assert_reduced_expression_unit_is("_km", "_m");
|
||||
assert_reduced_expression_unit_is("_min/_km", "_m^(-1)×_s");
|
||||
assert_reduced_expression_unit_is("_km^3", "_m^3");
|
||||
assert_reduced_expression_unit_is("1_m+_km", "_m");
|
||||
assert_reduced_expression_unit_is("_L^2×3×_s", "_m^6×_s");
|
||||
}
|
||||
|
||||
@@ -11,7 +11,11 @@ constexpr Poincare::ExpressionNode::ReductionTarget User = Poincare::ExpressionN
|
||||
constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceAllDefinedSymbolsWithDefinition = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition;
|
||||
constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceAllSymbolsWithDefinitionsOrUndefined = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined;
|
||||
constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceDefinedFunctionsWithDefinitions = Poincare::ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions;
|
||||
constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefinedAndDoNotReplaceUnits;
|
||||
constexpr Poincare::ExpressionNode::SymbolicComputation ReplaceAllSymbolsWithUndefined = Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined;
|
||||
constexpr Poincare::ExpressionNode::UnitConversion NoUnitConversion = Poincare::ExpressionNode::UnitConversion::None;
|
||||
constexpr Poincare::ExpressionNode::UnitConversion DefaultUnitConversion = Poincare::ExpressionNode::UnitConversion::Default;
|
||||
constexpr Poincare::ExpressionNode::UnitConversion ClassicUnitConversion = Poincare::ExpressionNode::UnitConversion::Classic;
|
||||
constexpr Poincare::ExpressionNode::UnitConversion InternationalSystemUnitConversion = Poincare::ExpressionNode::UnitConversion::InternationalSystem;
|
||||
constexpr Poincare::Preferences::AngleUnit Degree = Poincare::Preferences::AngleUnit::Degree;
|
||||
constexpr Poincare::Preferences::AngleUnit Radian = Poincare::Preferences::AngleUnit::Radian;
|
||||
constexpr Poincare::Preferences::AngleUnit Gradian = Poincare::Preferences::AngleUnit::Gradian;
|
||||
|
||||
Reference in New Issue
Block a user