LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
matrix_decomposition_qr.cpp
浏览该文件的文档.
4
5#include <algorithm>
6#include <new>
7
8namespace LMCAS {
9using namespace detail::matrix_decomposition;
10namespace {
12 const std::shared_ptr<const MatrixNode>& matrix,
14 const std::string& operation) {
15 auto values = exact_rational_matrix(matrix, context);
16 if (!values) {
19 "QR input is outside the exact rational full-column-rank support domain",
20 operation);
21 }
22 const size_t rows = values->size();
23 const size_t cols = rows == 0 ? 0 : (*values)[0].size();
24 if (rows < cols) {
27 "QR decomposition requires at least as many rows as columns in the supported domain",
28 operation);
29 }
30 std::vector<std::vector<Rational>> gram(
31 cols, std::vector<Rational>(cols, Rational(0)));
32 for (size_t i = 0; i < cols; ++i) {
33 for (size_t j = 0; j < cols; ++j) {
34 Rational sum(0);
35 for (size_t row = 0; row < rows; ++row) {
36 sum = sum + (*values)[row][i] * (*values)[row][j];
37 }
38 gram[i][j] = sum;
39 }
40 }
41 for (size_t order = 1; order <= cols; ++order) {
42 std::vector<Rational> leading;
43 leading.reserve(order * order);
44 for (size_t row = 0; row < order; ++row) {
45 for (size_t col = 0; col < order; ++col) {
46 leading.push_back(gram[row][col]);
47 }
48 }
49 auto determinant = detail::rational_determinant_exact(
50 order, std::move(leading), context, operation);
51 if (!determinant) return Result<void>::failure(determinant.error());
52 if (determinant.value() <= Rational(0)) {
55 "QR decomposition requires proven full column rank",
56 operation);
57 }
58 }
59 return Result<void>::success();
60}
62 const std::shared_ptr<SymbolicExpr>& A,
63 std::shared_ptr<SymbolicExpr>& Q,
64 std::shared_ptr<SymbolicExpr>& R) {
65 auto mat = std::dynamic_pointer_cast<const MatrixNode>(LMCAS::detail::node(A));
66 if (!mat) return false;
67 size_t m = mat->rows();
68 size_t n = mat->cols();
69
70 std::vector<std::vector<std::shared_ptr<SymbolicExpr>>> Q_grid(m, std::vector<std::shared_ptr<SymbolicExpr>>(n, SymbolicExpr::number(0)));
71 std::vector<std::vector<std::shared_ptr<SymbolicExpr>>> R_grid(n, std::vector<std::shared_ptr<SymbolicExpr>>(n, SymbolicExpr::number(0)));
72
73 std::vector<std::vector<std::shared_ptr<SymbolicExpr>>> A_cols(n, std::vector<std::shared_ptr<SymbolicExpr>>(m));
74 for (size_t j = 0; j < n; j++) {
75 for (size_t i = 0; i < m; i++) A_cols[j][i] = LMCAS::detail::make_expression_ptr(mat->get(i, j));
76 }
77
78 for (size_t j = 0; j < n; j++) {
79 std::vector<std::shared_ptr<SymbolicExpr>> u_j = A_cols[j];
80 for (size_t i = 0; i < j; i++) {
81 auto dot = SymbolicExpr::number(0);
82 for (size_t k = 0; k < m; k++) dot = SymbolicExpr::add(dot, SymbolicExpr::multiply(Q_grid[k][i], A_cols[j][k]));
83 R_grid[i][j] = dot;
84
85 for (size_t k = 0; k < m; k++) {
86 u_j[k] = SymbolicExpr::add(u_j[k], SymbolicExpr::multiply(SymbolicExpr::number(-1), SymbolicExpr::multiply(R_grid[i][j], Q_grid[k][i])));
87 }
88 }
89
90 auto norm_sq = SymbolicExpr::number(0);
91 for (size_t k = 0; k < m; k++) norm_sq = SymbolicExpr::add(norm_sq, SymbolicExpr::multiply(u_j[k], u_j[k]));
92 R_grid[j][j] = SymbolicExpr::sqrt(norm_sq);
93
94 for (size_t k = 0; k < m; k++) Q_grid[k][j] = SymbolicExpr::divide(u_j[k], R_grid[j][j]);
95 }
96
97 Q = SymbolicExpr::matrix(Q_grid);
98 R = SymbolicExpr::matrix(R_grid);
99 return true;
100}
101}
102
104 const std::shared_ptr<SymbolicExpr>& A,
106{
107 const std::string operation = "qr_decomposition";
108 auto matrix = validate_decomposition_matrix(A, false, context, operation);
109 if (!matrix) return QRDecompositionResult::failure(matrix.error());
110 auto budget = context.consume_steps(matrix.value()->rows() * matrix.value()->cols() * 12 + 8,
111 operation);
112 if (!budget) return QRDecompositionResult::failure(budget.error());
113 auto full_rank = prove_exact_full_column_rank_qr_support(
114 matrix.value(), context, operation);
115 if (!full_rank) return QRDecompositionResult::failure(full_rank.error());
116 try {
117 std::shared_ptr<SymbolicExpr> Q;
118 std::shared_ptr<SymbolicExpr> R;
119 if (!qr_decomposition_impl(A, Q, R)) {
122 "QR decomposition could not be constructed in the supported symbolic domain",
123 operation);
124 }
125 auto q_check = validate_decomposition_output(Q, "Q", operation);
126 if (!q_check) return QRDecompositionResult::failure(q_check.error());
127 auto r_check = validate_decomposition_output(R, "R", operation);
128 if (!r_check) return QRDecompositionResult::failure(r_check.error());
130 } catch (const std::bad_alloc&) {
132 "allocation failed while calculating QR decomposition",
133 operation);
134 } catch (const std::exception& ex) {
136 ex.what(),
137 operation);
138 }
139}
140
142 const std::shared_ptr<SymbolicExpr>& A)
143{
146}
147
148std::vector<std::vector<std::shared_ptr<SymbolicExpr>>> gram_schmidt(
149 const std::vector<std::vector<std::shared_ptr<SymbolicExpr>>>& vectors,
150 bool normalize) {
152 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
153 (context).limits().max_ast_nodes, "transform");
154 std::vector<std::vector<std::shared_ptr<SymbolicExpr>>> basis;
155 for (const auto& v : vectors) {
156 std::vector<std::shared_ptr<SymbolicExpr>> u = v;
157 for (const auto& b : basis) {
158 auto vb = SymbolicExpr::number(0);
159 auto bb = SymbolicExpr::number(0);
160 for (size_t k = 0; k < u.size(); ++k) {
161 vb = SymbolicExpr::add(vb, SymbolicExpr::multiply(v[k], b[k]));
162 bb = SymbolicExpr::add(bb, SymbolicExpr::multiply(b[k], b[k]));
163 }
164 if (LMCAS::detail::node(bb) && LMCAS::detail::node(bb)->is_zero()) continue;
165 auto coeff = SymbolicExpr::divide(vb, bb);
166 for (size_t k = 0; k < u.size(); ++k) {
168 SymbolicExpr::multiply(SymbolicExpr::number(-1),
169 SymbolicExpr::multiply(coeff, b[k])))), transform_budget));
170 }
171 }
172 auto norm_sq = SymbolicExpr::number(0);
173 for (auto& x : u) norm_sq = SymbolicExpr::add(norm_sq, SymbolicExpr::multiply(x, x));
174 norm_sq = detail::make_expression_ptr(detail::normalize_node(detail::node(norm_sq), transform_budget));
175 if (LMCAS::detail::node(norm_sq) && LMCAS::detail::node(norm_sq)->is_zero()) continue;
176 basis.push_back(u);
177 }
178 if (normalize) {
179 for (auto& u : basis) {
180 auto norm_sq = SymbolicExpr::number(0);
181 for (auto& x : u) norm_sq = SymbolicExpr::add(norm_sq, SymbolicExpr::multiply(x, x));
182 auto norm = SymbolicExpr::sqrt(norm_sq);
183 for (auto& x : u) x = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(x, norm)), transform_budget));
184 }
185 }
186 return basis;
187}
188
189}
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
static bool qr_decomposition_impl(const std::shared_ptr< SymbolicExpr > &A, std::shared_ptr< SymbolicExpr > &Q, std::shared_ptr< SymbolicExpr > &R)
Result< void > prove_exact_full_column_rank_qr_support(const std::shared_ptr< const MatrixNode > &matrix, ComputationContext &context, const std::string &operation)
Result< std::shared_ptr< const MatrixNode > > validate_decomposition_matrix(const std::shared_ptr< SymbolicExpr > &A, bool require_square, ComputationContext &context, const std::string &operation)
Result< void > validate_decomposition_output(const std::shared_ptr< SymbolicExpr > &expr, const std::string &name, const std::string &operation)
std::optional< std::vector< std::vector< Rational > > > exact_rational_matrix(const std::shared_ptr< const MatrixNode > &matrix, ComputationContext &context)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
Result< Rational > rational_determinant_exact(std::size_t dimension, std::vector< Rational > values, ComputationContext &context, const std::string &operation)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
__attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::string & v
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
const std::vector< FGLMPoly > const MonomialOrder & order
std::vector< std::vector< std::shared_ptr< SymbolicExpr > > > gram_schmidt(const std::vector< std::vector< std::shared_ptr< SymbolicExpr > > > &vectors, bool normalize)
const MultiPoly & b
const std::vector< FGLMPoly > & basis
Result< QRDecomposition > QRDecompositionResult
QRDecompositionResult qr_decomposition_checked(const std::shared_ptr< SymbolicExpr > &A, ComputationContext &context)
__attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string & u