LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
calculus_curvature.cpp
浏览该文件的文档.
1#include <stdexcept>
7
8namespace LMCAS {
9
10using namespace calculus_utils_detail;
11
13 const ExprPtr& expression, const std::string& variable,
14 ComputationContext& context, const char* operation)
15try {
17 expression, context, operation, "differentiate",
18 [&variable, &context, operation](const SymbolicExpr& value) {
19 detail::RewriteBudget budget(context, context.limits().max_recursion_depth,
20 context.limits().max_ast_nodes, operation);
23 });
24} catch (const CasError& error) {
25 return ExpressionResult::failure(error);
26} catch (const std::bad_alloc&) {
27 return ExpressionResult::failure(CasErrc::ResourceLimit, "allocation failed", operation);
28} catch (const std::length_error& error) {
29 return ExpressionResult::failure(CasErrc::ResourceLimit, error.what(), operation);
30} catch (const std::exception& error) {
31 return ExpressionResult::failure(CasErrc::InternalInvariant, error.what(), operation);
32}
33
35 const std::shared_ptr<SymbolicExpr>& f, const std::string& var,
37try {
38 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
39 (context).limits().max_ast_nodes, "transform");
40 const std::string operation = "curvature";
41 auto input = calculus_utils_validate_expr(f, var, context, operation);
42 if (!input) {
43 return ExpressionResult::failure(input.error());
44 }
45
46 auto first = checked_derivative(f, var, context, operation.c_str());
47 if (!first) {
48 return ExpressionResult::failure(first.error());
49 }
50 const auto& f_prime = first.value();
51 auto second = checked_derivative(f_prime, var, context, operation.c_str());
52 if (!second) {
53 return ExpressionResult::failure(second.error());
54 }
55 const auto& f_double_prime = second.value();
56
57 auto abs_f_pp = calculus_utils_make_abs(f_double_prime);
58 if (!abs_f_pp || !LMCAS::detail::node(abs_f_pp)) {
60 "absolute value node construction failed",
61 operation);
62 }
63
64 auto f_prime_sq = SymbolicExpr::power(f_prime, SymbolicExpr::number(2));
65 auto one_plus_fp_sq = SymbolicExpr::add(SymbolicExpr::number(1), f_prime_sq);
66
67 auto three_half = SymbolicExpr::number(Rational(3, 2));
68 auto denom = SymbolicExpr::power(one_plus_fp_sq, three_half);
69 auto result = SymbolicExpr::divide(abs_f_pp, denom);
70 auto simplified = detail::make_expression_ptr(detail::normalize_node(detail::node(result), transform_budget));
71 return ExpressionResult::success(simplified ? simplified : result);
72} catch (const CasError& error) {
73 return ExpressionResult::failure(error);
74} catch (const std::bad_alloc&) {
75 return ExpressionResult::failure(CasErrc::ResourceLimit, "allocation failed", "curvature");
76} catch (const std::length_error& error) {
77 return ExpressionResult::failure(CasErrc::ResourceLimit, error.what(), "curvature");
78} catch (const std::exception& error) {
79 return ExpressionResult::failure(CasErrc::InternalInvariant, error.what(), "curvature");
80}
81
83 const std::shared_ptr<SymbolicExpr>& f, const std::string& var)
84{
86 return curvature_checked(f, var, context);
87}
88
89
91 const std::shared_ptr<SymbolicExpr>& x_t,
92 const std::shared_ptr<SymbolicExpr>& y_t, const std::string& t,
94try {
95 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
96 (context).limits().max_ast_nodes, "transform");
97 const std::string operation = "curvature_parametric";
98 auto input = calculus_utils_validate_two_exprs(x_t, y_t, t, context, operation);
99 if (!input) {
100 return ExpressionResult::failure(input.error());
101 }
102
103 auto x_first = checked_derivative(x_t, t, context, operation.c_str());
104 if (!x_first) {
105 return ExpressionResult::failure(x_first.error());
106 }
107 const auto& x_prime = x_first.value();
108 auto x_second = checked_derivative(x_prime, t, context, operation.c_str());
109 if (!x_second) {
110 return ExpressionResult::failure(x_second.error());
111 }
112 const auto& x_double_prime = x_second.value();
113
114 auto y_first = checked_derivative(y_t, t, context, operation.c_str());
115 if (!y_first) {
116 return ExpressionResult::failure(y_first.error());
117 }
118 const auto& y_prime = y_first.value();
119 auto y_second = checked_derivative(y_prime, t, context, operation.c_str());
120 if (!y_second) {
121 return ExpressionResult::failure(y_second.error());
122 }
123 const auto& y_double_prime = y_second.value();
124
125 if (x_prime->is_zero() && y_prime->is_zero()) {
127 "parametric curvature is undefined for zero velocity",
128 operation);
129 }
130
131 auto cross_term = SymbolicExpr::add(
132 SymbolicExpr::multiply(x_prime, y_double_prime),
133 SymbolicExpr::multiply(
134 SymbolicExpr::number(-1),
135 SymbolicExpr::multiply(y_prime, x_double_prime)));
136
137 auto abs_cross = calculus_utils_make_abs(cross_term);
138 if (!abs_cross || !LMCAS::detail::node(abs_cross)) {
140 "absolute value node construction failed",
141 operation);
142 }
143
144 auto x_prime_sq = SymbolicExpr::power(x_prime, SymbolicExpr::number(2));
145 auto y_prime_sq = SymbolicExpr::power(y_prime, SymbolicExpr::number(2));
146 auto sum_sq = SymbolicExpr::add(x_prime_sq, y_prime_sq);
147
148 auto three_half = SymbolicExpr::number(Rational(3, 2));
149 auto denom = SymbolicExpr::power(sum_sq, three_half);
150 auto result = SymbolicExpr::divide(abs_cross, denom);
151 auto simplified = detail::make_expression_ptr(detail::normalize_node(detail::node(result), transform_budget));
152 return ExpressionResult::success(simplified ? simplified : result);
153} catch (const CasError& error) {
154 return ExpressionResult::failure(error);
155} catch (const std::bad_alloc&) {
156 return ExpressionResult::failure(CasErrc::ResourceLimit, "allocation failed", "curvature_parametric");
157} catch (const std::length_error& error) {
158 return ExpressionResult::failure(CasErrc::ResourceLimit, error.what(), "curvature_parametric");
159} catch (const std::exception& error) {
160 return ExpressionResult::failure(CasErrc::InternalInvariant, error.what(), "curvature_parametric");
161}
162
164 const std::shared_ptr<SymbolicExpr>& x_t,
165 const std::shared_ptr<SymbolicExpr>& y_t, const std::string& t)
166{
168 return curvature_parametric_checked(x_t, y_t, t, context);
169}
170
171
172
174 const std::shared_ptr<SymbolicExpr>& f,
175 const std::shared_ptr<SymbolicExpr>& f_prime,
176 const std::shared_ptr<SymbolicExpr>& f_double_prime,
177 const std::shared_ptr<SymbolicExpr>& point, const std::string& var,
178 const FactsQuery& facts, const std::string& operation, ComputationContext& context) try {
179 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
180 (context).limits().max_ast_nodes, "transform");
182 auto first = detail::make_expression_ptr(detail::substitute_node(detail::node(f_prime), var, detail::node(point), transform_budget));
183 auto second = detail::make_expression_ptr(detail::substitute_node(detail::node(f_double_prime), var, detail::node(point), transform_budget));
184 for (const auto& expression : {value, first, second}) {
185 auto defined = detail::query_definedness(detail::node(expression), facts, Domain::Real, context);
186 if (!defined) { return Result<bool>::failure(defined.error()); }
187 if (defined.value() == Tribool::False) { return false; }
188 auto real_value = detail::query_real_value(detail::node(expression), facts, context);
189 if (!real_value) { return Result<bool>::failure(real_value.error()); }
190 if (real_value.value() == Tribool::False) { return false; }
191 if (defined.value() != Tribool::True || real_value.value() != Tribool::True) {
193 "real curve domain at an inflection candidate is unproved",
194 operation);
195 }
196 }
197 return true;
198} catch (const CasError& error) {
199 return Result<bool>::failure(error);
200} catch (const std::bad_alloc&) {
201 return Result<bool>::failure(CasErrc::ResourceLimit, "allocation failed", operation);
202} catch (const std::length_error& error) {
203 return Result<bool>::failure(CasErrc::ResourceLimit, error.what(), operation);
204} catch (const std::exception& error) {
205 return Result<bool>::failure(CasErrc::InternalInvariant, error.what(), operation);
206}
207
209 const FiniteSolutions& finite, const std::shared_ptr<SymbolicExpr>& f,
210 const std::shared_ptr<SymbolicExpr>& f_prime,
211 const std::shared_ptr<SymbolicExpr>& f_double_prime, const std::string& var,
212 const FactsQuery& facts, ComputationContext& context, const std::string& operation) {
213 std::vector<std::shared_ptr<SymbolicExpr>> points;
214 points.reserve(finite.values.size());
215 for (const auto& solution : finite.values) {
216 auto step = context.consume_steps(1, operation);
217 if (!step) { return SymbolicExprVectorResult::failure(step.error()); }
218 if (!solution.value || !LMCAS::detail::node(solution.value)) {
220 "checked solver returned a null inflection candidate", operation);
221 }
222 auto real = detail::query_real_value(detail::node(solution.value), facts, context);
224 if (real.value() == Tribool::False) { continue; }
225 if (real.value() != Tribool::True || !solution.conditions.empty()) {
227 "inflection candidate is not proved unconditionally real", operation);
228 }
229 auto defined = inflection_curve_defined(
230 f, f_prime, f_double_prime, solution.value, var, facts, operation, context);
231 if (!defined) { return SymbolicExprVectorResult::failure(defined.error()); }
232 if (!defined.value()) { continue; }
233 points.push_back(solution.value);
234 }
235 return SymbolicExprVectorResult::success(std::move(points));
236}
237
239 const std::shared_ptr<SymbolicExpr>& f, const std::string& var,
241try {
242 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
243 (context).limits().max_ast_nodes, "transform");
244 const std::string operation = "inflection_points";
245 auto input = calculus_utils_validate_expr(f, var, context, operation);
246 if (!input) {
247 return SymbolicExprVectorResult::failure(input.error());
248 }
249
250 auto first = checked_derivative(f, var, context, operation.c_str());
251 if (!first) {
252 return SymbolicExprVectorResult::failure(first.error());
253 }
254 const auto& f_prime = first.value();
255
256 auto second = checked_derivative(f_prime, var, context, operation.c_str());
257 if (!second) {
258 return SymbolicExprVectorResult::failure(second.error());
259 }
260 const auto& f_double_prime = second.value();
261
262 auto equation = detail::make_expression_ptr(detail::normalize_node(detail::node(f_double_prime), transform_budget));
263 if (!equation || !LMCAS::detail::node(equation)) { equation = f_double_prime; }
264
265 auto solved = solve_equation(equation, var, context, SolveOptions{});
266 if (!solved) {
267 return SymbolicExprVectorResult::failure(solved.error());
268 }
269
270 const auto& solutions = solved.value();
271 if (std::holds_alternative<EmptySolutions>(solutions)) {
273 }
274 std::optional<detail::AssumptionFacts> assumed_facts;
275 if (context.assumptions()) { assumed_facts.emplace(*context.assumptions()); }
276 const FactsQuery& facts = assumed_facts
277 ? static_cast<const FactsQuery&>(*assumed_facts) : detail::no_facts();
278 if (const auto* finite = std::get_if<FiniteSolutions>(&solutions)) {
280 *finite, f, f_prime, f_double_prime, var, facts, context, operation);
281 }
282
283
286 "inflection equation is outside the finite exact support domain",
287 operation);
288} catch (const CasError& error) {
290} catch (const std::bad_alloc&) {
291 return SymbolicExprVectorResult::failure(CasErrc::ResourceLimit, "allocation failed", "inflection_points");
292} catch (const std::length_error& error) {
293 return SymbolicExprVectorResult::failure(CasErrc::ResourceLimit, error.what(), "inflection_points");
294} catch (const std::exception& error) {
295 return SymbolicExprVectorResult::failure(CasErrc::InternalInvariant, error.what(), "inflection_points");
296}
297
299 const std::shared_ptr<SymbolicExpr>& f, const std::string& var)
300{
302 return inflection_points_checked(f, var, context);
303}
304
305}
CasError & error()
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(std::shared_ptr< SymbolicExpr > value)
std::shared_ptr< SymbolicExpr > calculus_utils_make_abs(const std::shared_ptr< SymbolicExpr > &expr)
Result< void > calculus_utils_validate_two_exprs(const std::shared_ptr< SymbolicExpr > &first, const std::shared_ptr< SymbolicExpr > &second, const std::string &var, ComputationContext &context, const std::string &operation)
Result< void > calculus_utils_validate_expr(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, ComputationContext &context, 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
ExpressionResult checked_transform_expr(const ExprPtr &expression, ComputationContext &context, const char *operation, const char *transform_name, Transform &&transform)
const FactsQuery & no_facts() noexcept
Result< Tribool > query_definedness(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context, bool *violated_real_restriction)
Result< Tribool > query_real_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
SymbolicNodePtr substitute_node(const SymbolicNodePtr &node, const std::string &variable, const SymbolicNodePtr &replacement, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
const std::string const LimitExprPtr & point
const std::string & variable
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult real(const ExprPtr &expression, ComputationContext &context)
@ Real
Real numbers
static ExpressionResult checked_derivative(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const char *operation)
static Result< bool > inflection_curve_defined(const std::shared_ptr< SymbolicExpr > &f, const std::shared_ptr< SymbolicExpr > &f_prime, const std::shared_ptr< SymbolicExpr > &f_double_prime, const std::shared_ptr< SymbolicExpr > &point, const std::string &var, const FactsQuery &facts, const std::string &operation, ComputationContext &context)
@ True
Property definitely holds
@ False
Property definitely does not hold
LMCAS::SolveResult solve_equation(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, ComputationContext &context, const SolveOptions &opts)
Result< std::shared_ptr< SymbolicExpr > > ExpressionResult
Result of an operation that produces a symbolic expression.
std::vector< FiniteSolution > values
SymbolicExprVectorResult inflection_points_checked(const std::shared_ptr< SymbolicExpr > &f, const std::string &var, ComputationContext &context)
Result< std::vector< std::shared_ptr< SymbolicExpr > > > SymbolicExprVectorResult
std::shared_ptr< SymbolicExpr > ExprPtr
const std::string const ExprPtr & value
ExpressionResult curvature_parametric_checked(const std::shared_ptr< SymbolicExpr > &x_t, const std::shared_ptr< SymbolicExpr > &y_t, const std::string &t, ComputationContext &context)
ExpressionResult curvature_checked(const std::shared_ptr< SymbolicExpr > &f, const std::string &var, ComputationContext &context)
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string & t
static SymbolicExprVectorResult classify_inflection_candidates(const FiniteSolutions &finite, const std::shared_ptr< SymbolicExpr > &f, const std::shared_ptr< SymbolicExpr > &f_prime, const std::shared_ptr< SymbolicExpr > &f_double_prime, const std::string &var, const FactsQuery &facts, ComputationContext &context, const std::string &operation)
方程求解选项,控制数值求解行为和结果形式.
方程求解策略调度器 solve_dispatch 及相关选项结构体.
内部 AST 定义。