mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
140 lines
5.6 KiB
C++
140 lines
5.6 KiB
C++
#include <poincare/unit_convert.h>
|
|
#include <poincare/complex.h>
|
|
#include <poincare/context.h>
|
|
#include <poincare/division.h>
|
|
#include <poincare/float.h>
|
|
#include <poincare/infinity.h>
|
|
#include <poincare/multiplication.h>
|
|
#include <poincare/symbol.h>
|
|
#include <poincare/undefined.h>
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
|
|
namespace Poincare {
|
|
|
|
Expression UnitConvertNode::removeUnit(Expression * unit) {
|
|
/* Warning: removeUnit of a UnitConvert doesn't make much sense but we
|
|
* implement a 'dummy' version since UnitConvert still exists among the
|
|
* reduced expression. */
|
|
childAtIndex(1)->removeUnit(unit);
|
|
return UnitConvert(this).replaceWithUndefinedInPlace();
|
|
}
|
|
Expression UnitConvertNode::shallowBeautify(ReductionContext * reductionContext) {
|
|
return UnitConvert(this).shallowBeautify(reductionContext);
|
|
}
|
|
|
|
void UnitConvertNode::deepReduceChildren(ExpressionNode::ReductionContext reductionContext) {
|
|
UnitConvert(this).deepReduceChildren(reductionContext);
|
|
}
|
|
|
|
void UnitConvertNode::deepBeautifyChildren(ExpressionNode::ReductionContext reductionContext) {
|
|
UnitConvert(this).deepBeautifyChildren(reductionContext);
|
|
}
|
|
|
|
template<typename T>
|
|
Evaluation<T> UnitConvertNode::templatedApproximate(ApproximationContext approximationContext) const {
|
|
/* If we are here, it means that the unit convert node was not shallowReduced.
|
|
* Otherwise, it would have been replaced by the division of the value by the
|
|
* unit. We thus return Undefined. */
|
|
return Complex<T>::Undefined();
|
|
}
|
|
|
|
void UnitConvert::deepReduceChildren(ExpressionNode::ReductionContext reductionContext) {
|
|
childAtIndex(0).deepReduce(reductionContext);
|
|
ExpressionNode::ReductionContext reductionContextKeepUnitAsIs = ExpressionNode::ReductionContext(
|
|
reductionContext.context(),
|
|
reductionContext.complexFormat(),
|
|
reductionContext.angleUnit(),
|
|
reductionContext.unitFormat(),
|
|
reductionContext.target(),
|
|
ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined,
|
|
ExpressionNode::UnitConversion::None);
|
|
// Don't transform the targeted unit
|
|
childAtIndex(1).deepReduce(reductionContextKeepUnitAsIs);
|
|
}
|
|
|
|
void UnitConvert::deepBeautifyChildren(ExpressionNode::ReductionContext reductionContext) {
|
|
ExpressionNode::ReductionContext reductionContextKeepUnitAsIs = ExpressionNode::ReductionContext(
|
|
reductionContext.context(),
|
|
reductionContext.complexFormat(),
|
|
reductionContext.angleUnit(),
|
|
reductionContext.unitFormat(),
|
|
reductionContext.target(),
|
|
reductionContext.symbolicComputation(),
|
|
ExpressionNode::UnitConversion::None);
|
|
defaultDeepBeautifyChildren(reductionContextKeepUnitAsIs);
|
|
}
|
|
|
|
Expression UnitConvert::shallowBeautify(ExpressionNode::ReductionContext * reductionContext) {
|
|
// Discard cases like 4 -> _m/_km
|
|
{
|
|
ExpressionNode::ReductionContext reductionContextWithUnits = ExpressionNode::ReductionContext(
|
|
reductionContext->context(),
|
|
reductionContext->complexFormat(),
|
|
reductionContext->angleUnit(),
|
|
reductionContext->unitFormat(),
|
|
reductionContext->target(),
|
|
ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined);
|
|
Expression unit;
|
|
Expression childWithoutUnit = childAtIndex(1).clone().reduceAndRemoveUnit(reductionContextWithUnits, &unit);
|
|
if (childWithoutUnit.isUndefined() || unit.isUninitialized()) {
|
|
// There is no unit on the right
|
|
return replaceWithUndefinedInPlace();
|
|
}
|
|
}
|
|
// Find the unit
|
|
Expression unit;
|
|
childAtIndex(1).removeUnit(&unit);
|
|
if (unit.isUninitialized()) {
|
|
// There is no unit on the right
|
|
return replaceWithUndefinedInPlace();
|
|
}
|
|
|
|
/* Handle temperatures, as converting between Kelvin, Celsius and Fahrenheit
|
|
* cannot be done with a division. */
|
|
if (unit.type() == ExpressionNode::Type::Unit) {
|
|
Unit unitRef = static_cast<Unit &>(unit);
|
|
if (unitRef.representative()->dimensionVector() == Unit::TemperatureRepresentative::Default().dimensionVector()) {
|
|
Expression result = Unit::ConvertTemperatureUnits(childAtIndex(0), unitRef, *reductionContext);
|
|
replaceWithInPlace(result);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
// Divide the left member by the new unit
|
|
Expression division = Division::Builder(childAtIndex(0), unit.clone());
|
|
Expression divisionUnit;
|
|
division = division.reduceAndRemoveUnit(*reductionContext, &divisionUnit);
|
|
if (!divisionUnit.isUninitialized()) {
|
|
// The left and right members are not homogeneous
|
|
return replaceWithUndefinedInPlace();
|
|
}
|
|
Expression result = Multiplication::Builder(division, unit);
|
|
replaceWithInPlace(result);
|
|
ExpressionNode::ReductionContext reductionContextWithoutUnits = ExpressionNode::ReductionContext(
|
|
reductionContext->context(),
|
|
reductionContext->complexFormat(),
|
|
reductionContext->angleUnit(),
|
|
reductionContext->unitFormat(),
|
|
reductionContext->target(),
|
|
ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithUndefined,
|
|
ExpressionNode::UnitConversion::None);
|
|
result = result.shallowReduce(reductionContextWithoutUnits);
|
|
result = result.shallowBeautify(&reductionContextWithoutUnits);
|
|
*reductionContext = ExpressionNode::ReductionContext(
|
|
reductionContext->context(),
|
|
reductionContext->complexFormat(),
|
|
reductionContext->angleUnit(),
|
|
reductionContext->unitFormat(),
|
|
reductionContext->target(),
|
|
reductionContext->symbolicComputation(),
|
|
ExpressionNode::UnitConversion::None);
|
|
return result;
|
|
}
|
|
|
|
template Evaluation<float> UnitConvertNode::templatedApproximate<float>(ApproximationContext approximationContext) const;
|
|
template Evaluation<double> UnitConvertNode::templatedApproximate<double>(ApproximationContext approximationContext) const;
|
|
|
|
}
|