LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
differential_geometry.cpp
浏览该文件的文档.
1#include <stdexcept>
2/**
3 * @file differential_geometry.cpp
4 * @brief 微分几何实现。
5 */
7#include "symbolic_matrix.hpp"
8#include "symbolic.hpp"
12
13#include <algorithm>
14#include <map>
15#include <numeric>
16
17namespace LMCAS {
18
19namespace {
20
22 const std::shared_ptr<SymbolicExpr>& metric,
23 const std::vector<std::string>* coords,
25 const std::string& operation)
26{
27 auto step = context.consume_steps(1, operation);
28 if (!step) return Result<std::shared_ptr<const MatrixNode>>::failure(step.error());
29 if (!metric || !LMCAS::detail::node(metric)) {
32 "metric tensor cannot be null",
33 operation);
34 }
35 auto matrix = std::dynamic_pointer_cast<const MatrixNode>(LMCAS::detail::node(metric));
36 if (!matrix) {
39 "metric tensor must be a matrix",
40 operation);
41 }
42 if (matrix->rows() != matrix->cols()) {
45 "metric tensor must be square",
46 operation);
47 }
48 if (coords) {
49 if (coords->empty()) {
52 "coordinate list cannot be empty",
53 operation);
54 }
55 if (coords->size() != matrix->rows()) {
58 "coordinate count must match metric dimension",
59 operation);
60 }
61 for (const auto& coord : *coords) {
62 if (coord.empty()) {
65 "coordinate names cannot be empty",
66 operation);
67 }
68 }
69 }
70 return Result<std::shared_ptr<const MatrixNode>>::success(matrix);
71}
72
74 std::size_t dim,
75 const std::string& name,
76 const std::string& operation)
77{
78 if (idx < 0 || static_cast<std::size_t>(idx) >= dim) {
80 name + " index is out of bounds",
81 operation);
82 }
83 return Result<void>::success();
84}
85
86Result<void> validate_expr_vector(const std::vector<std::shared_ptr<SymbolicExpr>>& values,
87 const std::vector<std::string>& vars,
88 const std::string& value_name,
89 const std::string& operation)
90{
91 if (vars.empty()) {
93 "variable list cannot be empty",
94 operation);
95 }
96 if (values.size() != vars.size()) {
98 value_name + " dimension must match variable count",
99 operation);
100 }
101 for (const auto& var : vars) {
102 if (var.empty()) {
104 "variable names cannot be empty",
105 operation);
106 }
107 }
108 for (const auto& value : values) {
109 if (!value || !LMCAS::detail::node(value)) {
111 value_name + " components cannot be null",
112 operation);
113 }
114 }
115 return Result<void>::success();
116}
117
119 std::size_t k,
120 std::size_t limit,
121 const std::string& operation)
122{
123 if (k > n) return Result<std::size_t>::success(0);
124 k = std::min(k, n - k);
125 std::size_t value = 1;
126 for (std::size_t i = 1; i <= k; ++i) {
127 std::size_t numerator = n - k + i;
128 std::size_t denominator = i;
129 const auto fraction_gcd = std::gcd(numerator, denominator);
130 numerator /= fraction_gcd;
131 denominator /= fraction_gcd;
132 const auto value_gcd = std::gcd(value, denominator);
133 value /= value_gcd;
134 denominator /= value_gcd;
135 if (denominator != 1) {
138 "binomial coefficient reduction was not exact",
139 operation);
140 }
141 if (numerator != 0 && value > limit / numerator) {
144 "differential-form component count exceeds the expansion budget",
145 operation);
146 }
147 value *= numerator;
148 }
149 if (value > limit) {
152 "differential-form component count exceeds the expansion budget",
153 operation);
154 }
156}
157
158std::vector<std::vector<std::size_t>> index_combinations(std::size_t n,
159 std::size_t k,
160 std::size_t count)
161{
162 std::vector<std::vector<std::size_t>> combinations;
163 combinations.reserve(count);
164 if (k > n) return combinations;
165 if (k == 0) {
166 combinations.emplace_back();
167 return combinations;
168 }
169
170 std::vector<std::size_t> current(k);
171 std::iota(current.begin(), current.end(), 0);
172 while (true) {
173 combinations.push_back(current);
174 std::size_t position = k;
175 while (position > 0) {
176 --position;
177 if (current[position] < n - k + position) break;
178 }
179 if (position == 0 && current[0] == n - k) break;
180 ++current[position];
181 for (std::size_t i = position + 1; i < k; ++i) {
182 current[i] = current[i - 1] + 1;
183 }
184 }
185 return combinations;
186}
187
189 std::shared_ptr<SymbolicExpr>&& result,
190 CasErrc error,
191 const char* message,
192 const std::string& operation)
193{
194 if (!result || !LMCAS::detail::node(result)) {
195 return DifferentialGeometryExprResult::failure(error, message, operation);
196 }
197 return DifferentialGeometryExprResult::success(std::move(result));
198}
199
200Result<void> validate_form_coordinates(const std::vector<std::string>& vars,
201 const std::string& operation)
202{
203 if (vars.empty()) {
205 "variable list cannot be empty", operation);
206 }
207 for (std::size_t i = 0; i < vars.size(); ++i) {
208 if (vars[i].empty()) {
210 "variable names cannot be empty", operation);
211 }
212 const auto current = vars.begin() + static_cast<std::ptrdiff_t>(i);
213 if (std::find(vars.begin(), current, vars[i]) != current) {
215 "coordinate variables must be unique", operation);
216 }
217 }
218 return Result<void>::success();
219}
220
222 const std::vector<std::shared_ptr<SymbolicExpr>>& form_coeffs,
223 int degree,
224 const std::vector<std::string>& vars,
226 const std::string& operation)
227{
228 auto coordinates = validate_form_coordinates(vars, operation);
229 if (!coordinates) return Result<std::size_t>::failure(coordinates.error());
230 if (degree < 0 || static_cast<std::size_t>(degree) > vars.size()) {
233 "form degree must be between zero and the coordinate dimension", operation);
234 }
235 const auto input_count = bounded_binomial(vars.size(),
236 static_cast<std::size_t>(degree),
237 context.limits().max_expansion_terms,
238 operation);
239 if (!input_count) return input_count;
240 if (form_coeffs.size() != input_count.value()) {
243 "form coefficient count does not match degree and dimension", operation);
244 }
245 for (const auto& coeff : form_coeffs) {
246 if (!coeff || !LMCAS::detail::node(coeff)) {
248 "form coefficients cannot be null", operation);
249 }
250 }
251 return input_count;
252}
253
255 const std::vector<std::shared_ptr<SymbolicExpr>>& form_coeffs,
256 const std::vector<std::string>& vars,
257 const std::map<std::vector<std::size_t>, std::size_t>& coefficient_index,
258 const std::vector<std::size_t>& output_index,
259 std::size_t removed,
260 detail::RewriteBudget& budget,
261 const std::string& operation)
262try {
263 auto term_budget = budget.context().consume_steps(4, operation);
264 if (!term_budget) return DifferentialGeometryExprResult::failure(term_budget.error());
265
266 auto source_index = output_index;
267 const std::size_t derivative_variable = source_index[removed];
268 source_index.erase(source_index.begin() + static_cast<std::ptrdiff_t>(removed));
269 const auto source = coefficient_index.find(source_index);
270 if (source == coefficient_index.end()) {
273 "exterior derivative could not locate an input coefficient", operation);
274 }
276 detail::node(form_coeffs[source->second]), vars[derivative_variable], budget));
277 if (removed % 2 != 0) {
278 partial = SymbolicExpr::multiply(SymbolicExpr::number(-1), partial);
279 }
280 budget.measure(detail::node(partial));
281 return DifferentialGeometryExprResult::success(std::move(partial));
282} catch (const CasError& error) {
284} catch (const std::bad_alloc&) {
285 return DifferentialGeometryExprResult::failure(CasErrc::ResourceLimit, "allocation failed", operation);
286} catch (const std::length_error& error) {
288} catch (const std::exception& error) {
290}
291
293 const std::vector<std::shared_ptr<SymbolicExpr>>& form_coeffs,
294 const std::vector<std::string>& vars,
295 const std::map<std::vector<std::size_t>, std::size_t>& coefficient_index,
296 const std::vector<std::size_t>& output_index,
297 detail::RewriteBudget& budget,
298 const std::string& operation)
299try {
300 auto component = SymbolicExpr::number(0);
301 for (std::size_t removed = 0; removed < output_index.size(); ++removed) {
302 auto partial = exterior_derivative_term(
303 form_coeffs, vars, coefficient_index, output_index, removed, budget, operation);
304 if (!partial) return partial;
305 component = SymbolicExpr::add(component, partial.value());
306 }
307 component = detail::make_expression_ptr(
308 detail::normalize_node(detail::node(component), budget));
309 return checked_geometry_expression(std::move(component), CasErrc::InternalInvariant,
310 "exterior derivative produced a null component",
311 operation);
312} catch (const CasError& error) {
314} catch (const std::bad_alloc&) {
315 return DifferentialGeometryExprResult::failure(CasErrc::ResourceLimit, "allocation failed", operation);
316} catch (const std::length_error& error) {
318} catch (const std::exception& error) {
320}
321
322} // namespace
323
324static std::shared_ptr<SymbolicExpr> christoffel_first_kind_impl(
325 const std::shared_ptr<SymbolicExpr>&,
326 const std::vector<std::string>&, int, int, int, ComputationContext& context);
327static std::shared_ptr<SymbolicExpr> christoffel_second_kind_impl(
328 const std::shared_ptr<SymbolicExpr>&,
329 const std::shared_ptr<SymbolicExpr>&,
330 const std::vector<std::string>&, int, int, int, ComputationContext& context);
331static std::shared_ptr<SymbolicExpr> lie_derivative_impl(
332 const std::shared_ptr<SymbolicExpr>&,
333 const std::vector<std::shared_ptr<SymbolicExpr>>&,
334 const std::vector<std::string>&, int, ComputationContext& context);
335
337 const std::shared_ptr<SymbolicExpr>& g_ij,
339{
340 const std::string operation = "metric_inverse";
341 auto metric = validate_metric_matrix(g_ij, nullptr, context, operation);
342 if (!metric) return DifferentialGeometryExprResult::failure(metric.error());
343 auto budget = context.consume_steps(12, operation);
344 if (!budget) return DifferentialGeometryExprResult::failure(budget.error());
345 try {
346 auto result = matrix_inverse_checked(g_ij, context);
347 if (!result) {
348 return DifferentialGeometryExprResult::failure(result.error());
349 }
350 return DifferentialGeometryExprResult::success(result.value());
351 } catch (const std::bad_alloc&) {
353 "allocation failed while inverting metric",
354 operation);
355 } catch (const std::exception& ex) {
357 ex.what(),
358 operation);
359 }
360}
361
363 const std::shared_ptr<SymbolicExpr>& g_ij)
364{
366 return metric_inverse_checked(g_ij, context);
367}
368
369
371 const std::shared_ptr<SymbolicExpr>& g_ij,
372 const std::vector<std::string>& coords,
373 int k, int i, int j,
375{
376 const std::string operation = "christoffel_first_kind";
377 auto metric = validate_metric_matrix(g_ij, &coords, context, operation);
378 if (!metric) {
379 return DifferentialGeometryExprResult::failure(metric.error());
380 }
381 const std::size_t dim = metric.value()->rows();
382 auto k_check = validate_index(k, dim, "k", operation);
383 if (!k_check) {
384 return DifferentialGeometryExprResult::failure(k_check.error());
385 }
386 auto i_check = validate_index(i, dim, "i", operation);
387 if (!i_check) {
388 return DifferentialGeometryExprResult::failure(i_check.error());
389 }
390 auto j_check = validate_index(j, dim, "j", operation);
391 if (!j_check) {
392 return DifferentialGeometryExprResult::failure(j_check.error());
393 }
394 auto budget = context.consume_steps(16, operation);
395 if (!budget) {
396 return DifferentialGeometryExprResult::failure(budget.error());
397 }
398 try {
399 auto result = christoffel_first_kind_impl(g_ij, coords, k, i, j, context);
400 return checked_geometry_expression(std::move(result), CasErrc::Inconclusive,
401 "Christoffel symbol could not be constructed",
402 operation);
403 } catch (const std::bad_alloc&) {
405 "allocation failed while calculating Christoffel symbol",
406 operation);
407 } catch (const std::exception& ex) {
409 ex.what(),
410 operation);
411 }
412}
413
415 const std::shared_ptr<SymbolicExpr>& g_ij,
416 const std::vector<std::string>& coords,
417 int k, int i, int j)
418{
420 return christoffel_first_kind_checked(g_ij, coords, k, i, j, context);
421}
422
423static std::shared_ptr<SymbolicExpr> christoffel_first_kind_impl(
424 const std::shared_ptr<SymbolicExpr>& g_ij,
425 const std::vector<std::string>& coords,
426 int k, int i, int j, ComputationContext& context) {
427
428 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
429 (context).limits().max_ast_nodes, "transform");
430
431 auto mat = std::dynamic_pointer_cast<const MatrixNode>(LMCAS::detail::node(g_ij));
432 if (!mat) return SymbolicExpr::number(0);
433
434 auto g_jk = LMCAS::detail::make_expression_ptr(mat->get(j, k));
435 auto g_ik = LMCAS::detail::make_expression_ptr(mat->get(i, k));
436 auto g_ij_comp = LMCAS::detail::make_expression_ptr(mat->get(i, j));
437
438 auto term1 = detail::make_expression_ptr(detail::differentiate_node(detail::node(g_jk), coords[i], transform_budget));
439 auto term2 = detail::make_expression_ptr(detail::differentiate_node(detail::node(g_ik), coords[j], transform_budget));
440 auto term3 = detail::make_expression_ptr(detail::differentiate_node(detail::node(g_ij_comp), coords[k], transform_budget));
441
442 auto sum12 = SymbolicExpr::add(term1, term2);
443 auto diff = SymbolicExpr::add(sum12, SymbolicExpr::multiply(term3, SymbolicExpr::number(-1)));
444
446 SymbolicExpr::number(Rational(BigInt(1), BigInt(2))),
447 diff)), transform_budget));
448}
449
451 const std::shared_ptr<SymbolicExpr>& g_ij,
452 const std::shared_ptr<SymbolicExpr>& g_up_ij,
453 const std::vector<std::string>& coords,
454 int k, int i, int j,
456{
457 const std::string operation = "christoffel_second_kind";
458 auto metric = validate_metric_matrix(g_ij, &coords, context, operation);
459 if (!metric) {
460 return DifferentialGeometryExprResult::failure(metric.error());
461 }
462 auto inverse_metric = validate_metric_matrix(g_up_ij, &coords, context, operation);
463 if (!inverse_metric) {
464 return DifferentialGeometryExprResult::failure(inverse_metric.error());
465 }
466 const std::size_t dim = metric.value()->rows();
467 auto k_check = validate_index(k, dim, "k", operation);
468 if (!k_check) {
469 return DifferentialGeometryExprResult::failure(k_check.error());
470 }
471 auto i_check = validate_index(i, dim, "i", operation);
472 if (!i_check) {
473 return DifferentialGeometryExprResult::failure(i_check.error());
474 }
475 auto j_check = validate_index(j, dim, "j", operation);
476 if (!j_check) {
477 return DifferentialGeometryExprResult::failure(j_check.error());
478 }
479 auto budget = context.consume_steps(dim * 20 + 12, operation);
480 if (!budget) {
481 return DifferentialGeometryExprResult::failure(budget.error());
482 }
483 try {
484 auto result = christoffel_second_kind_impl(g_ij, g_up_ij, coords, k, i, j, context);
485 return checked_geometry_expression(std::move(result), CasErrc::Inconclusive,
486 "Christoffel symbol could not be constructed",
487 operation);
488 } catch (const std::bad_alloc&) {
490 "allocation failed while calculating Christoffel symbol",
491 operation);
492 } catch (const std::exception& ex) {
494 ex.what(),
495 operation);
496 }
497}
498
500 const std::shared_ptr<SymbolicExpr>& g_ij,
501 const std::shared_ptr<SymbolicExpr>& g_up_ij,
502 const std::vector<std::string>& coords,
503 int k, int i, int j)
504{
506 return christoffel_second_kind_checked(g_ij, g_up_ij, coords, k, i, j, context);
507}
508
509static std::shared_ptr<SymbolicExpr> christoffel_second_kind_impl(
510 const std::shared_ptr<SymbolicExpr>& g_ij,
511 const std::shared_ptr<SymbolicExpr>& g_up_ij,
512 const std::vector<std::string>& coords,
513 int k, int i, int j, ComputationContext& context) {
514
515 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
516 (context).limits().max_ast_nodes, "transform");
517
518 auto mat_up = std::dynamic_pointer_cast<const MatrixNode>(LMCAS::detail::node(g_up_ij));
519 if (!mat_up) return SymbolicExpr::number(0);
520
521 size_t dim = coords.size();
522 auto result = SymbolicExpr::number(0);
523
524 for (size_t m = 0; m < dim; m++) {
525 auto g_up_km = LMCAS::detail::make_expression_ptr(mat_up->get(k, m));
526 auto gamma_first = christoffel_first_kind_impl(g_ij, coords, m, i, j, context);
527 auto term = SymbolicExpr::multiply(g_up_km, gamma_first);
528 result = SymbolicExpr::add(result, term);
529 }
530
531 return detail::make_expression_ptr(detail::normalize_node(detail::node(result), transform_budget));
532}
533
534static std::shared_ptr<SymbolicExpr> riemann_curvature_tensor_with_inverse(
535 const std::shared_ptr<SymbolicExpr>& g_ij,
536 const std::shared_ptr<SymbolicExpr>& g_up_ij,
537 const std::vector<std::string>& coords,
538 int rho, int sigma, int mu, int nu, ComputationContext& context) {
539
540 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
541 (context).limits().max_ast_nodes, "transform");
542 auto gamma_rho_nu_sigma =
543 christoffel_second_kind_impl(g_ij, g_up_ij, coords, rho, nu, sigma, context);
544 auto gamma_rho_mu_sigma =
545 christoffel_second_kind_impl(g_ij, g_up_ij, coords, rho, mu, sigma, context);
546
547 auto term1 = detail::make_expression_ptr(detail::differentiate_node(detail::node(gamma_rho_nu_sigma), coords[mu], transform_budget));
548 auto term2 = detail::make_expression_ptr(detail::differentiate_node(detail::node(gamma_rho_mu_sigma), coords[nu], transform_budget));
549 auto result = SymbolicExpr::add(
550 term1,
551 SymbolicExpr::multiply(term2, SymbolicExpr::number(-1)));
552
553 for (std::size_t lambda = 0; lambda < coords.size(); ++lambda) {
554 auto gamma_rho_mu_lambda =
555 christoffel_second_kind_impl(g_ij, g_up_ij, coords, rho, mu, lambda, context);
556 auto gamma_lambda_nu_sigma =
557 christoffel_second_kind_impl(g_ij, g_up_ij, coords, lambda, nu, sigma, context);
558 auto gamma_rho_nu_lambda =
559 christoffel_second_kind_impl(g_ij, g_up_ij, coords, rho, nu, lambda, context);
560 auto gamma_lambda_mu_sigma =
561 christoffel_second_kind_impl(g_ij, g_up_ij, coords, lambda, mu, sigma, context);
562 auto product_difference = SymbolicExpr::add(
563 SymbolicExpr::multiply(
564 gamma_rho_mu_lambda, gamma_lambda_nu_sigma),
565 SymbolicExpr::multiply(
566 SymbolicExpr::multiply(
567 gamma_rho_nu_lambda, gamma_lambda_mu_sigma),
568 SymbolicExpr::number(-1)));
569 result = SymbolicExpr::add(result, product_difference);
570 }
571 return detail::make_expression_ptr(detail::normalize_node(detail::node(result), transform_budget));
572}
573
575 const std::shared_ptr<SymbolicExpr>& g_ij,
576 const std::vector<std::string>& coords,
577 int rho, int sigma, int mu, int nu,
579{
580 const std::string operation = "riemann_curvature_tensor";
581 auto metric = validate_metric_matrix(g_ij, &coords, context, operation);
582 if (!metric) {
583 return DifferentialGeometryExprResult::failure(metric.error());
584 }
585 const std::size_t dim = metric.value()->rows();
586 auto rho_check = validate_index(rho, dim, "rho", operation);
587 if (!rho_check) {
588 return DifferentialGeometryExprResult::failure(rho_check.error());
589 }
590 auto sigma_check = validate_index(sigma, dim, "sigma", operation);
591 if (!sigma_check) {
592 return DifferentialGeometryExprResult::failure(sigma_check.error());
593 }
594 auto mu_check = validate_index(mu, dim, "mu", operation);
595 if (!mu_check) {
596 return DifferentialGeometryExprResult::failure(mu_check.error());
597 }
598 auto nu_check = validate_index(nu, dim, "nu", operation);
599 if (!nu_check) {
600 return DifferentialGeometryExprResult::failure(nu_check.error());
601 }
602 auto budget = context.consume_steps(dim * 80 + 40, operation);
603 if (!budget) {
604 return DifferentialGeometryExprResult::failure(budget.error());
605 }
606 try {
607 auto inverse_metric = metric_inverse_checked(g_ij, context);
608 if (!inverse_metric) {
609 return DifferentialGeometryExprResult::failure(inverse_metric.error());
610 }
612 g_ij, inverse_metric.value(), coords, rho, sigma, mu, nu, context);
613 return checked_geometry_expression(std::move(result), CasErrc::Inconclusive,
614 "Riemann curvature component could not be constructed",
615 operation);
616 } catch (const std::bad_alloc&) {
618 "allocation failed while calculating Riemann curvature",
619 operation);
620 } catch (const std::exception& ex) {
622 ex.what(),
623 operation);
624 }
625}
626
628 const std::shared_ptr<SymbolicExpr>& g_ij,
629 const std::vector<std::string>& coords,
630 int rho, int sigma, int mu, int nu)
631{
633 return riemann_curvature_tensor_checked(g_ij, coords, rho, sigma, mu, nu, context);
634}
635
636
638 const std::shared_ptr<SymbolicExpr>& f,
639 const std::vector<std::shared_ptr<SymbolicExpr>>& X,
640 const std::vector<std::string>& vars,
641 int order,
643{
644 const std::string operation = "lie_derivative";
645 auto step = context.consume_steps(1, operation);
646 if (!step) return DifferentialGeometryExprResult::failure(step.error());
647 if (!f || !LMCAS::detail::node(f)) {
649 "scalar function cannot be null",
650 operation);
651 }
652 if (order < 0 || order > 64) {
654 "Lie derivative order must be between 0 and 64",
655 operation);
656 }
657 auto vector_check = validate_expr_vector(X, vars, "vector field", operation);
658 if (!vector_check) return DifferentialGeometryExprResult::failure(vector_check.error());
659 auto budget = context.consume_steps(static_cast<std::size_t>(order + 1) * vars.size() * 8 + 8,
660 operation);
661 if (!budget) return DifferentialGeometryExprResult::failure(budget.error());
662 try {
663 auto result = lie_derivative_impl(f, X, vars, order, context);
664 return checked_geometry_expression(std::move(result), CasErrc::Inconclusive,
665 "Lie derivative could not be constructed",
666 operation);
667 } catch (const std::bad_alloc&) {
669 "allocation failed while calculating Lie derivative",
670 operation);
671 } catch (const std::exception& ex) {
673 ex.what(),
674 operation);
675 }
676}
677
679 const std::shared_ptr<SymbolicExpr>& f,
680 const std::vector<std::shared_ptr<SymbolicExpr>>& X,
681 const std::vector<std::string>& vars,
682 int order)
683{
686}
687
688static std::shared_ptr<SymbolicExpr> lie_derivative_impl(
689 const std::shared_ptr<SymbolicExpr>& f,
690 const std::vector<std::shared_ptr<SymbolicExpr>>& X,
691 const std::vector<std::string>& vars,
693
694 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
695 (context).limits().max_ast_nodes, "transform");
696 if (!f || X.size() != vars.size()) return SymbolicExpr::number(0);
697 auto result = f;
698 for (int it = 0; it < order; ++it) {
699 auto acc = SymbolicExpr::number(0);
700 for (size_t i = 0; i < vars.size(); ++i) {
701 auto partial = detail::make_expression_ptr(detail::differentiate_node(detail::node(result), vars[i], transform_budget));
702 acc = SymbolicExpr::add(acc, SymbolicExpr::multiply(X[i], partial));
703 }
704 result = detail::make_expression_ptr(detail::normalize_node(detail::node(acc), transform_budget));
705 }
706 return result;
707}
708
710 const std::vector<std::shared_ptr<SymbolicExpr>>& form_coeffs,
711 int degree,
712 const std::vector<std::string>& vars,
714{
715 const std::string operation = "exterior_derivative";
716 auto step = context.consume_steps(1, operation);
717 if (!step) return DifferentialGeometryVectorResult::failure(step.error());
718 const auto input_count =
719 validate_form_coefficients(form_coeffs, degree, vars, context, operation);
720 if (!input_count) return DifferentialGeometryVectorResult::failure(input_count.error());
721 const auto output_count = bounded_binomial(vars.size(),
722 static_cast<std::size_t>(degree) + 1,
723 context.limits().max_expansion_terms,
724 operation);
725 if (!output_count) return DifferentialGeometryVectorResult::failure(output_count.error());
726 try {
727 detail::RewriteBudget budget(context, context.limits().max_recursion_depth,
728 context.limits().max_ast_nodes, operation.c_str());
729 std::size_t input_nodes = 0;
730 for (const auto& coefficient : form_coeffs) {
731 input_nodes = budget.append_size(
732 input_nodes, budget.measure(detail::node(coefficient)));
733 }
734 const auto input_indices = index_combinations(vars.size(),
735 static_cast<std::size_t>(degree),
736 input_count.value());
737 const auto output_indices = index_combinations(vars.size(),
738 static_cast<std::size_t>(degree) + 1,
739 output_count.value());
740 std::map<std::vector<std::size_t>, std::size_t> coefficient_index;
741 for (std::size_t i = 0; i < input_indices.size(); ++i) {
742 coefficient_index.emplace(input_indices[i], i);
743 }
744
745 std::vector<std::shared_ptr<SymbolicExpr>> result;
746 result.reserve(output_count.value());
747 std::size_t output_nodes = 0;
748 for (const auto& output_index : output_indices) {
749 auto component = exterior_derivative_component(
750 form_coeffs, vars, coefficient_index, output_index, budget, operation);
751 if (!component) return DifferentialGeometryVectorResult::failure(component.error());
752 output_nodes = budget.append_size(
753 output_nodes, budget.measure(detail::node(component.value())));
754 result.push_back(std::move(component.value()));
755 }
756 return DifferentialGeometryVectorResult::success(std::move(result));
757 } catch (const CasError& error) {
759 } catch (const std::bad_alloc&) {
761 "allocation failed while calculating exterior derivative",
762 operation);
763 } catch (const std::exception& ex) {
765 ex.what(),
766 operation);
767 }
768}
769
771 const std::vector<std::shared_ptr<SymbolicExpr>>& form_coeffs,
772 int degree,
773 const std::vector<std::string>& vars)
774{
776 return exterior_derivative_checked(form_coeffs, degree, vars, context);
777}
778
779
780} // namespace LMCAS
Result< void > consume_steps(std::size_t amount=1, const std::string &operation={})
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
ComputationContext & context() const noexcept
std::size_t measure(const std::shared_ptr< const SymbolicNode > &node)
std::size_t append_size(std::size_t current, std::size_t child)
微分几何:度量张量,克里斯托弗符号,黎曼曲率张量.
DifferentialGeometryExprResult exterior_derivative_component(const std::vector< std::shared_ptr< SymbolicExpr > > &form_coeffs, const std::vector< std::string > &vars, const std::map< std::vector< std::size_t >, std::size_t > &coefficient_index, const std::vector< std::size_t > &output_index, detail::RewriteBudget &budget, const std::string &operation)
Result< std::size_t > validate_form_coefficients(const std::vector< std::shared_ptr< SymbolicExpr > > &form_coeffs, int degree, const std::vector< std::string > &vars, ComputationContext &context, const std::string &operation)
Result< std::shared_ptr< const MatrixNode > > validate_metric_matrix(const std::shared_ptr< SymbolicExpr > &metric, const std::vector< std::string > *coords, ComputationContext &context, const std::string &operation)
Result< void > validate_expr_vector(const std::vector< std::shared_ptr< SymbolicExpr > > &values, const std::vector< std::string > &vars, const std::string &value_name, const std::string &operation)
DifferentialGeometryExprResult checked_geometry_expression(std::shared_ptr< SymbolicExpr > &&result, CasErrc error, const char *message, const std::string &operation)
Result< std::size_t > bounded_binomial(std::size_t n, std::size_t k, std::size_t limit, const std::string &operation)
std::vector< std::vector< std::size_t > > index_combinations(std::size_t n, std::size_t k, std::size_t count)
DifferentialGeometryExprResult exterior_derivative_term(const std::vector< std::shared_ptr< SymbolicExpr > > &form_coeffs, const std::vector< std::string > &vars, const std::map< std::vector< std::size_t >, std::size_t > &coefficient_index, const std::vector< std::size_t > &output_index, std::size_t removed, detail::RewriteBudget &budget, const std::string &operation)
Result< void > validate_index(int idx, std::size_t dim, const std::string &name, const std::string &operation)
Result< void > validate_form_coordinates(const std::vector< std::string > &vars, const std::string &operation)
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)
DifferentialGeometryExprResult christoffel_first_kind_checked(const std::shared_ptr< SymbolicExpr > &g_ij, const std::vector< std::string > &coords, int k, int i, int j, ComputationContext &context)
DifferentialGeometryExprResult metric_inverse_checked(const std::shared_ptr< SymbolicExpr > &g_ij, ComputationContext &context)
static std::shared_ptr< SymbolicExpr > lie_derivative_impl(const std::shared_ptr< SymbolicExpr > &, const std::vector< std::shared_ptr< SymbolicExpr > > &, const std::vector< std::string > &, int, ComputationContext &context)
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
Result< std::shared_ptr< SymbolicExpr > > DifferentialGeometryExprResult
const std::vector< FGLMPoly > const MonomialOrder & order
ExpressionResult matrix_inverse_checked(const std::shared_ptr< SymbolicExpr > &A, ComputationContext &context)
static std::shared_ptr< SymbolicExpr > christoffel_second_kind_impl(const std::shared_ptr< SymbolicExpr > &, const std::shared_ptr< SymbolicExpr > &, const std::vector< std::string > &, int, int, int, ComputationContext &context)
DifferentialGeometryExprResult christoffel_second_kind_checked(const std::shared_ptr< SymbolicExpr > &g_ij, const std::shared_ptr< SymbolicExpr > &g_up_ij, const std::vector< std::string > &coords, int k, int i, int j, ComputationContext &context)
static std::shared_ptr< SymbolicExpr > christoffel_first_kind_impl(const std::shared_ptr< SymbolicExpr > &, const std::vector< std::string > &, int, int, int, ComputationContext &context)
DifferentialGeometryExprResult riemann_curvature_tensor_checked(const std::shared_ptr< SymbolicExpr > &g_ij, const std::vector< std::string > &coords, int rho, int sigma, int mu, int nu, ComputationContext &context)
DifferentialGeometryVectorResult exterior_derivative_checked(const std::vector< std::shared_ptr< SymbolicExpr > > &form_coeffs, int degree, const std::vector< std::string > &vars, ComputationContext &context)
__attribute__((visibility("default"))) MatrixRankResult matrix_rank_checked(const std __attribute__((visibility("default"))) MatrixRankResult matrix_rank_checked(const std __attribute__((visibility("default"))) ExpressionResult matrix_rref_checked(const std __attribute__((visibility("default"))) ExpressionResult matrix_rref_checked(const std __attribute__((visibility("default"))) MatrixNullspaceResult matrix_nullspace_checked(const std __attribute__((visibility("default"))) MatrixNullspaceResult matrix_nullspace_checked(const std __attribute__((visibility("default"))) MatrixLinearSolveResult matrix_solve_linear_checked(const std __attribute__((visibility("default"))) MatrixLinearSolveResult matrix_solve_linear_checked(const std int dim
DifferentialGeometryExprResult lie_derivative_checked(const std::shared_ptr< SymbolicExpr > &f, const std::vector< std::shared_ptr< SymbolicExpr > > &X, const std::vector< std::string > &vars, int order, ComputationContext &context)
const std::string const ExprPtr & value
const ExprPtr & denominator
Result< std::vector< std::shared_ptr< SymbolicExpr > > > DifferentialGeometryVectorResult
__attribute__((visibility("default"))) Result< EqvProfile > eqv_profile_from_name(const std const std::string & name
static std::shared_ptr< SymbolicExpr > riemann_curvature_tensor_with_inverse(const std::shared_ptr< SymbolicExpr > &g_ij, const std::shared_ptr< SymbolicExpr > &g_up_ij, const std::vector< std::string > &coords, int rho, int sigma, int mu, int nu, ComputationContext &context)
符号表达式主类 SymbolicExpr 及其工厂方法,运算接口.
内部 AST 定义。
符号矩阵运算:乘法、行列式、逆、旋转/反射/缩放矩阵、特征值。