LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
symbolic_matrix_eigen.cpp
浏览该文件的文档.
1#include <stdexcept>
4
8#include <new>
9#include <set>
10
11namespace LMCAS {
12using namespace detail::matrix_api;
14 const std::shared_ptr<SymbolicExpr>& A, const std::string& variable,
16 constexpr const char* operation = "matrix_characteristic_polynomial";
17 auto matrix_result = require_square_matrix(A, context, operation);
18 if (!matrix_result) return ExpressionResult::failure(matrix_result.error());
19 if (variable.empty()) {
22 "characteristic polynomial variable cannot be empty", operation);
23 }
24 try {
25 const auto& matrix = *matrix_result.value();
26 std::vector<std::vector<std::shared_ptr<SymbolicExpr>>> entries(
27 matrix.rows(),
28 std::vector<std::shared_ptr<SymbolicExpr>>(matrix.cols()));
29 auto lambda = SymbolicExpr::variable(variable);
30 for (std::size_t row = 0; row < matrix.rows(); ++row) {
31 for (std::size_t column = 0; column < matrix.cols(); ++column) {
33 matrix.get(row, column));
34 entries[row][column] = row == column
35 ? SymbolicExpr::add(
36 value,
37 SymbolicExpr::multiply(
38 lambda, SymbolicExpr::number(-1)))
39 : std::move(value);
40 }
41 }
42 auto determinant = matrix_determinant_checked(
43 SymbolicExpr::matrix(entries), context);
44 if (!determinant) return ExpressionResult::failure(determinant.error());
46 std::move(determinant.value()));
47 } catch (const std::bad_alloc&) {
50 "allocation failed while constructing characteristic polynomial",
51 operation);
52 } catch (const std::exception& ex) {
54 CasErrc::InternalInvariant, ex.what(), operation);
55 }
56}
57
59 const std::shared_ptr<SymbolicExpr>& A, const std::string& variable) {
62}
63
65 const std::shared_ptr<SymbolicExpr>& A, ComputationContext& context) try {
66 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
67 (context).limits().max_ast_nodes, "transform");
68 constexpr const char* operation = "matrix_eigenvalues";
69 auto matrix_result = require_square_matrix(A, context, operation);
70 if (!matrix_result) {
71 return MatrixEigenvalueResult::failure(matrix_result.error());
72 }
73 const auto& matrix = *matrix_result.value();
74 bool triangular = true;
75 for (std::size_t row = 0; row < matrix.rows() && triangular; ++row) {
76 for (std::size_t column = 0; column < row; ++column) {
77 auto value =
78 detail::make_expression_ptr(detail::normalize_node(matrix.get(row, column), transform_budget));
79 if (!detail::node(value)->is_zero()) {
80 triangular = false;
81 break;
82 }
83 }
84 }
85 if (triangular) {
86 std::vector<std::shared_ptr<SymbolicExpr>> values;
87 values.reserve(matrix.rows());
88 for (std::size_t index = 0; index < matrix.rows(); ++index) {
89 values.push_back(
90 detail::make_expression_ptr(detail::normalize_node(matrix.get(index, index), transform_budget)));
91 }
92 return MatrixEigenvalueResult::success(std::move(values));
93 }
94
96 A, "lambda", context);
97 if (!polynomial) {
98 return MatrixEigenvalueResult::failure(polynomial.error());
99 }
101 polynomial.value(), "lambda", context, SolveOptions{});
103 std::vector<std::shared_ptr<SymbolicExpr>> values;
104 std::set<std::string> seen;
105 for (auto& root : roots.value()) {
106 const auto key = root->to_string();
107 if (seen.insert(key).second) values.push_back(std::move(root));
108 }
109 if (values.empty()) {
112 "eigenvalue solver produced no finite roots", operation);
113 }
114 return MatrixEigenvalueResult::success(std::move(values));
115} catch (const CasError& error) {
117} catch (const std::bad_alloc&) {
118 return MatrixEigenvalueResult::failure(CasErrc::ResourceLimit, "allocation failed", "matrix_eigenvalues");
119} catch (const std::length_error& error) {
120 return MatrixEigenvalueResult::failure(CasErrc::ResourceLimit, error.what(), "matrix_eigenvalues");
121} catch (const std::exception& error) {
122 return MatrixEigenvalueResult::failure(CasErrc::InternalInvariant, error.what(), "matrix_eigenvalues");
123}
124
126 const std::shared_ptr<SymbolicExpr>& A) {
129}
130
131namespace {
132using Eigenspaces = std::vector<std::pair<ExprPtr, std::vector<std::vector<ExprPtr>>>>;
133
135 const Eigenspaces& spaces, ComputationContext& context,
136 const detail::AssumptionFacts& facts) try {
137 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
138 (context).limits().max_ast_nodes, "transform");
139 constexpr const char* operation = "matrix_eigenspaces";
140 for (const auto& space : spaces) {
141 if (detail::node(lambda)->equals(*detail::node(space.first))) { return true; }
142 auto difference = SymbolicExpr::add(lambda,
143 SymbolicExpr::multiply(SymbolicExpr::number(-1), space.first));
144 auto proof = detail::classify_exact_zero(difference, context, operation);
145 if (!proof) { return Result<bool>::failure(proof.error()); }
146 if (proof.value() == detail::ZeroProof::Zero) { return true; }
147 auto nonzero = detail::query_nonzero_value(detail::normalize_node(detail::node(difference), transform_budget), facts, Domain::Complex, context);
148 if (!nonzero) { return Result<bool>::failure(nonzero.error()); }
149 if (nonzero.value() != Tribool::True) {
151 "eigenvalues cannot be proved pointwise distinct", operation);
152 }
153 }
154 return false;
155} catch (const CasError& error) {
156 return Result<bool>::failure(error);
157} catch (const std::bad_alloc&) {
158 return Result<bool>::failure(CasErrc::ResourceLimit, "allocation failed", "matrix_eigenspaces");
159} catch (const std::length_error& error) {
160 return Result<bool>::failure(CasErrc::ResourceLimit, error.what(), "matrix_eigenspaces");
161} catch (const std::exception& error) {
162 return Result<bool>::failure(CasErrc::InternalInvariant, error.what(), "matrix_eigenspaces");
163}
164
166 const ExprPtr& lambda, ComputationContext& context) try {
167 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
168 (context).limits().max_ast_nodes, "transform");
169 std::vector<std::vector<std::shared_ptr<SymbolicExpr>>> shifted(
170 matrix.rows(),
171 std::vector<std::shared_ptr<SymbolicExpr>>(matrix.cols()));
172 for (std::size_t row = 0; row < matrix.rows(); ++row) {
173 for (std::size_t column = 0; column < matrix.cols(); ++column) {
174 auto value = detail::make_expression_ptr(matrix.get(row, column));
175 shifted[row][column] = row == column
176 ? detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::add(value, SymbolicExpr::multiply(
177 SymbolicExpr::number(-1), lambda))), transform_budget))
178 : std::move(value);
179 }
180 }
181 auto nullspace = matrix_nullspace_checked(SymbolicExpr::matrix(shifted), context);
182 if (!nullspace) { return MatrixEigenvectorResult::failure(nullspace.error()); }
183 if (nullspace.value().empty()) {
185 "eigenvalue has no proved nonzero nullspace basis", "matrix_eigenspaces");
186 }
187 return nullspace;
188} catch (const CasError& error) {
190} catch (const std::bad_alloc&) {
191 return MatrixEigenvectorResult::failure(CasErrc::ResourceLimit, "allocation failed", "eigenvalue_nullspace");
192} catch (const std::length_error& error) {
193 return MatrixEigenvectorResult::failure(CasErrc::ResourceLimit, error.what(), "eigenvalue_nullspace");
194} catch (const std::exception& error) {
195 return MatrixEigenvectorResult::failure(CasErrc::InternalInvariant, error.what(), "eigenvalue_nullspace");
196}
197}
198
201 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
202 (context).limits().max_ast_nodes, "transform");
203 using SpacesResult = Result<Eigenspaces>;
204 constexpr const char* operation = "matrix_eigenspaces";
205 auto matrix_result = require_square_matrix(A, context, operation);
206 if (!matrix_result) { return SpacesResult::failure(matrix_result.error()); }
207 auto eigenvalues = matrix_eigenvalues_checked(A, context);
208 if (!eigenvalues) { return SpacesResult::failure(eigenvalues.error()); }
209 const auto& matrix = *matrix_result.value();
210 Eigenspaces spaces;
211 AssumptionContext assumptions;
212 detail::AssumptionFacts facts(context.assumptions() ? *context.assumptions() : assumptions);
213 try {
214 for (const auto& eigenvalue : eigenvalues.value()) {
215 auto lambda = detail::make_expression_ptr(detail::normalize_node(detail::node(eigenvalue), transform_budget));
216 auto duplicate = eigenvalue_already_collected(lambda, spaces, context, facts);
217 if (!duplicate) { return SpacesResult::failure(duplicate.error()); }
218 if (duplicate.value()) { continue; }
219 auto nullspace = eigenvalue_nullspace(matrix, lambda, context);
220 if (!nullspace) { return SpacesResult::failure(nullspace.error()); }
221 spaces.emplace_back(std::move(lambda), std::move(nullspace.value()));
222 }
223 return SpacesResult::success(std::move(spaces));
224 } catch (const std::bad_alloc&) {
225 return SpacesResult::failure(CasErrc::ResourceLimit,
226 "allocation failed while computing eigenspaces", operation);
227 } catch (const std::length_error& error) { return Result<std::vector<std::pair<ExprPtr, std::vector<std::vector<ExprPtr>>>>>::failure(CasErrc::ResourceLimit, error.what(), "matrix_eigenspaces"); } catch (const std::exception& ex) {
228 return SpacesResult::failure(CasErrc::InternalInvariant, ex.what(), operation);
229 }
230} catch (const CasError& error) {
232} catch (const std::bad_alloc&) {
233 return Result<std::vector<std::pair<ExprPtr, std::vector<std::vector<ExprPtr>>>>>::failure(CasErrc::ResourceLimit, "allocation failed", "matrix_eigenspaces");
234} catch (const std::length_error& error) {
235 return Result<std::vector<std::pair<ExprPtr, std::vector<std::vector<ExprPtr>>>>>::failure(CasErrc::ResourceLimit, error.what(), "matrix_eigenspaces");
236} catch (const std::exception& error) {
237 return Result<std::vector<std::pair<ExprPtr, std::vector<std::vector<ExprPtr>>>>>::failure(CasErrc::InternalInvariant, error.what(), "matrix_eigenspaces");
238}
239
241 const std::shared_ptr<SymbolicExpr>& A, ComputationContext& context) {
243 if (!spaces) return MatrixEigenvectorResult::failure(spaces.error());
244 try {
245 std::vector<std::vector<ExprPtr>> vectors;
246 for (auto& space : spaces.value())
247 for (auto& vector : space.second) vectors.push_back(std::move(vector));
248 return MatrixEigenvectorResult::success(std::move(vectors));
249 } catch (const std::bad_alloc&) {
251 "allocation failed while collecting eigenvectors", "matrix_eigenvectors");
252 }
253}
254
256 const std::shared_ptr<SymbolicExpr>& A) {
259}
260
261}
AssumptionContext class with scoped push/pop management.
矩阵节点,支持稠密和稀疏两种存储方式。
size_t cols() const noexcept
size_t rows() const noexcept
std::shared_ptr< const SymbolicNode > get(size_t r, size_t c) const
获取指定位置的矩阵元素。
CasError & error()
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(std::shared_ptr< SymbolicExpr > value)
Result< bool > eigenvalue_already_collected(const ExprPtr &lambda, const Eigenspaces &spaces, ComputationContext &context, const detail::AssumptionFacts &facts)
std::vector< std::pair< ExprPtr, std::vector< std::vector< ExprPtr > > > > Eigenspaces
MatrixEigenvectorResult eigenvalue_nullspace(const MatrixNode &matrix, const ExprPtr &lambda, ComputationContext &context)
Result< std::shared_ptr< const MatrixNode > > require_square_matrix(const std::shared_ptr< SymbolicExpr > &expr, ComputationContext &context, const std::string &operation)
Result< ZeroProof > classify_exact_zero(const ExprPtr &expression, ComputationContext &context, const std::string &operation)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
Result< Tribool > query_nonzero_value(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context)
RewriteBudget const FactsQuery & facts
ComputationContext const std::string & operation
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::size_t std::size_t ComputationContext & context
Result< std::vector< std::pair< ExprPtr, std::vector< std::vector< ExprPtr > > > > > matrix_eigenspaces_checked(const ExprPtr &matrix, ComputationContext &context)
MatrixEigenvalueResult matrix_eigenvalues_checked(const std::shared_ptr< SymbolicExpr > &A, ComputationContext &context)
const std::string & variable
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExpressionResult matrix_characteristic_polynomial_checked(const std::shared_ptr< SymbolicExpr > &A, const std::string &variable, ComputationContext &context)
@ Complex
Complex numbers (default, least specific)
ExpressionResult matrix_determinant_checked(const std::shared_ptr< SymbolicExpr > &A, ComputationContext &context)
@ True
Property definitely holds
Result< std::vector< std::shared_ptr< SymbolicExpr > > > MatrixEigenvalueResult
Result< std::shared_ptr< SymbolicExpr > > ExpressionResult
Result of an operation that produces a symbolic expression.
Result< std::vector< std::vector< std::shared_ptr< SymbolicExpr > > > > MatrixEigenvectorResult
LMCAS::FiniteSolveResult solve_finite_checked(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, ComputationContext &context, const SolveOptions &opts)
std::shared_ptr< SymbolicExpr > ExprPtr
MatrixEigenvectorResult matrix_eigenvectors_checked(const std::shared_ptr< SymbolicExpr > &A, ComputationContext &context)
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
const std::string const ExprPtr & value
MatrixNullspaceResult matrix_nullspace_checked(const std::shared_ptr< SymbolicExpr > &A, ComputationContext &context)
方程求解选项,控制数值求解行为和结果形式.
方程求解策略调度器 solve_dispatch 及相关选项结构体.