LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
vector_calculus_extrema.cpp
浏览该文件的文档.
5#include "integration.hpp"
7#include "solver.hpp"
10#include "symbolic_matrix.hpp"
12
13#include <cmath>
14#include <exception>
15#include <limits>
16#include <map>
17#include <memory>
18#include <set>
19#include <stdexcept>
20#include <string>
21#include <vector>
22
23namespace LMCAS {
24
25using namespace vector_calculus_detail;
26
27static std::vector<CriticalPoint> find_extrema_impl(
28 const std::shared_ptr<SymbolicExpr>& f, const std::vector<std::string>& vars,
30 detail::RewriteBudget& transform_budget);
31
33 const std::shared_ptr<SymbolicExpr>& H,
34 const std::vector<std::string>&,
35 const std::map<std::string, std::shared_ptr<SymbolicExpr>>& pt,
36 size_t n,
37 std::vector<double>& numeric_H, ComputationContext& context,
38 detail::RewriteBudget& transform_budget)
39{
40 auto mat_node = std::dynamic_pointer_cast<const MatrixNode>(LMCAS::detail::node(H));
41 if (!mat_node || mat_node->rows() != n || mat_node->cols() != n) {
42 return false;
43 }
44
45 numeric_H.resize(n * n);
46 for (size_t i = 0; i < n; ++i) {
47 for (size_t j = 0; j < n; ++j) {
48 auto elem_node = mat_node->get(i, j);
49 if (!elem_node) {
50 numeric_H[i * n + j] = 0.0;
51 continue;
52 }
53 auto elem = LMCAS::detail::make_expression_ptr(elem_node);
54 /// 代入临界点坐标
55 for (const auto& [var_name, val] : pt) {
56 elem = detail::make_expression_ptr(detail::substitute_node(detail::node(elem), var_name, detail::node(val), transform_budget));
57 if (!elem) {
58 return false;
59 }
60 }
62 if (!elem) {
63 return false;
64 }
65
67 elem, numeric_H[i * n + j], context)) {
68 return false;
69 }
70 }
71 }
72 return true;
73}
74
76 const std::vector<double>& numeric_H, double tol)
77{
78 double a = numeric_H[0], b = numeric_H[1];
79 double c = numeric_H[2], d = numeric_H[3];
80 double det = a * d - b * c;
81 double trace = a + d;
82
83 if (std::abs(det) < tol) {
85 }
86 if (det > 0 && trace > 0) {
88 }
89 if (det > 0 && trace < 0) {
91 }
93}
94
95static std::shared_ptr<SymbolicExpr> symbolic_hessian(
96 const std::vector<double>& numeric_H, size_t n, double tol)
97{
98 std::vector<std::vector<std::shared_ptr<SymbolicExpr>>> grid(n,
99 std::vector<std::shared_ptr<SymbolicExpr>>(n));
100 for (size_t i = 0; i < n; ++i) {
101 for (size_t j = 0; j < n; ++j) {
102 double val = numeric_H[i * n + j];
103 const double rounded = std::round(val);
104 const bool representable_integer =
105 std::isfinite(val) &&
106 rounded >=
107 static_cast<double>(std::numeric_limits<int>::min()) &&
108 rounded <=
109 static_cast<double>(std::numeric_limits<int>::max()) &&
110 std::abs(val - rounded) < tol;
111 if (representable_integer) {
112 grid[i][j] =
113 SymbolicExpr::number(static_cast<int>(rounded));
114 } else {
115 grid[i][j] = SymbolicExpr::number(val);
116 }
117 }
118 }
119 return SymbolicExpr::matrix(grid);
120}
121
123 const std::vector<std::shared_ptr<SymbolicExpr>>& eigenvals, double tol,
125 detail::RewriteBudget& transform_budget)
126{
127 bool all_positive = true;
128 bool all_negative = true;
129 bool has_zero = false;
130
131 for (const auto& ev : eigenvals) {
132 if (!ev) {
134 }
135 auto ev_simplified = detail::make_expression_ptr(detail::normalize_node(detail::node(ev), transform_budget));
136 double val = 0.0;
137 if (!vector_calculus_checked_finite_numeric(ev_simplified, val, context)) {
139 }
140
141 if (std::abs(val) < tol) {
142 has_zero = true;
143 all_positive = false;
144 all_negative = false;
145 } else if (val > 0) {
146 all_negative = false;
147 } else {
148 all_positive = false;
149 }
150 }
151
152 if (has_zero) {
154 }
155 if (all_positive) {
157 }
158 if (all_negative) {
160 }
162}
163
164// The 1e-10 threshold matches the existing real-eigenvalue classification
165// tolerance used by the one- and two-dimensional paths.
167 const std::vector<double>& numeric_H, size_t n, ComputationContext& context,
168 detail::RewriteBudget& transform_budget)
169{
170 const double tol = 1e-10;
171 if (n == 1) {
172 const double value = numeric_H[0];
173 if (std::abs(value) < tol) {
175 }
176 if (value > 0) {
178 }
180 }
181 if (n == 2) {
182 return classify_hessian_pair(numeric_H, tol);
183 }
184 auto matrix = symbolic_hessian(numeric_H, n, tol);
185 auto eigenvalues = matrix_eigenvalues_checked(matrix, context);
186 if (!eigenvalues) {
187 if (eigenvalues.error().code != CasErrc::Inconclusive &&
188 eigenvalues.error().code != CasErrc::UnsupportedExpression) {
189 throw eigenvalues.error();
190 }
192 }
193 return classify_hessian_eigenvalues(eigenvalues.value(), tol, context, transform_budget);
194}
195
196
198 const std::shared_ptr<SymbolicExpr>& f,
199 const std::vector<std::string>& vars,
201{
202 detail::RewriteBudget transform_budget(context, context.limits().max_recursion_depth,
203 context.limits().max_ast_nodes, "find_extrema");
204 const std::string operation = "find_extrema";
205 auto valid = vector_calculus_validate_expr_vars(f, vars, context, operation);
206 if (!valid) {
207 return ExtremaResult::failure(valid.error());
208 }
209 auto distinct = vector_calculus_validate_distinct_vars(vars, vars.size(), context, operation);
210 if (!distinct) {
211 return ExtremaResult::failure(distinct.error());
212 }
213 auto step = context.consume_steps(vars.size() * vars.size() + vars.size() * 8 + 8,
214 operation);
215 if (!step) {
216 return ExtremaResult::failure(step.error());
217 }
218
219 try {
220 std::vector<std::shared_ptr<SymbolicExpr>> gradient;
221 gradient.reserve(vars.size());
222 for (const auto& var : vars) {
223 auto partial = vector_calculus_differentiate_strict(f, var, operation, transform_budget);
224 if (!partial) {
225 return ExtremaResult::failure(partial.error());
226 }
227 gradient.push_back(std::move(partial.value()));
228 }
229
230 auto extrema = find_extrema_impl(f, vars, context, transform_budget);
231 if (extrema.empty()) {
234 "extrema solver produced no verifiable critical points in the supported domain",
235 operation);
236 }
237
238 for (const auto& cp : extrema) {
239 if (!vector_calculus_point_has_vars(cp.point, vars)) {
242 "extrema candidate omits one or more variables",
243 operation);
244 }
245 for (const auto& partial : gradient) {
246 if (!vector_calculus_expr_zero_after_substitution(partial, cp.point, context, transform_budget)) {
249 "extrema candidate does not verify against the gradient",
250 operation);
251 }
252 }
253 if (cp.classification == CriticalPointClassification::Inconclusive) {
256 "extrema candidate has no verified classification",
257 operation);
258 }
259 }
260 return ExtremaResult::success(std::move(extrema));
261 } catch (const CasError& error) {
262 return ExtremaResult::failure(error);
263 } catch (const std::bad_alloc&) {
265 "extrema allocation failed",
266 operation);
267 } catch (const std::length_error& error) {
268 return ExtremaResult::failure(CasErrc::ResourceLimit, error.what(), operation);
269 } catch (const std::exception& e) {
270 return ExtremaResult::failure(CasErrc::InternalInvariant, e.what(), operation);
271 }
272}
273
275 const std::shared_ptr<SymbolicExpr>& f,
276 const std::vector<std::string>& vars)
277{
280}
281
282static std::vector<CriticalPoint> find_extrema_impl(
283 const std::shared_ptr<SymbolicExpr>& f, const std::vector<std::string>& vars,
285 detail::RewriteBudget& transform_budget)
286{
287 if (!f || vars.empty()) {
288 return {};
289 }
290
291 size_t n = vars.size();
292
293 /// 计算梯度 gradf
294 std::vector<std::shared_ptr<SymbolicExpr>> grad_eqs;
295 grad_eqs.reserve(n);
296 for (const auto& var : vars) {
297 auto partial = detail::make_expression_ptr(detail::differentiate_node(detail::node(f), var, transform_budget));
298 if (partial) {
299 partial = detail::make_expression_ptr(detail::normalize_node(detail::node(partial), transform_budget));
300 }
301 grad_eqs.push_back(partial);
302 }
303
304 /// 求解 gradf = 0 系统(使用多项式系统求解器)
305 std::vector<std::map<std::string, std::shared_ptr<SymbolicExpr>>> solutions;
306
307 std::vector<SymbolicExpr> poly_eqs;
308 poly_eqs.reserve(n);
309 for (const auto& eq : grad_eqs) {
310 if (eq) poly_eqs.push_back(*eq);
311 }
312 if (poly_eqs.size() == n) {
313 auto checked_solutions =
314 Solver::solve_polynomial_system_checked(poly_eqs, vars, context);
315 if (!checked_solutions &&
316 checked_solutions.error().code != CasErrc::Inconclusive &&
317 checked_solutions.error().code != CasErrc::UnsupportedExpression) {
318 throw checked_solutions.error();
319 }
320 const auto poly_solutions = checked_solutions
321 ? std::move(checked_solutions.value())
322 : std::vector<std::map<std::string, SymbolicExpr>>{};
323 for (const auto& sol : poly_solutions) {
324 std::map<std::string, std::shared_ptr<SymbolicExpr>> pt;
325 for (const auto& [name, val] : sol) {
327 }
328 solutions.push_back(pt);
329 }
330 }
331
332 /// 如果多项式求解器失败,尝试线性求解器
333 if (solutions.empty()) {
334 auto solved = solver_detail::solve_linear_system_impl(poly_eqs, vars, context);
335 if (!solved.empty()) {
336 std::map<std::string, std::shared_ptr<SymbolicExpr>> point;
337 for (auto& [variable, value] : solved) {
338 point.emplace(variable, detail::make_expression_ptr(std::move(value)));
339 }
340 solutions.push_back(std::move(point));
341 }
342 }
343
344 if (solutions.empty()) {
345 return {};
346 }
347
348 /// 计算海森矩阵
349 auto H = hessian_impl(f, vars, transform_budget);
350
351 /// 对每个临界点进行分类
352 std::vector<CriticalPoint> result;
353 result.reserve(solutions.size());
354
355 for (const auto& sol : solutions) {
356 CriticalPoint cp;
357 cp.point = sol;
358
359 /// 在临界点处求值海森矩阵
360 std::vector<double> numeric_H;
361 if (vector_calculus_evaluate_hessian_at_point(H, vars, sol, n, numeric_H, context, transform_budget)) {
362 cp.classification = vector_calculus_classify_critical_point(numeric_H, n, context, transform_budget);
363 } else {
365 }
366
367 result.push_back(std::move(cp));
368 }
369
370 return result;
371}
372
373std::vector<CriticalPoint> find_extrema(
374 const std::shared_ptr<SymbolicExpr>& f, const std::vector<std::string>& vars) {
376 detail::RewriteBudget transform_budget(context, context.limits().max_recursion_depth,
377 context.limits().max_ast_nodes, "find_extrema");
378 return find_extrema_impl(f, vars, context, transform_budget);
379}
380
381}
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(std::vector< CriticalPoint > value)
Symbolic integration APIs.
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)
SymbolicNodePtr substitute_node(const SymbolicNodePtr &node, const std::string &variable, const SymbolicNodePtr &replacement, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::map< std::string, SymbolicExpr > solve_linear_system_impl(const std::vector< SymbolicExpr > &equations, const std::vector< std::string > &variables, ComputationContext &context)
bool vector_calculus_point_has_vars(const std::map< std::string, std::shared_ptr< SymbolicExpr > > &point, const std::vector< std::string > &vars)
Result< void > vector_calculus_validate_distinct_vars(const std::vector< std::string > &vars, std::size_t expected, ComputationContext &context, const std::string &operation)
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)
VectorCalculusExprResult vector_calculus_differentiate_strict(const std::shared_ptr< SymbolicExpr > &expr, const std::string &variable, const std::string &operation, detail::RewriteBudget &transform_budget)
bool vector_calculus_expr_zero_after_substitution(const std::shared_ptr< SymbolicExpr > &expr, const std::map< std::string, std::shared_ptr< SymbolicExpr > > &point, ComputationContext &context, detail::RewriteBudget &transform_budget)
bool vector_calculus_checked_finite_numeric(const std::shared_ptr< SymbolicExpr > &expr, double &value, ComputationContext &context)
std::shared_ptr< SymbolicExpr > hessian_impl(const std::shared_ptr< SymbolicExpr > &f, const std::vector< std::string > &vars, detail::RewriteBudget &transform_budget)
MatrixEigenvalueResult matrix_eigenvalues_checked(const std::shared_ptr< SymbolicExpr > &A, ComputationContext &context)
const std::string const LimitExprPtr & point
const std::string & variable
ExprResult eq(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
static CriticalPointClassification classify_hessian_eigenvalues(const std::vector< std::shared_ptr< SymbolicExpr > > &eigenvals, double tol, ComputationContext &context, detail::RewriteBudget &transform_budget)
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
const VectorField const VectorField & c
static std::shared_ptr< SymbolicExpr > symbolic_hessian(const std::vector< double > &numeric_H, size_t n, double tol)
const MultiPoly & b
__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 const std::shared_ptr< SymbolicExpr > & a
static CriticalPointClassification vector_calculus_classify_critical_point(const std::vector< double > &numeric_H, size_t n, ComputationContext &context, detail::RewriteBudget &transform_budget)
static CriticalPointClassification classify_hessian_pair(const std::vector< double > &numeric_H, double tol)
const std::string const ExprPtr & value
static bool vector_calculus_evaluate_hessian_at_point(const std::shared_ptr< SymbolicExpr > &H, const std::vector< std::string > &, const std::map< std::string, std::shared_ptr< SymbolicExpr > > &pt, size_t n, std::vector< double > &numeric_H, ComputationContext &context, detail::RewriteBudget &transform_budget)
ExtremaResult find_extrema_checked(const std::shared_ptr< SymbolicExpr > &f, const std::vector< std::string > &vars, ComputationContext &context)
Result< std::vector< CriticalPoint > > ExtremaResult
std::vector< CriticalPoint > find_extrema(const std::shared_ptr< SymbolicExpr > &f, const std::vector< std::string > &vars)
__attribute__((visibility("default"))) Result< EqvProfile > eqv_profile_from_name(const std const std::string & name
VectorField gradient(const std::shared_ptr< SymbolicExpr > &f, const std::vector< std::string > &vars)
static std::vector< CriticalPoint > find_extrema_impl(const std::shared_ptr< SymbolicExpr > &f, const std::vector< std::string > &vars, ComputationContext &context, detail::RewriteBudget &transform_budget)
方程求解策略调度器 solve_dispatch 及相关选项结构体.
多项式方程组求解器 Solver,包含 Gröbner 基、线性系统求解。
临界点的坐标、分类及成立条件。
CriticalPointClassification classification
std::map< std::string, std::shared_ptr< SymbolicExpr > > point
内部 AST 定义。
符号矩阵运算:乘法、行列式、逆、旋转/反射/缩放矩阵、特征值。