LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
vector_calculus_differential.cpp
浏览该文件的文档.
4#include <stdexcept>
5
6namespace LMCAS {
7
8using namespace vector_calculus_detail;
9
11 const std::shared_ptr<SymbolicExpr>& f,
12 const std::vector<std::string>& vars,
14{
15 detail::RewriteBudget transform_budget(context, context.limits().max_recursion_depth,
16 context.limits().max_ast_nodes, "gradient");
17 const std::string operation = "gradient";
18 auto valid = vector_calculus_validate_expr_vars(f, vars, context, operation);
19 if (!valid) {
20 return VectorCalculusFieldResult::failure(valid.error());
21 }
22 auto step = context.consume_steps(vars.size(), operation);
23 if (!step) {
24 return VectorCalculusFieldResult::failure(step.error());
25 }
26 try {
27 return vector_calculus_wrap_field(gradient_impl(f, vars, transform_budget), operation);
28 } catch (const CasError& error) {
30 } catch (const std::bad_alloc&) {
32 "vector calculus allocation failed",
33 operation);
34 } catch (const std::length_error& error) {
35 return VectorCalculusFieldResult::failure(CasErrc::ResourceLimit, error.what(), operation);
36 } catch (const std::exception& e) {
38 }
39}
40
42 const std::shared_ptr<SymbolicExpr>& f,
43 const std::vector<std::string>& vars)
44{
46 return gradient_checked(f, vars, context);
47}
48
49VectorField vector_calculus_detail::gradient_impl(const std::shared_ptr<SymbolicExpr>& f,
50 const std::vector<std::string>& vars,
51 detail::RewriteBudget& transform_budget)
52{
53 if (!f) {
54 throw std::invalid_argument("gradient: f must not be null");
55 }
56 VectorField result;
57 transform_budget.require_nodes(vars.size());
58 std::size_t nodes = 0;
59 result.reserve(vars.size());
60 for (const auto& var : vars) {
61 auto partial = detail::make_expression_ptr(detail::differentiate_node(detail::node(f), var, transform_budget));
62 if (partial) {
63 partial = detail::make_expression_ptr(detail::normalize_node(detail::node(partial), transform_budget));
64 }
65 nodes = transform_budget.append_size(
66 nodes, transform_budget.measure(detail::node(partial)));
67 result.push_back(partial);
68 }
69 return result;
70}
71
72
74 const VectorField& F,
75 const std::vector<std::string>& vars,
77{
78 detail::RewriteBudget transform_budget(context, context.limits().max_recursion_depth,
79 context.limits().max_ast_nodes, "divergence");
80 const std::string operation = "divergence";
81 auto valid = vector_calculus_validate_field_vars(F, vars, context, operation);
82 if (!valid) {
83 return VectorCalculusExprResult::failure(valid.error());
84 }
85 auto step = context.consume_steps(F.size(), operation);
86 if (!step) {
87 return VectorCalculusExprResult::failure(step.error());
88 }
89 try {
90 return vector_calculus_wrap_expr(divergence_impl(F, vars, transform_budget), operation);
91 } catch (const CasError& error) {
93 } catch (const std::bad_alloc&) {
95 "vector calculus allocation failed",
96 operation);
97 } catch (const std::length_error& error) {
98 return VectorCalculusExprResult::failure(CasErrc::ResourceLimit, error.what(), operation);
99 } catch (const std::exception& e) {
101 }
102}
103
105 const VectorField& F,
106 const std::vector<std::string>& vars)
107{
109 return divergence_checked(F, vars, context);
110}
111
112std::shared_ptr<SymbolicExpr> vector_calculus_detail::divergence_impl(const VectorField& F,
113 const std::vector<std::string>& vars,
114 detail::RewriteBudget& transform_budget)
115{
116 if (F.size() != vars.size()) {
117 throw std::invalid_argument(
118 "divergence: F and vars must have the same dimension");
119 }
120 if (F.empty()) {
121 return SymbolicExpr::number(0);
122 }
123
124 std::shared_ptr<SymbolicExpr> sum = nullptr;
125 for (size_t i = 0; i < F.size(); ++i) {
126 if (!F[i]) {
127 continue;
128 }
129 auto partial = detail::make_expression_ptr(detail::differentiate_node(detail::node(F[i]), vars[i], transform_budget));
130 if (!partial) {
131 continue;
132 }
133 partial = detail::make_expression_ptr(detail::normalize_node(detail::node(partial), transform_budget));
134 if (!sum) {
135 sum = partial;
136 } else {
137 sum = SymbolicExpr::add(sum, partial);
139 }
140 }
141
142 if (!sum) {
143 return SymbolicExpr::number(0);
144 }
146}
147
148
150 const VectorField& F,
151 const std::vector<std::string>& vars,
153{
154 detail::RewriteBudget transform_budget(context, context.limits().max_recursion_depth,
155 context.limits().max_ast_nodes, "curl");
156 const std::string operation = "curl";
157 auto valid = vector_calculus_validate_field_vars(F, vars, context, operation);
158 if (!valid) {
159 return VectorCalculusFieldResult::failure(valid.error());
160 }
161 if (F.size() != 2 && F.size() != 3) {
164 "curl requires a 2D or 3D vector field",
165 operation);
166 }
167 auto step = context.consume_steps(F.size(), operation);
168 if (!step) {
169 return VectorCalculusFieldResult::failure(step.error());
170 }
171 try {
172 return vector_calculus_wrap_field(curl_impl(F, vars, transform_budget), operation);
173 } catch (const CasError& error) {
175 } catch (const std::bad_alloc&) {
177 "vector calculus allocation failed",
178 operation);
179 } catch (const std::length_error& error) {
180 return VectorCalculusFieldResult::failure(CasErrc::ResourceLimit, error.what(), operation);
181 } catch (const std::exception& e) {
183 }
184}
185
187 const VectorField& F,
188 const std::vector<std::string>& vars)
189{
191 return curl_checked(F, vars, context);
192}
193
195 const std::vector<std::string>& vars,
196 detail::RewriteBudget& transform_budget)
197{
198 if (F.size() != vars.size()) {
199 throw std::invalid_argument(
200 "curl: F and vars must have the same dimension");
201 }
202
203 /// 二维标量旋度: ∂F₂/∂x₁ - ∂F₁/∂x₂
204 if (F.size() == 2 && vars.size() == 2) {
205 auto dF2_dx1 = detail::make_expression_ptr(detail::differentiate_node(detail::node(F[1]), vars[0], transform_budget));
206 auto dF1_dx2 = detail::make_expression_ptr(detail::differentiate_node(detail::node(F[0]), vars[1], transform_budget));
207
208 auto neg_dF1_dx2 = SymbolicExpr::multiply(
209 SymbolicExpr::number(-1), dF1_dx2);
210 auto scalar_curl = SymbolicExpr::add(dF2_dx1, neg_dF1_dx2);
211 scalar_curl = detail::make_expression_ptr(detail::normalize_node(detail::node(scalar_curl), transform_budget));
212
213 return VectorField{scalar_curl};
214 }
215
216 /// 三维旋度
217 if (F.size() != 3 || vars.size() != 3) {
218 throw std::invalid_argument(
219 "curl: requires 2D or 3D vector field");
220 }
221
222 /// curl_x = ∂F₃/∂x₂ - ∂F₂/∂x₃
223 auto dF3_dx2 = detail::make_expression_ptr(detail::differentiate_node(detail::node(F[2]), vars[1], transform_budget));
224 auto dF2_dx3 = detail::make_expression_ptr(detail::differentiate_node(detail::node(F[1]), vars[2], transform_budget));
225 auto curl_x = SymbolicExpr::add(
226 dF3_dx2,
227 SymbolicExpr::multiply(SymbolicExpr::number(-1), dF2_dx3));
228 curl_x = detail::make_expression_ptr(detail::normalize_node(detail::node(curl_x), transform_budget));
229
230 /// curl_y = ∂F₁/∂x₃ - ∂F₃/∂x₁
231 auto dF1_dx3 = detail::make_expression_ptr(detail::differentiate_node(detail::node(F[0]), vars[2], transform_budget));
232 auto dF3_dx1 = detail::make_expression_ptr(detail::differentiate_node(detail::node(F[2]), vars[0], transform_budget));
233 auto curl_y = SymbolicExpr::add(
234 dF1_dx3,
235 SymbolicExpr::multiply(SymbolicExpr::number(-1), dF3_dx1));
236 curl_y = detail::make_expression_ptr(detail::normalize_node(detail::node(curl_y), transform_budget));
237
238 /// curl_z = ∂F₂/∂x₁ - ∂F₁/∂x₂
239 auto dF2_dx1 = detail::make_expression_ptr(detail::differentiate_node(detail::node(F[1]), vars[0], transform_budget));
240 auto dF1_dx2 = detail::make_expression_ptr(detail::differentiate_node(detail::node(F[0]), vars[1], transform_budget));
241 auto curl_z = SymbolicExpr::add(
242 dF2_dx1,
243 SymbolicExpr::multiply(SymbolicExpr::number(-1), dF1_dx2));
244 curl_z = detail::make_expression_ptr(detail::normalize_node(detail::node(curl_z), transform_budget));
245
246 VectorField result{curl_x, curl_y, curl_z};
247 std::size_t nodes = 0;
248 for (const auto& component : result) {
249 nodes = transform_budget.append_size(
250 nodes, transform_budget.measure(detail::node(component)));
251 }
252 return result;
253}
254
255
257 const std::shared_ptr<SymbolicExpr>& f,
258 const std::vector<std::string>& vars,
260{
261 detail::RewriteBudget transform_budget(context, context.limits().max_recursion_depth,
262 context.limits().max_ast_nodes, "laplacian");
263 const std::string operation = "laplacian";
264 auto valid = vector_calculus_validate_expr_vars(f, vars, context, operation);
265 if (!valid) {
266 return VectorCalculusExprResult::failure(valid.error());
267 }
268 auto step = context.consume_steps(vars.size() * 2, operation);
269 if (!step) {
270 return VectorCalculusExprResult::failure(step.error());
271 }
272 try {
273 return vector_calculus_wrap_expr(laplacian_impl(f, vars, transform_budget), operation);
274 } catch (const CasError& error) {
276 } catch (const std::bad_alloc&) {
278 "vector calculus allocation failed",
279 operation);
280 } catch (const std::length_error& error) {
281 return VectorCalculusExprResult::failure(CasErrc::ResourceLimit, error.what(), operation);
282 } catch (const std::exception& e) {
284 }
285}
286
288 const std::shared_ptr<SymbolicExpr>& f,
289 const std::vector<std::string>& vars)
290{
292 return laplacian_checked(f, vars, context);
293}
294
295std::shared_ptr<SymbolicExpr> vector_calculus_detail::laplacian_impl(const std::shared_ptr<SymbolicExpr>& f,
296 const std::vector<std::string>& vars,
297 detail::RewriteBudget& transform_budget)
298{
299 if (!f) {
300 throw std::invalid_argument("laplacian: f must not be null");
301 }
302 if (vars.empty()) {
303 return SymbolicExpr::number(0);
304 }
305
306 std::shared_ptr<SymbolicExpr> sum = nullptr;
307 for (const auto& var : vars) {
308 auto first = detail::make_expression_ptr(detail::differentiate_node(detail::node(f), var, transform_budget));
309 if (!first) {
310 continue;
311 }
312 auto second = detail::make_expression_ptr(detail::differentiate_node(detail::node(first), var, transform_budget));
313 if (!second) {
314 continue;
315 }
316 second = detail::make_expression_ptr(detail::normalize_node(detail::node(second), transform_budget));
317 if (!sum) {
318 sum = second;
319 } else {
320 sum = SymbolicExpr::add(sum, second);
322 }
323 }
324
325 if (!sum) {
326 return SymbolicExpr::number(0);
327 }
329}
330
331
332VectorField gradient(const std::shared_ptr<SymbolicExpr>& f,
333 const std::vector<std::string>& vars)
334{
336 detail::RewriteBudget transform_budget(context, context.limits().max_recursion_depth,
337 context.limits().max_ast_nodes, "gradient");
338 return gradient_impl(f, vars, transform_budget);
339}
340
341std::shared_ptr<SymbolicExpr> divergence(const VectorField& F,
342 const std::vector<std::string>& vars)
343{
345 detail::RewriteBudget transform_budget(context, context.limits().max_recursion_depth,
346 context.limits().max_ast_nodes, "divergence");
347 return divergence_impl(F, vars, transform_budget);
348}
349
351 const std::vector<std::string>& vars)
352{
354 detail::RewriteBudget transform_budget(context, context.limits().max_recursion_depth,
355 context.limits().max_ast_nodes, "curl");
356 return curl_impl(F, vars, transform_budget);
357}
358
359std::shared_ptr<SymbolicExpr> laplacian(const std::shared_ptr<SymbolicExpr>& f,
360 const std::vector<std::string>& vars)
361{
363 detail::RewriteBudget transform_budget(context, context.limits().max_recursion_depth,
364 context.limits().max_ast_nodes, "laplacian");
365 return laplacian_impl(f, vars, transform_budget);
366}
367
368}
static Result failure(CasErrc code, std::string message, std::string operation={})
std::size_t measure(const std::shared_ptr< const SymbolicNode > &node)
void require_nodes(std::size_t nodes) const
std::size_t append_size(std::size_t current, std::size_t child)
SymbolicNodePtr differentiate_node(const SymbolicNodePtr &node, const std::string &variable, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
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)
Result< void > vector_calculus_validate_expr_vars(const std::shared_ptr< SymbolicExpr > &f, const std::vector< std::string > &vars, ComputationContext &context, const std::string &operation)
VectorField gradient_impl(const std::shared_ptr< SymbolicExpr > &f, const std::vector< std::string > &vars, detail::RewriteBudget &transform_budget)
std::shared_ptr< SymbolicExpr > divergence_impl(const VectorField &F, const std::vector< std::string > &vars, detail::RewriteBudget &transform_budget)
std::shared_ptr< SymbolicExpr > laplacian_impl(const std::shared_ptr< SymbolicExpr > &f, const std::vector< std::string > &vars, detail::RewriteBudget &transform_budget)
VectorCalculusFieldResult vector_calculus_wrap_field(VectorField field, const std::string &operation)
VectorCalculusExprResult vector_calculus_wrap_expr(std::shared_ptr< SymbolicExpr > expr, const std::string &operation)
Result< void > vector_calculus_validate_field_vars(const VectorField &field, const std::vector< std::string > &vars, ComputationContext &context, const std::string &operation)
VectorField curl_impl(const VectorField &F, const std::vector< std::string > &vars, detail::RewriteBudget &transform_budget)
VectorCalculusFieldResult curl_checked(const VectorField &F, const std::vector< std::string > &vars, ComputationContext &context)
ExprResult e()
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
__attribute__((visibility("default"))) VectorCalculusFieldResult gradient_checked(const std __attribute__((visibility("default"))) VectorCalculusFieldResult gradient_checked(const std __attribute__((visibility("default"))) VectorField gradient(const std const std::vector< std::string > & vars
VectorField curl(const VectorField &F, const std::vector< std::string > &vars)
VectorCalculusFieldResult gradient_checked(const std::shared_ptr< SymbolicExpr > &f, const std::vector< std::string > &vars, ComputationContext &context)
std::shared_ptr< SymbolicExpr > laplacian(const std::shared_ptr< SymbolicExpr > &f, const std::vector< std::string > &vars)
VectorCalculusExprResult laplacian_checked(const std::shared_ptr< SymbolicExpr > &f, const std::vector< std::string > &vars, ComputationContext &context)
std::shared_ptr< SymbolicExpr > divergence(const VectorField &F, const std::vector< std::string > &vars)
std::vector< std::shared_ptr< SymbolicExpr > > VectorField
向量场由标量表达式组成。
VectorCalculusExprResult divergence_checked(const VectorField &F, const std::vector< std::string > &vars, ComputationContext &context)
Result< VectorField > VectorCalculusFieldResult
Result< std::shared_ptr< SymbolicExpr > > VectorCalculusExprResult
VectorField gradient(const std::shared_ptr< SymbolicExpr > &f, const std::vector< std::string > &vars)