void LU_solve(const DenseMatrix &A, const DenseMatrix &b, DenseMatrix &x) { DenseMatrix L = DenseMatrix(A.nrows(), A.ncols()); DenseMatrix U = DenseMatrix(A.nrows(), A.ncols()); DenseMatrix x_ = DenseMatrix(b.nrows(), b.ncols()); LU(A, L, U); forward_substitution(L, b, x_); back_substitution(U, x_, x); }
void char_poly(const DenseMatrix &A, DenseMatrix &B) { SYMENGINE_ASSERT(B.ncols() == 1 and B.nrows() == A.nrows() + 1); SYMENGINE_ASSERT(A.nrows() == A.ncols()); std::vector<DenseMatrix> polys; berkowitz(A, polys); B = polys[polys.size() - 1]; }
void fraction_free_LU_solve(const DenseMatrix &A, const DenseMatrix &b, DenseMatrix &x) { DenseMatrix LU = DenseMatrix(A.nrows(), A.ncols()); DenseMatrix x_ = DenseMatrix(b.nrows(), b.ncols()); fraction_free_LU(A, LU); forward_substitution(LU, b, x_); back_substitution(LU, x_, x); }
void LDL_solve(const DenseMatrix &A, const DenseMatrix &b, DenseMatrix &x) { DenseMatrix L = DenseMatrix(A.nrows(), A.ncols()); DenseMatrix D = DenseMatrix(A.nrows(), A.ncols()); DenseMatrix x_ = DenseMatrix(b.nrows(), b.ncols()); if (not is_symmetric_dense(A)) throw SymEngineException("Matrix must be symmetric"); LDL(A, L, D); forward_substitution(L, b, x); diagonal_solve(D, x, x_); transpose_dense(L, D); back_substitution(D, x_, x); }
// Extract main diagonal of CSR matrix A void csr_diagonal(const CSRMatrix &A, DenseMatrix &D) { unsigned N = std::min(A.row_, A.col_); SYMENGINE_ASSERT(D.nrows() == N and D.ncols() == 1); unsigned row_start; unsigned row_end; RCP<const Basic> diag; for (unsigned i = 0; i < N; i++) { row_start = A.p_[i]; row_end = A.p_[i + 1]; diag = zero; unsigned jj; while (row_start <= row_end) { jj = (row_start + row_end) / 2; if (A.j_[jj] == i) { diag = A.x_[jj]; break; } else if (A.j_[jj] < i) { row_start = jj + 1; } else { row_end = jj - 1; } } D.set(i, 0, diag); } }
void jacobian(const DenseMatrix &A, const DenseMatrix &x, DenseMatrix &result) { SYMENGINE_ASSERT(A.col_ == 1); SYMENGINE_ASSERT(x.col_ == 1); SYMENGINE_ASSERT(A.row_ == result.nrows() and x.row_ == result.ncols()); bool error = false; #pragma omp parallel for for (unsigned i = 0; i < result.row_; i++) { for (unsigned j = 0; j < result.col_; j++) { if (is_a<Symbol>(*(x.m_[j]))) { const RCP<const Symbol> x_ = rcp_static_cast<const Symbol>(x.m_[j]); result.m_[i * result.col_ + j] = A.m_[i]->diff(x_); } else { error = true; break; } } } if (error) { throw SymEngineException( "'x' must contain Symbols only. " "Use sjacobian for SymPy style differentiation"); } }
void diff(const DenseMatrix &A, const RCP<const Symbol> &x, DenseMatrix &result) { SYMENGINE_ASSERT(A.row_ == result.nrows() and A.col_ == result.ncols()); #pragma omp parallel for for (unsigned i = 0; i < result.row_; i++) { for (unsigned j = 0; j < result.col_; j++) { result.m_[i * result.col_ + j] = A.m_[i * result.col_ + j]->diff(x); } } }
// Scale the rows of a CSR matrix *in place* // A[i, :] *= X[i] void csr_scale_rows(CSRMatrix &A, const DenseMatrix &X) { SYMENGINE_ASSERT(A.row_ == X.nrows() and X.ncols() == 1); for (unsigned i = 0; i < A.row_; i++) { if (eq(*(X.get(i, 0)), *zero)) throw SymEngineException("Scaling factor can't be zero"); for (unsigned jj = A.p_[i]; jj < A.p_[i + 1]; jj++) A.x_[jj] = mul(A.x_[jj], X.get(i, 0)); } }
void pivoted_LU_solve(const DenseMatrix &A, const DenseMatrix &b, DenseMatrix &x) { DenseMatrix L = DenseMatrix(A.nrows(), A.ncols()); DenseMatrix U = DenseMatrix(A.nrows(), A.ncols()); DenseMatrix x_ = DenseMatrix(b); permutelist pl; pivoted_LU(A, L, U, pl); permuteFwd(x_, pl); forward_substitution(L, x_, x_); back_substitution(U, x_, x); }
// Scale the columns of a CSR matrix *in place* // A[:, i] *= X[i] void csr_scale_columns(CSRMatrix &A, const DenseMatrix &X) { SYMENGINE_ASSERT(A.col_ == X.nrows() and X.ncols() == 1); const unsigned nnz = A.p_[A.row_]; unsigned i; for (i = 0; i < A.col_; i++) { if (eq(*(X.get(i, 0)), *zero)) throw SymEngineException("Scaling factor can't be zero"); } for (i = 0; i < nnz; i++) A.x_[i] = mul(A.x_[i], X.get(A.j_[i], 0)); }
void LDL_solve(const DenseMatrix &A, const DenseMatrix &b, DenseMatrix &x) { DenseMatrix L = DenseMatrix(A.nrows(), A.ncols()); DenseMatrix D = DenseMatrix(A.nrows(), A.ncols()); DenseMatrix x_ = DenseMatrix(b.nrows(), 1); if (!is_symmetric_dense(A)) throw std::runtime_error("Matrix must be symmetric"); LDL(A, L, D); forward_substitution(L, b, x); diagonal_solve(D, x, x_); transpose_dense(L, D); back_substitution(D, x_, x); }
void sdiff(const DenseMatrix &A, const RCP<const Basic> &x, DenseMatrix &result) { SYMENGINE_ASSERT(A.row_ == result.nrows() and A.col_ == result.ncols()); #pragma omp parallel for for (unsigned i = 0; i < result.row_; i++) { for (unsigned j = 0; j < result.col_; j++) { if (is_a<Symbol>(*x)) { const RCP<const Symbol> x_ = rcp_static_cast<const Symbol>(x); result.m_[i * result.col_ + j] = A.m_[i * result.col_ + j]->diff(x_); } else { // TODO: Use a dummy symbol const RCP<const Symbol> x_ = symbol("_x"); result.m_[i * result.col_ + j] = ssubs( ssubs(A.m_[i * result.col_ + j], {{x, x_}})->diff(x_), {{x_, x}}); } } } }
void sjacobian(const DenseMatrix &A, const DenseMatrix &x, DenseMatrix &result) { SYMENGINE_ASSERT(A.col_ == 1); SYMENGINE_ASSERT(x.col_ == 1); SYMENGINE_ASSERT(A.row_ == result.nrows() and x.row_ == result.ncols()); #pragma omp parallel for for (unsigned i = 0; i < result.row_; i++) { for (unsigned j = 0; j < result.col_; j++) { if (is_a<Symbol>(*(x.m_[j]))) { const RCP<const Symbol> x_ = rcp_static_cast<const Symbol>(x.m_[j]); result.m_[i * result.col_ + j] = A.m_[i]->diff(x_); } else { // TODO: Use a dummy symbol const RCP<const Symbol> x_ = symbol("x_"); result.m_[i * result.col_ + j] = ssubs( ssubs(A.m_[i], {{x.m_[j], x_}})->diff(x_), {{x_, x.m_[j]}}); } } } }
bool order(const DenseMatrix &t, const std::vector<DenseMatrix> &basis, unsigned k) { bool eq = true; for (unsigned j = 0; j < t.ncols(); j++) { SYMENGINE_ASSERT(is_a<Integer>(*t.get(0, j))); integer_class t_ = rcp_static_cast<const Integer>(t.get(0, j))->as_integer_class(); SYMENGINE_ASSERT(is_a<Integer>(*basis[k].get(0, j))); integer_class b_ = rcp_static_cast<const Integer>(basis[k].get(0, j)) ->as_integer_class(); if (t_ < b_) { return false; } if (t_ > b_) { eq = false; } } return not eq; }
// Solve the diophantine system Ax = 0 and return a basis set for solutions // Reference: // Evelyne Contejean, Herve Devie. An Efficient Incremental Algorithm for // Solving // Systems of Linear Diophantine Equations. Information and computation, // 113(1):143-172, // August 1994. void homogeneous_lde(std::vector<DenseMatrix> &basis, const DenseMatrix &A) { unsigned p = A.nrows(); unsigned q = A.ncols(); unsigned n; SYMENGINE_ASSERT(p > 0 and q > 1); DenseMatrix row_zero(1, q); zeros(row_zero); DenseMatrix col_zero(p, 1); zeros(col_zero); std::vector<DenseMatrix> P; P.push_back(row_zero); std::vector<std::vector<bool>> Frozen(q, std::vector<bool>(q, true)); for (unsigned j = 0; j < q; j++) { Frozen[0][j] = false; } std::vector<bool> F(q, false); DenseMatrix t, transpose, product, T; RCP<const Integer> dot; product = DenseMatrix(p, 1); transpose = DenseMatrix(q, 1); while (P.size() > 0) { n = P.size() - 1; t = P[n]; P.pop_back(); t.transpose(transpose); A.mul_matrix(transpose, product); if (product.eq(col_zero) and not t.eq(row_zero)) { basis.push_back(t); } else { for (unsigned i = 0; i < q; i++) { F[i] = Frozen[n][i]; } T = t; for (unsigned i = 0; i < q; i++) { SYMENGINE_ASSERT(is_a<Integer>(*T.get(0, i))); T.set(0, i, rcp_static_cast<const Integer>(T.get(0, i)) ->addint(*one)); if (i > 0) { SYMENGINE_ASSERT(is_a<Integer>(*T.get(0, i - 1))); T.set(0, i - 1, rcp_static_cast<const Integer>(T.get(0, i - 1)) ->subint(*one)); } dot = zero; for (unsigned j = 0; j < p; j++) { SYMENGINE_ASSERT(is_a<Integer>(*product.get(j, 0))); RCP<const Integer> p_j0 = rcp_static_cast<const Integer>(product.get(j, 0)); SYMENGINE_ASSERT(is_a<Integer>(*A.get(j, i))); RCP<const Integer> A_ji = rcp_static_cast<const Integer>(A.get(j, i)); dot = dot->addint(*p_j0->mulint(*A_ji)); } if (F[i] == false and ((dot->is_negative() and is_minimum(T, basis, basis.size())) or t.eq(row_zero))) { P.push_back(T); n = n + 1; for (unsigned j = 0; j < q; j++) { Frozen[n - 1][j] = F[j]; } F[i] = true; } } } } }