4#include "lmmc/numeric.h"
11void append_array(std::string& result,
const std::vector<Value>& values) {
13 for (
size_t index = 0; index < values.size(); ++index) {
14 if (index) result +=
", ";
15 result += values[index].to_string();
26std::string
format_matrix(
const std::vector<std::vector<Value>>& matrix) {
27 std::string result =
"[";
28 for (
size_t row = 0; row < matrix.size(); ++row) {
29 if (row) result +=
", ";
37 std::string result = std::to_string(
value);
38 result.erase(result.find_last_not_of(
'0') + 1, std::string::npos);
39 result.erase(result.find_last_not_of(
'.') + 1, std::string::npos);
44 return sign && *sign > 0 ?
"inf" :
"-inf";
47template <
typename Exact>
49 const auto range_failure = [] {
52 "exact numeric value is outside the floating-point range",
53 "Value::as_number_checked");
56 const lmmc_real_t converted =
value.to_double();
57 if (!std::isfinite(converted) ||
58 (converted == 0.0 && !
value.is_zero())) {
59 return range_failure();
62 }
catch (
const std::overflow_error&) {
63 return range_failure();
64 }
catch (
const std::underflow_error&) {
65 return range_failure();
66 }
catch (
const std::out_of_range&) {
67 return range_failure();
68 }
catch (
const std::range_error&) {
69 return range_failure();
74 Value::Value(lmmc_real_t f) : type(Type::Float), data(f) {
76 throw std::invalid_argument(
"Value: floating-point value must not be NaN");
82 this->type = Type::Infinity;
83 this->data = DataType(std::in_place_index<1>, res);
87 Value::Value(
const std::vector<Value>& arr) {
88 bool is_matrix = !arr.empty() && arr[0].is_array();
90 std::vector<std::vector<Value>> matrix;
91 for (
const auto& row : arr) {
93 matrix.push_back(std::get<std::vector<Value>>(row.data));
108 bool Value::is_numeric()
const {
111 (
context).limits().max_ast_nodes,
"transform");
112 if (type == Type::Int || type == Type::Float ||
113 type == Type::BigInt || type == Type::Rational ||
114 type == Type::Irrational) {
117 if (type == Type::Symbolic) {
118 const auto& sp = std::get<std::shared_ptr<SymbolicExpr>>(data);
119 if (!sp)
return false;
122 return simp && simp->is_number();
123 }
catch (
const std::invalid_argument&) {
125 }
catch (
const std::out_of_range&) {
132 LMCAS::Result<lmmc_real_t> Value::as_number_checked()
const {
133 if (type == Type::Infinity) {
136 const auto sign = std::get_if<int>(&data);
138 (sign && *sign > 0) ? inf : -inf);
140 if (type == Type::Int) {
142 static_cast<lmmc_real_t
>(std::get<int>(data)));
144 if (type == Type::Float) {
146 std::get<lmmc_real_t>(data));
148 if (type == Type::BigInt) {
150 std::get<::LMCAS::BigInt>(data));
152 if (type == Type::Rational) {
154 std::get<::LMCAS::Rational>(data));
156 if (type == Type::Irrational) {
158 std::get<::LMCAS::Irrational>(data).to_double());
160 if (type == Type::Symbolic) {
161 const auto& expression =
162 std::get<std::shared_ptr<SymbolicExpr>>(data);
168 if (!evaluated.value().is_finite() ||
169 !std::isfinite(evaluated.value().value)) {
172 "symbolic value did not evaluate to a finite number",
173 "Value::as_number_checked");
176 static_cast<lmmc_real_t
>(evaluated.value().value));
180 "value is not numeric",
"Value::as_number_checked");
184 LMCAS::Result<::LMCAS::Rational> Value::as_rational_checked()
const {
185 if (type == Type::Rational) {
187 std::get<::LMCAS::Rational>(data));
189 if (type == Type::Int) {
193 if (type == Type::Float) {
195 ::LMCAS::Rational::from_double(std::get<lmmc_real_t>(data)));
197 if (type == Type::BigInt) {
201 if (type == Type::Irrational) {
202 return std::get<::LMCAS::Irrational>(data).as_rational_checked();
206 "value cannot be represented as a rational",
207 "Value::as_rational_checked");
211 LMCAS::Result<::LMCAS::Irrational> Value::as_irrational_checked()
const {
212 if (type == Type::Irrational) {
214 std::get<::LMCAS::Irrational>(data));
216 if (type == Type::Int) {
220 if (type == Type::Float) {
222 ::LMCAS::Irrational::constant(std::get<lmmc_real_t>(data)));
224 if (type == Type::Rational) {
226 ::LMCAS::Irrational::constant(
227 std::get<::LMCAS::Rational>(data)));
229 if (type == Type::BigInt) {
231 ::LMCAS::Irrational::constant(
236 "value cannot be represented as an irrational wrapper",
237 "Value::as_irrational_checked");
241 LMCAS::Result<std::shared_ptr<SymbolicExpr>> Value::as_symbolic_checked()
const {
242 if (type == Type::Infinity) {
243 const auto sign = std::get_if<int>(&data);
244 return LMCAS::Result<std::shared_ptr<SymbolicExpr>>::success(
245 SymbolicExpr::infinity(sign ? *sign : 1));
247 if (type == Type::Symbolic) {
248 return LMCAS::Result<std::shared_ptr<SymbolicExpr>>::success(
249 std::get<std::shared_ptr<SymbolicExpr>>(data));
251 if (type == Type::Float) {
252 return LMCAS::Result<std::shared_ptr<SymbolicExpr>>::success(
253 SymbolicExpr::number(std::get<lmmc_real_t>(data)));
255 if (type == Type::Int || type == Type::Rational ||
256 type == Type::BigInt) {
257 auto rational = as_rational_checked();
259 return LMCAS::Result<std::shared_ptr<SymbolicExpr>>::failure(
262 return LMCAS::Result<std::shared_ptr<SymbolicExpr>>::success(
265 if (type == Type::Irrational) {
266 return LMCAS::Result<std::shared_ptr<SymbolicExpr>>::success(
267 std::get<::LMCAS::Irrational>(data).to_symbolic());
269 if (type == Type::Matrix) {
271 std::get<std::vector<std::vector<Value>>>(data);
272 std::vector<std::vector<std::shared_ptr<SymbolicExpr>>>
274 symbolic_matrix.reserve(matrix.size());
275 for (
const auto& row : matrix) {
276 std::vector<std::shared_ptr<SymbolicExpr>> symbolic_row;
277 symbolic_row.reserve(row.size());
278 for (
const auto&
value : row) {
279 auto symbolic =
value.as_symbolic_checked();
281 return LMCAS::Result<
282 std::shared_ptr<SymbolicExpr>>::failure(
285 symbolic_row.push_back(std::move(symbolic.value()));
287 symbolic_matrix.push_back(std::move(symbolic_row));
289 return LMCAS::Result<std::shared_ptr<SymbolicExpr>>::success(
290 SymbolicExpr::matrix(symbolic_matrix));
292 return LMCAS::Result<std::shared_ptr<SymbolicExpr>>::failure(
294 "value cannot be converted to a symbolic expression",
295 "Value::as_symbolic_checked");
299 bool Value::as_symbolic_compatible()
const {
301 case Type::Symbolic: {
304 case Type::Infinity: {
313 case Type::Rational: {
319 case Type::Irrational: {
330 std::string Value::to_string()
const {
331 if (type == Type::String) {
334 if (!_str_cache.empty()) {
338 case Type::Infinity: {
345 return std::to_string(std::get<int>(data));
351 return format_array(std::get<std::vector<Value>>(data));
354 return format_matrix(std::get<std::vector<std::vector<Value>>>(data));
357 return std::get<::LMCAS::BigInt>(data).to_string();
359 case Type::Rational: {
360 return std::get<::LMCAS::Rational>(data).to_string();
362 case Type::Irrational: {
363 return std::get<::LMCAS::Irrational>(data).to_string();
365 case Type::Symbolic: {
366 const auto& expression =
367 std::get<std::shared_ptr<SymbolicExpr>>(data);
369 return "<invalid-symbolic>";
371 return expression->to_string();
378 bool Value::operator==(
const Value& other)
const {
379 if (type != other.type)
return false;
380 if (type == Type::String) {
381 return _str_cache == other._str_cache;
383 if (data.index() != other.data.index())
return false;
384 return std::visit([&other](
const auto& val1) ->
bool {
385 using T = std::decay_t<
decltype(val1)>;
386 if constexpr (std::is_same_v<T, std::nullptr_t>) {
388 }
else if constexpr (std::is_same_v<T, std::shared_ptr<SymbolicExpr>>) {
389 if (!val1 && !std::get<T>(other.data))
return true;
390 if (!val1 || !std::get<T>(other.data))
return false;
391 return val1->compare(std::get<T>(other.data)) == 0;
393 return val1 == std::get<T>(other.data);
398 bool Value::operator<(
const Value& other)
const {
399 if (type != other.type)
return static_cast<int>(type) <
static_cast<int>(other.type);
400 if (type == Type::String) {
401 return _str_cache < other._str_cache;
403 if (data.index() != other.data.index())
return data.index() < other.data.index();
404 return std::visit([&other](
const auto& val1) ->
bool {
405 using T = std::decay_t<
decltype(val1)>;
406 if constexpr (std::is_same_v<T, std::nullptr_t>) {
408 }
else if constexpr (std::is_same_v<T, std::shared_ptr<SymbolicExpr>>) {
409 if (!val1 && !std::get<T>(other.data))
return false;
410 if (!val1)
return true;
411 if (!std::get<T>(other.data))
return false;
412 return val1->compare(std::get<T>(other.data)) < 0;
414 return val1 < std::get<T>(other.data);
419 LMCAS::Result<Value> Value::vector_add_checked(
const Value& other)
const {
420 if (!is_array() || !other.is_array()) {
423 "vector addition requires two arrays",
424 "Value::vector_add_checked");
426 const auto& lhs = std::get<std::vector<Value>>(data);
427 const auto&
rhs = std::get<std::vector<Value>>(other.data);
428 if (lhs.size() !=
rhs.size()) {
431 "vector lengths do not match",
432 "Value::vector_add_checked");
434 std::vector<Value> values;
435 values.reserve(lhs.size());
436 for (
size_t index = 0; index < lhs.size(); ++index) {
437 auto left = lhs[index].as_number_checked();
439 auto right =
rhs[index].as_number_checked();
441 values.emplace_back(left.value() +
right.value());
447 LMCAS::Result<Value> Value::dot_product_checked(
const Value& other)
const {
448 if (!is_array() || !other.is_array()) {
451 "dot product requires two arrays",
452 "Value::dot_product_checked");
454 const auto& lhs = std::get<std::vector<Value>>(data);
455 const auto&
rhs = std::get<std::vector<Value>>(other.data);
456 if (lhs.size() !=
rhs.size()) {
459 "vector lengths do not match",
460 "Value::dot_product_checked");
462 lmmc_real_t sum = 0.0;
463 for (
size_t index = 0; index < lhs.size(); ++index) {
464 auto left = lhs[index].as_number_checked();
466 auto right =
rhs[index].as_number_checked();
468 sum += left.value() *
right.value();
474 LMCAS::Result<Value> Value::matrix_multiply_checked(
475 const Value& other)
const {
476 if (!is_matrix() || !other.is_matrix()) {
479 "matrix multiplication requires two matrices",
480 "Value::matrix_multiply_checked");
483 std::get<std::vector<std::vector<Value>>>(data);
485 std::get<std::vector<std::vector<Value>>>(other.data);
486 if (lhs.empty() ||
rhs.empty() ||
487 lhs.front().size() !=
rhs.size()) {
490 "matrix dimensions are not multiplicatively compatible",
491 "Value::matrix_multiply_checked");
493 const size_t rows = lhs.size();
494 const size_t columns =
rhs.front().size();
495 const size_t inner = lhs.front().size();
496 std::vector<std::vector<Value>> values(
497 rows, std::vector<Value>(columns, Value(0.0)));
498 for (
size_t row = 0; row < rows; ++row) {
499 for (
size_t column = 0; column < columns; ++column) {
500 lmmc_real_t sum = 0.0;
501 for (
size_t index = 0; index < inner; ++index) {
502 auto left = lhs[row][index].as_number_checked();
506 auto right =
rhs[index][column].as_number_checked();
510 sum += left.value() *
right.value();
512 values[row][column] = Value(sum);
519 std::shared_ptr<SymbolicExpr> Value::require_symbolic(
520 const std::shared_ptr<SymbolicExpr>& expression) {
522 throw std::invalid_argument(
523 "Value: symbolic expression must not be null");
528 std::vector<std::vector<Value>> Value::validate_matrix(
529 std::vector<std::vector<Value>> matrix) {
530 if (matrix.empty())
return matrix;
531 const size_t columns = matrix.front().size();
532 for (
const auto& row : matrix) {
533 if (row.size() != columns) {
534 throw std::invalid_argument(
535 "Value: all matrix rows must have the same number of columns");
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
std::string format_array(const std::vector< Value > &values)
LMCAS::Result< lmmc_real_t > exact_number_as_floating(const Exact &value)
void append_array(std::string &result, const std::vector< Value > &values)
std::string format_matrix(const std::vector< std::vector< Value > > &matrix)
std::string format_float(lmmc_real_t value)
const char * format_infinity(const int *sign)
int sign(const Rational &value)
Result< void > validate_matrix(const ExactMatrixData &matrix, const std::string &operation)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
@ Rational
Rational numbers
const std::string const ExprPtr & value
Result< ApproxReal > evaluate_numeric(const SymbolicExpr &expression, const NumericBindings &bindings={})
ExprResult rational(const Rational &value)
运行时值类型 Value,支持数值,符号,容器类型.