20 auto left = std::dynamic_pointer_cast<const MatrixNode>(
detail::node(ap.value()));
21 auto right = std::dynamic_pointer_cast<const MatrixNode>(
detail::node(pj.value()));
22 if (!left || !
right) {
24 "Jordan matrix product did not produce a matrix", operation);
26 for (std::size_t row = 0; row < matrix.
rows(); ++row) {
27 for (std::size_t col = 0; col < matrix.
cols(); ++col) {
29 SymbolicExpr::multiply(SymbolicExpr::number(-1),
36 "Jordan intertwining identity is not proved at (" +
37 std::to_string(row) +
"," + std::to_string(col) +
38 "): " + difference->to_string(), operation);
47 return a.rows() ==
a.cols() && p.
rows() ==
a.rows() && p.
cols() ==
a.cols() &&
53 const std::string operation =
"jordan_form.verify";
54 auto a = std::dynamic_pointer_cast<const MatrixNode>(
detail::node(A));
59 "Jordan certificate has invalid dimensions", operation);
63 if (rank.value() !=
a->rows()) {
65 "Jordan change of basis is singular", operation);
87 const auto n = matrix.value()->rows();
88 std::size_t count = 0;
89 for (
const auto& space : spaces.value()) { count += space.second.size(); }
92 "ordinary eigenspaces do not span the matrix",
"matrix.diagonalize");
94 std::vector<std::vector<ExprPtr>> p(n, std::vector<ExprPtr>(n));
95 std::vector<std::vector<ExprPtr>> j(n,
96 std::vector<ExprPtr>(n, SymbolicExpr::number(0)));
97 std::size_t column = 0;
98 for (
const auto& space : spaces.value()) {
99 for (
const auto& vector : space.second) {
100 if (vector.size() != n) {
102 "eigenspace vector has invalid dimensions",
"matrix.diagonalize");
104 for (std::size_t row = 0; row < n; ++row) { p[row][column] = vector[row]; }
105 j[column][column] = space.first;
110 {SymbolicExpr::matrix(j), SymbolicExpr::matrix(p)},
context);
118 if (proved_sign > 0)
has_pos =
true;
119 else if (proved_sign < 0)
has_neg =
true;
124 if (
has_pos) {
return any_zero ?
"positive_semidefinite" :
"positive_definite"; }
125 if (
has_neg) {
return any_zero ?
"negative_semidefinite" :
"negative_definite"; }
126 return any_zero ?
"positive_semidefinite" :
"unknown";
135 if (!zero) {
return std::nullopt; }
138 if (!positive) {
return std::nullopt; }
140 auto negative_value = SymbolicExpr::multiply(SymbolicExpr::number(-1),
value);
142 if (!negative || negative.value() !=
Tribool::True) {
return std::nullopt; }
149 (
context).limits().max_ast_nodes,
"transform");
158 return matrix.size() == 2 && matrix[0].size() == 2 &&
159 matrix[0][0] == matrix[1][1] && matrix[1][0] == Rational(0) &&
160 matrix[0][1] != Rational(0);
167 const std::string operation =
"jordan_form";
170 auto budget =
context.consume_steps(matrix.value()->rows() * matrix.value()->cols() * 48 + 32,
176 matrix.value()->rows(), matrix.value()->cols(), *diagonal),
180 if (exact && is_defective_upper_pair(*exact)) {
181 auto zero = SymbolicExpr::number(0);
182 auto one = SymbolicExpr::number(1);
184 auto j = SymbolicExpr::matrix({{lambda, one}, {zero, lambda}});
185 auto p = SymbolicExpr::matrix({{
exact_number_expr((*exact)[0][1]), zero}, {zero, one}});
186 return certified_jordan(A, {std::move(j), std::move(p)},
context);
188 return diagonalization_checked(A,
context);
189 }
catch (
const std::bad_alloc&) {
191 "allocation failed while calculating Jordan form", operation);
192 }
catch (
const std::exception& ex) {
205 (
context).limits().max_ast_nodes,
"transform");
207 auto decomposition = diagonalization_checked(A,
context);
208 if (!decomposition)
return SymbolicExpr::exp(A);
210 if (!inverse)
return SymbolicExpr::exp(A);
211 auto diagonal = std::dynamic_pointer_cast<const MatrixNode>(
detail::node(decomposition.value().J));
212 const auto n = diagonal->rows();
213 std::vector<std::vector<ExprPtr>> values(n, std::vector<ExprPtr>(n, SymbolicExpr::number(0)));
214 for (std::size_t i = 0; i < n; ++i)
217 SymbolicExpr::multiply(SymbolicExpr::matrix(values), inverse.value()))), transform_budget));
223 (
context).limits().max_ast_nodes,
"transform");
225 auto decomposition = diagonalization_checked(A,
context);
226 if (!decomposition)
return nullptr;
228 if (!inverse)
return nullptr;
229 auto diagonal = std::dynamic_pointer_cast<const MatrixNode>(
detail::node(decomposition.value().J));
230 const auto n = diagonal->rows();
231 AssumptionContext assumptions;
233 std::vector<std::vector<ExprPtr>> values(n, std::vector<ExprPtr>(n, SymbolicExpr::number(0)));
234 for (std::size_t i = 0; i < n; ++i) {
236 if (!positive || positive.value() !=
Tribool::True)
return nullptr;
240 SymbolicExpr::multiply(SymbolicExpr::matrix(values), inverse.value()))), transform_budget));
246 if (!eigenvalues || eigenvalues.value().empty()) {
return "unknown"; }
247 AssumptionContext assumptions;
249 QuadraticSigns signs;
250 for (
const auto& eigenvalue : eigenvalues.value()) {
251 auto sign = quadratic_eigenvalue_sign(eigenvalue, facts,
context);
252 if (!sign) {
return "unknown"; }
253 signs.include(*sign);
255 return signs.classification();
AssumptionContext class with scoped push/pop management.
size_t cols() const noexcept
size_t rows() const noexcept
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
Result< void > verify_jordan_decomposition(const ExprPtr &A, const JordanDecomposition &value, ComputationContext &context)
std::optional< int > symbolic_quadratic_sign(const ExprPtr &value, const detail::AssumptionFacts &facts, ComputationContext &context)
JordanDecompositionResult certified_jordan(const ExprPtr &A, JordanDecomposition value, ComputationContext &context)
Result< void > verify_jordan_identity(const ExprPtr &A, const JordanDecomposition &value, const MatrixNode &matrix, ComputationContext &context, const std::string &operation)
JordanDecompositionResult diagonalization_checked(const ExprPtr &A, ComputationContext &context)
bool is_defective_upper_pair(const std::vector< std::vector< Rational > > &matrix)
bool jordan_dimensions_match(const MatrixNode &a, const MatrixNode &p, const MatrixNode &j)
std::optional< int > quadratic_eigenvalue_sign(const ExprPtr &eigenvalue, const detail::AssumptionFacts &facts, ComputationContext &context)
std::shared_ptr< SymbolicExpr > identity_matrix_expr(std::size_t n)
std::shared_ptr< SymbolicExpr > exact_number_expr(const Rational &value)
std::optional< Rational > exact_rational_expr(const std::shared_ptr< const SymbolicNode > &node)
std::optional< std::vector< Rational > > exact_diagonal_entries(const std::shared_ptr< const MatrixNode > &matrix, ComputationContext &context)
std::shared_ptr< SymbolicExpr > rectangular_diagonal_expr(std::size_t rows, std::size_t cols, const std::vector< Rational > &diagonal)
Result< std::shared_ptr< const MatrixNode > > validate_decomposition_matrix(const std::shared_ptr< SymbolicExpr > &A, bool require_square, ComputationContext &context, const std::string &operation)
std::optional< std::vector< std::vector< Rational > > > exact_rational_matrix(const std::shared_ptr< const MatrixNode > &matrix, ComputationContext &context)
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_real_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
Result< std::vector< std::pair< ExprPtr, std::vector< std::vector< ExprPtr > > > > > matrix_eigenspaces_checked(const ExprPtr &matrix, ComputationContext &context)
Result< Tribool > query_positive_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
MatrixEigenvalueResult matrix_eigenvalues_checked(const std::shared_ptr< SymbolicExpr > &A, ComputationContext &context)
JordanDecompositionResult jordan_form_checked(const ExprPtr &A, ComputationContext &context)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult real(const ExprPtr &expression, ComputationContext &context)
@ True
Property definitely holds
Result< JordanDecomposition > JordanDecompositionResult
ExpressionResult matrix_inverse_checked(const std::shared_ptr< SymbolicExpr > &A, 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 const std::shared_ptr< SymbolicExpr > & a
ExpressionResult matrix_multiply_checked(const std::shared_ptr< SymbolicExpr > &A, const std::shared_ptr< SymbolicExpr > &B, ComputationContext &context)
std::shared_ptr< SymbolicExpr > ExprPtr
const std::string const ExprPtr & value
std::string classify_quadratic_form(const ExprPtr &A)
MatrixRankResult matrix_rank_checked(const std::shared_ptr< SymbolicExpr > &A, ComputationContext &context)
ExprResult rational(const Rational &value)
ExprPtr matrix_exp(const ExprPtr &A)
ExprPtr matrix_log(const ExprPtr &A)
void include(int proved_sign)
std::string classification() const