LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
expr_parser_functions.cpp
浏览该文件的文档.
4
5#include <exception>
6#include <utility>
7
8namespace LMCAS::expr_detail {
9namespace {
10
11using UnaryFunction = ExprResult (*)(const ExprPtr&);
12
14 static const struct {
15 const char* name;
17 } functions[] = {
18 {"sin", LMCAS::sin},
19 {"cos", LMCAS::cos},
20 {"tan", LMCAS::tan},
21 {"asin", LMCAS::asin},
22 {"acos", LMCAS::acos},
23 {"atan", LMCAS::atan},
24 {"sqrt", LMCAS::sqrt},
25 {"exp", LMCAS::exp},
26 {"ln", LMCAS::log},
27 {"log", LMCAS::log},
28 {"log10", LMCAS::log10},
29 {"floor", LMCAS::floor},
30 {"ceil", LMCAS::ceil},
31 {"round", LMCAS::round},
32 {"abs", LMCAS::abs},
33 {"real", LMCAS::real},
34 {"imag", LMCAS::imag},
35 {"conj", LMCAS::conj}
36 };
37 for (const auto& entry : functions) {
38 if (name == entry.name) {
39 return entry.function;
40 }
41 }
42 return nullptr;
43}
44
45}
46
47ExprResult ExprParser::apply_log(const std::vector<ExprPtr>& arguments) {
48 try {
49 auto result = SymbolicExpr::log(arguments[0], arguments[1]);
50 return ExprResult::success(std::move(result));
51 } catch (const std::bad_alloc&) {
53 "log expression allocation failed",
55 } catch (const std::exception& error) {
58 }
59}
60
61ExprResult ExprParser::apply_atan2(const std::vector<ExprPtr>& arguments) {
62 try {
63 auto result = SymbolicExpr::atan2(arguments[0], arguments[1]);
64 return ExprResult::success(std::move(result));
65 } catch (const std::bad_alloc&) {
67 "atan2 expression allocation failed",
69 } catch (const std::exception& error) {
72 }
73}
74
75ExprResult ExprParser::apply_integral(const std::vector<ExprPtr>& arguments) {
76 auto variable = std::dynamic_pointer_cast<const VariableNode>(
77 LMCAS::detail::node(arguments[1]));
78 if (!variable || variable->is_constant()) {
79 return fail("Integral variable must be a symbol");
80 }
81 try {
83 LMCAS::detail::node(arguments[0]), variable->name(),
84 arguments.size() == 4
85 ? LMCAS::detail::node(arguments[2])
86 : nullptr,
87 arguments.size() == 4
88 ? LMCAS::detail::node(arguments[3])
89 : nullptr);
91 LMCAS::detail::make_expression_ptr(std::move(node)));
92 } catch (const std::bad_alloc&) {
94 "Integral expression allocation failed",
96 } catch (const std::exception& error) {
98 }
99}
100
101ExprResult ExprParser::apply_limit(const std::vector<ExprPtr>& arguments) {
102 auto variable = std::dynamic_pointer_cast<const VariableNode>(
103 LMCAS::detail::node(arguments[1]));
104 auto direction = std::dynamic_pointer_cast<const VariableNode>(
105 LMCAS::detail::node(arguments[3]));
106 if (!variable || variable->is_constant() ||
107 !direction || direction->is_constant()) {
108 return fail("limit variable and direction must be symbols");
109 }
110 LimitDirection parsed_direction;
111 if (direction->name() == "both") {
112 parsed_direction = LimitDirection::Both;
113 } else if (direction->name() == "below" ||
114 direction->name() == "left" ||
115 direction->name() == "from_below") {
116 parsed_direction = LimitDirection::FromBelow;
117 } else if (direction->name() == "above" ||
118 direction->name() == "right" ||
119 direction->name() == "from_above") {
120 parsed_direction = LimitDirection::FromAbove;
121 } else {
122 return fail("invalid limit direction");
123 }
126 LMCAS::detail::node(arguments[0]), variable->name(),
127 LMCAS::detail::node(arguments[2]), parsed_direction)));
128}
129
130ExprResult ExprParser::apply_rootof(const std::vector<ExprPtr>& arguments) {
131 auto variable = std::dynamic_pointer_cast<const VariableNode>(
132 LMCAS::detail::node(arguments[1]));
133 auto index = std::dynamic_pointer_cast<const NumberNode>(
134 LMCAS::detail::node(arguments[2]));
135 if (!variable || variable->is_constant() || !index) {
136 return fail("RootOf variable and index are invalid");
137 }
138 BigInt index_value;
139 if (std::holds_alternative<BigInt>(index->value())) {
140 index_value = std::get<BigInt>(index->value());
141 } else {
142 const auto& rational = std::get<Rational>(index->value());
143 if (!rational.is_integer()) {
144 return fail("RootOf index must be an integer");
145 }
146 index_value = rational.to_bigint();
147 }
148 const auto converted = index_value.try_to_int64();
149 if (!converted || *converted < 0) {
150 return fail("RootOf index is negative or too large");
151 }
152 auto root = make_rootof_checked(
153 arguments[0], variable->name(),
154 static_cast<std::size_t>(*converted));
155 if (!root) {
156 return ExprResult::failure(root.error());
157 }
158 return ExprResult::success(std::move(root.value()));
159}
160
161ExprResult ExprParser::apply_clamp(const std::vector<ExprPtr>& arguments) {
162 return clamp(arguments[0], arguments[1], arguments[2]);
163}
164
166 const std::vector<ExprPtr>& arguments) {
167 if (auto unary = find_unary_function(name)) {
168 if (arguments.size() == 1) {
169 return unary(arguments[0]);
170 }
171 if (name == "log" && arguments.size() == 2) {
172 return apply_log(arguments);
173 }
174 return fail("invalid argument count for function '" + name + "'");
175 }
176 using Constructor = ExprResult (ExprParser::*)(const std::vector<ExprPtr>&);
177 static const struct {
178 const char* name;
179 Constructor construct;
180 std::size_t arity;
181 std::size_t alternative_arity;
182 } functions[] = {
183 {"atan2", &ExprParser::apply_atan2, 2, 2},
184 {"clamp", &ExprParser::apply_clamp, 3, 3},
185 {"Integral", &ExprParser::apply_integral, 2, 4},
186 {"integral", &ExprParser::apply_integral, 2, 4},
187 {"Limit", &ExprParser::apply_limit, 4, 4},
188 {"limit", &ExprParser::apply_limit, 4, 4},
189 {"RootOf", &ExprParser::apply_rootof, 3, 3},
190 {"rootof", &ExprParser::apply_rootof, 3, 3}
191 };
192 for (const auto& entry : functions) {
193 if (name == entry.name) {
194 if (arguments.size() != entry.arity &&
195 arguments.size() != entry.alternative_arity) {
196 return fail("invalid argument count for function '" + name + "'");
197 }
198 return (this->*entry.construct)(arguments);
199 }
200 }
201 if (!arguments.empty() && (name == "max" || name == "min")) {
202 return function_node(name, arguments,
204 }
205 return uninterpreted_function(name, arguments);
206}
207
209 const std::string& name, const std::vector<ExprPtr>& arguments) {
210 try {
211 std::vector<std::shared_ptr<const SymbolicNode>> nodes;
212 nodes.reserve(arguments.size());
213 for (const auto& argument : arguments) {
214 if (!argument || !LMCAS::detail::node(argument)) {
216 "function arguments cannot be null",
218 }
219 nodes.push_back(LMCAS::detail::node(argument));
220 }
222 name, std::move(nodes));
224 } catch (const std::bad_alloc&) {
226 "function expression allocation failed",
228 } catch (const std::exception& error) {
231 }
232}
233
234}
@ Max
最大值 max(a, b)。
@ Min
最小值 min(a, b)。
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(ExprPtr value)
ExprResult apply_log(const std::vector< ExprPtr > &arguments)
ExprResult uninterpreted_function(const std::string &name, const std::vector< ExprPtr > &arguments)
ExprResult function_node(const std::string &name, const std::vector< ExprPtr > &arguments, FunctionNode::FuncType type)
ExprResult apply_function(const std::string &name, const std::vector< ExprPtr > &arguments)
ExprResult apply_clamp(const std::vector< ExprPtr > &arguments)
ExprResult apply_atan2(const std::vector< ExprPtr > &arguments)
ExprResult apply_limit(const std::vector< ExprPtr > &arguments)
ExprResult apply_integral(const std::vector< ExprPtr > &arguments)
ExprResult apply_rootof(const std::vector< ExprPtr > &arguments)
ExprResult fail(std::string message) const
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)
ExprResult expression_failure(CasErrc code, std::string message, const char *operation)
constexpr const char * kParseOperation
const std::string & variable
ExprResult exp(const ExprPtr &expression, ComputationContext &context)
ExprResult log10(const ExprPtr &expression, ComputationContext &context)
ExprResult ceil(const ExprPtr &expression, ComputationContext &context)
ExprResult real(const ExprPtr &expression, ComputationContext &context)
ExprResult acos(const ExprPtr &expression, ComputationContext &context)
const std::string const LimitExprPtr LimitDirection direction
Result< ExprPtr > ExprResult
ExprResult conj(const ExprPtr &expression, ComputationContext &context)
ExprResult atan(const ExprPtr &expression, ComputationContext &context)
ExprResult clamp(const ExprPtr &expression, const ExprPtr &lower, const ExprPtr &upper, ComputationContext &context)
ExprResult asin(const ExprPtr &expression, ComputationContext &context)
RootOfConstructionResult make_rootof_checked(const std::shared_ptr< SymbolicExpr > &polynomial, const std::string &variable, std::size_t index, ComputationContext &context)
ExprResult sin(const ExprPtr &expression, ComputationContext &context)
ExprResult tan(const ExprPtr &expression, ComputationContext &context)
ExprPtr imag
ExprResult cos(const ExprPtr &expression, ComputationContext &context)
std::shared_ptr< SymbolicExpr > ExprPtr
ExprResult sqrt(const ExprPtr &expression, ComputationContext &context)
ExprResult log(const ExprPtr &expression, ComputationContext &context)
LimitDirection
Direction from which a limit approaches its point.
ExprResult floor(const ExprPtr &expression, ComputationContext &context)
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
ExprResult abs(const ExprPtr &expression, ComputationContext &context)
__attribute__((visibility("default"))) Result< EqvProfile > eqv_profile_from_name(const std const std::string & name
ExprResult rational(const Rational &value)
ExprResult round(const ExprPtr &expression, ComputationContext &context)
精确 RootOf 标识构造及受检数值求值。