LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
numeric_evaluation.cpp
浏览该文件的文档.
3#include <cmath>
4#include <limits>
5
6namespace LMCAS {
7namespace {
8
9constexpr const char* kOperation = "evaluate_numeric";
10
12public:
14 ~RecursionScope() { context_.leave_recursion(); }
15
16private:
18};
19
20}
21
22namespace detail {
23
24Result<ApproxReal> numeric_failure(CasErrc code, std::string message) {
25 return Result<ApproxReal>::failure(code, std::move(message), kOperation);
26}
27
29 if (!std::isfinite(value)) {
30 return numeric_failure(CasErrc::NumericFailure, "numeric evaluation produced a nonfinite result");
31 }
33 ApproxReal{value, std::numeric_limits<double>::infinity(), NumericStatus::Finite});
34}
35
36Result<ApproxReal> NumericEvaluator::evaluate(const std::shared_ptr<const SymbolicNode>& node) {
37 auto entered = context_.enter_recursion(kOperation);
38 if (!entered) {
39 return Result<ApproxReal>::failure(entered.error());
40 }
41 RecursionScope scope(context_);
42 if (!node) {
43 return numeric_failure(CasErrc::InvalidArgument, "expression contains a null node");
44 }
45 if (const auto* value = dynamic_cast<const NumberNode*>(node.get())) {
46 return number(*value);
47 }
48 if (const auto* value = dynamic_cast<const VariableNode*>(node.get())) {
49 return variable(*value);
50 }
51 if (const auto* value = dynamic_cast<const AddNode*>(node.get())) {
52 return sum(*value);
53 }
54 if (const auto* value = dynamic_cast<const MultiplyNode*>(node.get())) {
55 return product(*value);
56 }
57 const auto squares = squared_norm_terms(*node);
58 if (squares[0]) {
59 return norm(squares);
60 }
61 if (const auto* value = dynamic_cast<const PowerNode*>(node.get())) {
62 return power(*value);
63 }
64 if (dynamic_cast<const RootOfNode*>(node.get())) {
65 return root(node);
66 }
67 if (const auto* value = dynamic_cast<const FunctionNode*>(node.get())) {
68 return function(*value);
69 }
71 "expression node is not real-numerically evaluable");
72}
73
75 if (node.type() == FunctionNode::FuncType::Infinity && node.arguments().empty()) {
77 std::numeric_limits<double>::infinity(), 0.0, NumericStatus::PositiveInfinity});
78 }
79 if (node.type() == FunctionNode::FuncType::Atan2) {
80 return atan2(node);
81 }
83 return extremum(node);
84 }
85 if (node.type() == FunctionNode::FuncType::Log &&
86 node.arguments().size() == 2) {
87 auto value = evaluate(node.arguments()[0]);
88 if (!value) {
89 return value;
90 }
91 auto base = evaluate(node.arguments()[1]);
92 if (!base) {
93 return base;
94 }
95 const double numeric_value = value.value().value;
96 const double numeric_base = base.value().value;
97 if (!(numeric_value > 0.0)) {
98 return numeric_failure(
100 "logarithm requires a positive real argument");
101 }
102 if (!(numeric_base > 0.0) || numeric_base == 1.0) {
103 return numeric_failure(
105 "logarithm base must be positive and not equal to one");
106 }
108 std::log(numeric_value) / std::log(numeric_base));
109 }
110 if (node.arguments().size() != 1) {
112 "function is not supported by real numeric evaluation");
113 }
114 if (node.type() == FunctionNode::FuncType::Sqrt) {
115 if (const auto* value = dynamic_cast<const NumberNode*>(node.arguments()[0].get())) {
116 return square_root(*value);
117 }
118 }
119 auto argument = evaluate(node.arguments()[0]);
120 if (!argument) {
121 return argument;
122 }
123 return evaluate_unary_numeric(node.type(), argument.value().value);
124}
125
126}
127
128Result<ApproxReal> evaluate_numeric(const SymbolicExpr& expression,
131 if (!detail::node(expression)) {
133 "cannot evaluate an empty expression", kOperation);
134 }
136 return evaluator.evaluate(detail::node(expression));
137}
138catch (const CasError& error) {
139 return Result<ApproxReal>::failure(error);
140} catch (const std::bad_alloc&) {
142 CasErrc::ResourceLimit, "numeric evaluation allocation failed", kOperation);
143} catch (const std::length_error& error) {
144 return Result<ApproxReal>::failure(CasErrc::ResourceLimit, error.what(), kOperation);
145} catch (const std::exception& error) {
146 return Result<ApproxReal>::failure(CasErrc::InternalInvariant, error.what(), kOperation);
147}
148
149}
加法节点,表示多个操作数的求和。
Result< void > enter_recursion(const std::string &operation={})
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
@ Atan2
双参数反正切。
@ Max
最大值 max(a, b)。
@ Min
最小值 min(a, b)。
@ Sqrt
对数、绝对值、平方根。
乘法节点,表示多个操作数的乘积。
幂运算节点,表示 base^exponent。
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
变量节点,表示一个符号变量。
Result< ApproxReal > variable(const VariableNode &node)
Result< ApproxReal > sum(const AddNode &node)
Result< ApproxReal > norm(const std::array< const PowerNode *, 2 > &squares)
Result< ApproxReal > number(const NumberNode &node)
Result< ApproxReal > function(const FunctionNode &node)
Result< ApproxReal > extremum(const FunctionNode &node)
Result< ApproxReal > root(const std::shared_ptr< const SymbolicNode > &node)
Result< ApproxReal > atan2(const FunctionNode &node)
Result< ApproxReal > square_root(const NumberNode &node)
Result< ApproxReal > evaluate(const std::shared_ptr< const SymbolicNode > &node)
Result< ApproxReal > power(const PowerNode &node)
Result< ApproxReal > product(const MultiplyNode &node)
多元 Hensel 提升(单变量步)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
Result< ApproxReal > numeric_failure(CasErrc code, std::string message)
Result< ApproxReal > evaluate_unary_numeric(FunctionNode::FuncType type, double value)
std::array< const PowerNode *, 2 > squared_norm_terms(const SymbolicNode &root)
Recognize real-numeric norm forms without evaluating their squares.
Result< ApproxReal > numeric_approximation(double value)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
const std::vector< Binding > & bindings
const std::string const ExprPtr & value
Result< ApproxReal > evaluate_numeric(const SymbolicExpr &expression, const NumericBindings &bindings={})
std::unordered_map< std::string, double > NumericBindings