14 std::shared_ptr<const SymbolicNode>
value;
25 if (
auto quantity = std::dynamic_pointer_cast<const QuantityNode>(
detail::node(expression))) {
26 return {quantity->value(), quantity->dimension(), quantity->scale_to_base(),
27 quantity->display_unit()};
29 return {
detail::node(expression), DimensionSignature{}, Rational(1), {}};
37 if (quantity.
scale == Rational(1))
return quantity.
value;
42 DimensionSignature dimension,
44 std::string display) {
46 if (dimension.is_dimensionless()) {
54 std::move(scale), std::move(display))));
55 }
catch (
const std::bad_alloc&) {
57 }
catch (
const std::exception& error) {
63 auto number = std::dynamic_pointer_cast<const NumberNode>(node);
66 if (std::holds_alternative<BigInt>(number->value())) {
69 if (std::holds_alternative<Rational>(number->value())) {
77 const std::shared_ptr<SymbolicExpr>&
rhs,
81 if (!step)
return step;
84 "quantity operands cannot be null",
kOperation);
92 const std::string&
unit,
94 auto step =
context.consume_steps(1, kOperation);
112 auto step =
context.consume_steps(1, kOperation);
129 const std::string& target_unit,
131 auto step =
context.consume_steps(1, kOperation);
133 auto quantity = expression
134 ? std::dynamic_pointer_cast<const QuantityNode>(
detail::node(expression))
138 "unit conversion requires a quantity expression");
142 if (quantity->dimension() !=
target.value().dimension) {
144 "unit conversion requires equal dimensions");
146 const Rational factor = quantity->scale_to_base() /
target.value().scale_to_base;
148 {quantity->value(), rational_node(factor)});
149 return make_quantity(std::move(
value),
target.value().dimension,
150 target.value().scale_to_base, target_unit);
157 auto step =
context.consume_steps(1, kOperation);
159 auto quantity = expression
160 ? std::dynamic_pointer_cast<const QuantityNode>(
detail::node(expression))
164 "unit conversion requires a quantity expression");
169 if (quantity->dimension() !=
definition.dimension) {
171 "unit conversion requires equal dimensions");
173 const Rational factor = quantity->scale_to_base() /
definition.scale_to_base;
175 {quantity->value(), rational_node(factor)});
176 return make_quantity(std::move(
value), std::move(
definition.dimension),
184 auto step =
context.consume_steps(1, kOperation);
188 "unit stripping requires an expression");
190 auto quantity = std::dynamic_pointer_cast<const QuantityNode>(
195 {quantity->value(), rational_node(quantity->scale_to_base())})
205 if (
auto quantity = std::dynamic_pointer_cast<const QuantityNode>(
detail::node(expression))) {
212 const std::shared_ptr<SymbolicExpr>&
rhs,
214 auto checked = checked_binary(lhs,
rhs,
context,
"quantity.add");
216 const auto left = view(lhs);
218 if (left.dimension !=
right.dimension) {
220 "addition requires operands with equal dimensions");
222 const Rational factor =
right.scale / left.scale;
224 {
right.value, rational_node(factor)});
226 left.dimension, left.scale, left.display);
230 const std::shared_ptr<SymbolicExpr>&
rhs,
232 auto checked = checked_binary(lhs,
rhs,
context,
"quantity.subtract");
234 const auto left = view(lhs);
236 if (left.dimension !=
right.dimension) {
238 "subtraction requires operands with equal dimensions");
240 const Rational factor = Rational(-1) *
right.scale / left.scale;
242 {
right.value, rational_node(factor)});
244 left.dimension, left.scale, left.display);
248 const std::shared_ptr<SymbolicExpr>&
rhs,
250 auto checked = checked_binary(lhs,
rhs,
context,
"quantity.multiply");
252 const auto left = view(lhs);
254 const auto dimension = left.dimension.multiplied_by(
right.dimension);
255 const std::string display = left.display.empty() ?
right.display
256 :
right.display.empty() ? left.display : left.display +
"*" +
right.display;
258 dimension, left.scale *
right.scale, display);
262 const std::shared_ptr<SymbolicExpr>&
rhs,
264 auto checked = checked_binary(lhs,
rhs,
context,
"quantity.divide");
266 const auto left = view(lhs);
270 const std::string display =
right.display.empty() ? left.display
271 : left.display.empty() ?
"1/" +
right.display : left.display +
"/" +
right.display;
273 left.dimension.divided_by(
right.dimension),
274 left.scale /
right.scale, display);
278 const std::shared_ptr<SymbolicExpr>&
exponent,
280 auto checked = checked_binary(base,
exponent,
context,
"quantity.power");
282 const auto exponent_view = view(
exponent);
283 if (!exponent_view.dimension.is_dimensionless()) {
285 "a quantity exponent must be dimensionless");
287 const auto base_view = view(base);
288 auto base_value = scaled_value(base_view);
289 if (base_view.dimension.is_dimensionless()) {
290 return make_quantity(
292 DimensionSignature{}, Rational(1), {});
294 auto power = exact_rational(exponent_view.value);
296 auto dimension = base_view.dimension.raised_to(power.value());
297 return make_quantity(
299 dimension, Rational(1), dimension.to_string());
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(std::shared_ptr< SymbolicExpr > value)
static std::shared_ptr< const SymbolicNode > create_add(std::vector< std::shared_ptr< const SymbolicNode > > ops, detail::RewriteBudget *budget=nullptr)
创建加法节点,自动扁平化嵌套加法并消除零项.
static std::shared_ptr< const SymbolicNode > create_power(std::shared_ptr< const SymbolicNode > base, std::shared_ptr< const SymbolicNode > exponent)
创建幂运算节点,自动处理指数为 0/1 及底数为 0/1 的情况.
static std::shared_ptr< const SymbolicNode > create_multiply(std::vector< std::shared_ptr< const SymbolicNode > > ops, detail::RewriteBudget *budget=nullptr)
创建乘法节点,自动扁平化嵌套乘法并消除单位元.
static std::shared_ptr< const SymbolicNode > create_number(const ::LMCAS::BigInt &v)
Result< void > checked_binary(const std::shared_ptr< SymbolicExpr > &lhs, const std::shared_ptr< SymbolicExpr > &rhs, ComputationContext &context, const char *name)
std::shared_ptr< const SymbolicNode > rational_node(const Rational &value)
QuantityResult make_quantity(std::shared_ptr< const SymbolicNode > value, DimensionSignature dimension, Rational scale, std::string display)
DimensionSignature dimension
std::shared_ptr< const SymbolicNode > scaled_value(const QuantityView &quantity)
constexpr const char * kOperation
std::shared_ptr< const SymbolicNode > value
QuantityView view(const std::shared_ptr< SymbolicExpr > &expression)
QuantityResult failure(CasErrc code, std::string message)
Result< Rational > exact_rational(const std::shared_ptr< const SymbolicNode > &node)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
std::shared_ptr< const Node > make_node(Args &&... args)
Result< DimensionSignature > dimension_of(const SymbolicExpr &expression)
Result< std::shared_ptr< SymbolicExpr > > QuantityResult
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
QuantityResult attach_unit(const std::shared_ptr< SymbolicExpr > &value, const std::string &unit, ComputationContext &context)
QuantityResult quantity_divide(const std::shared_ptr< SymbolicExpr > &lhs, const std::shared_ptr< SymbolicExpr > &rhs, ComputationContext &context)
std::string UnitDefinition definition
QuantityResult quantity_power(const std::shared_ptr< SymbolicExpr > &base, const std::shared_ptr< SymbolicExpr > &exponent, ComputationContext &context)
const std::string const ExprPtr & value
QuantityResult quantity_multiply(const std::shared_ptr< SymbolicExpr > &lhs, const std::shared_ptr< SymbolicExpr > &rhs, ComputationContext &context)
QuantityResult quantity_subtract(const std::shared_ptr< SymbolicExpr > &lhs, const std::shared_ptr< SymbolicExpr > &rhs, ComputationContext &context)
__attribute__((visibility("default"))) Result< EqvProfile > eqv_profile_from_name(const std const std::string & name
QuantityResult strip_unit(const std::shared_ptr< SymbolicExpr > &expression, UnitStripMode mode, ComputationContext &context)
QuantityResult convert_unit(const std::shared_ptr< SymbolicExpr > &expression, const std::string &target_unit, ComputationContext &context)
QuantityResult quantity_add(const std::shared_ptr< SymbolicExpr > &lhs, const std::shared_ptr< SymbolicExpr > &rhs, ComputationContext &context)