Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple LDL^T solve interface #2915

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from

Conversation

roryhubbard
Copy link

@roryhubbard roryhubbard commented Apr 25, 2022

What?

Simplify the interface to solving a linear system via LDL^T factorization (https://en.wikipedia.org/wiki/Cholesky_decomposition).
I overloaded the preexisting "ldl_solve" function to accept just "A" and "b" and return the solution to the linear system "Ax=b".

Why?

Allow user to write less when using the "ldl_solve" function. Currently, one must write code like this:

casadi::SX D, LT;
std::vector<casadi_int> p;
ldl(A, D, LT, p, false);
auto x = ldl_solve(b, D, LT, p);

The Eigen library has a more concise interface (https://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.html):

auto x = A.ldlt().solve(b)

This pull request will allow a user to call "ldl_solve" like this:

auto x = ldl_solve(A, b);

@jgillis
Copy link
Member

jgillis commented Nov 2, 2022

@jaeandersson what's your opinion?
Should we instead expose this through solve(A,b,'ldl')?

@jaeandersson
Copy link
Member

@jaeandersson what's your opinion? Should we instead expose this through solve(A,b,'ldl')?

Yes, you're right. I think we should reserve ldl_solve for the lower level routine, that is separate steps for factorization and solution. qr_solve works the same way. It does make sense to have an overload of solve(A,b,'ldl') as you suggest. It probably already works by the way, but only for casadi::DM, not for casadi::SX. You could easily add an implementation for SX here:

  template<typename Scalar>
  Matrix<Scalar> Matrix<Scalar>::
  solve(const Matrix<Scalar>& a, const Matrix<Scalar>& b,
           const std::string& lsolver, const Dict& dict) {
    casadi_error("'solve' with plugin not defined for " + type_name());
    return Matrix<Scalar>();
  }

Just make a if-else to cover ldl and qr:

  template<typename Scalar>
  Matrix<Scalar> Matrix<Scalar>::
  solve(const Matrix<Scalar>& a, const Matrix<Scalar>& b,
           const std::string& lsolver, const Dict& dict) {
    if (lsolver == "qr") {
       ...
    } else if (lsolver == "ldl") {
       ...
    } else {
        casadi_error("'solve' with plugin not defined for " + type_name());
        return Matrix<Scalar>();
    }
  }

@roryhubbard
Copy link
Author

Okay sorry for the delay. Is it correct to use qr_sparse over qr? And how do we feel about the hard coded false values for qr_sparse, qr_solve, and ldl? I'm not sure if it would be better to set any of those to true as the default value instead.

Also, is Sparsity::is_symmetric only checking for structural symmetry as oppose to numerical symmetry? It is currently possible to call solve(A, b, 'ldl') solve with a non symmetric square A and it will return a false solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants