#include #include #include #include #include #include #include #include #include #include #include #include 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 Evaluation 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::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); 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 UnitConvertNode::templatedApproximate(ApproximationContext approximationContext) const; template Evaluation UnitConvertNode::templatedApproximate(ApproximationContext approximationContext) const; }