Solving linear systems with AutoDiffScalar produces wrong results with LLT and LDLT solver
Summary
Environment
- Operating System : Linux
- Architecture : x64
- Eigen Version : 3.4.0
- Compiler Version : Gcc8.4
- Compile Flags :
- Vector Extension :
Minimal Example
//show your code here
#include <Eigen/Core>
#include <Eigen/Dense>
#include <iostream>
#include <unsupported/Eigen/AutoDiff>
using namespace Eigen;
template <typename LinearSolverType>
void CheckLinearSolver(
const LinearSolverType& linear_solver,
const Eigen::Matrix<Eigen::AutoDiffScalar<Eigen::VectorXd>, 2, 2>& A_ad) {
Eigen::Matrix<Eigen::AutoDiffScalar<Eigen::VectorXd>, 2, 1> b_ad;
b_ad(0).value() = 3;
b_ad(1).value() = 5;
b_ad(0).derivatives() = Eigen::Vector3d(0, 0, 0);
b_ad(1).derivatives() = Eigen::Vector3d(0, 0, 0);
const auto x = linear_solver.solve(b_ad);
const Matrix<Eigen::AutoDiffScalar<Eigen::VectorXd>, 2, 1> Ax = A_ad * x;
std::cout << "A*x value: " << Ax(0).value() << ", " << Ax(1).value() << "\n";
std::cout << "b value: " << b_ad(0).value() << ", " << b_ad(1).value()
<< "\n";
// The derivative of A * x should be 0, since the right-hand side b_ad
// contains no gradient.
std::cout << "A*x derivatives:\n"
<< Ax(0).derivatives().transpose() << "\n"
<< Ax(1).derivatives().transpose() << "\n";
std::cout << "b derivatives:\n"
<< b_ad(0).derivatives().transpose() << "\n"
<< b_ad(1).derivatives().transpose() << "\n";
std::cout << "--------------------\n";
}
int main() {
using TypeA = Eigen::Matrix<Eigen::AutoDiffScalar<Eigen::VectorXd>, 2, 2>;
TypeA A_ad;
A_ad(0, 0).value() = 1;
A_ad(0, 1).value() = 3;
A_ad(1, 0).value() = 3;
A_ad(1, 1).value() = 10;
A_ad(0, 0).derivatives() = Eigen::Vector3d(1, 2, 3);
A_ad(0, 1).derivatives() = Eigen::Vector3d(4, 5, 6);
A_ad(1, 0).derivatives() = Eigen::Vector3d(7, 8, 9);
A_ad(1, 1).derivatives() = Eigen::Vector3d(10, 11, 12);
const Eigen::LLT<TypeA> llt_solver(A_ad);
std::cout << "LLT solver\n";
CheckLinearSolver(llt_solver, A_ad);
const Eigen::LDLT<TypeA> ldlt_solver(A_ad);
std::cout << "LDLT solver\n";
CheckLinearSolver(ldlt_solver, A_ad);
const Eigen::PartialPivLU<TypeA> partial_piv_lu_solver(A_ad);
std::cout << "PartialPivLU solver\n";
CheckLinearSolver(partial_piv_lu_solver, A_ad);
const Eigen::FullPivLU<TypeA> full_piv_lu_solver(A_ad);
std::cout << "FullPivLU solver\n";
CheckLinearSolver(full_piv_lu_solver, A_ad);
const Eigen::HouseholderQR<TypeA> householder_qr_solver(A_ad);
std::cout << "HouseholderQR solver\n";
CheckLinearSolver(householder_qr_solver, A_ad);
const Eigen::ColPivHouseholderQR<TypeA> col_piv_householder_qr_solver(A_ad);
std::cout << "ColPivHouseholderQR solver\n";
CheckLinearSolver(col_piv_householder_qr_solver, A_ad);
const Eigen::FullPivHouseholderQR<TypeA> full_piv_householder_qr_solver(A_ad);
std::cout << "FullPivHouseholderQR solver\n";
CheckLinearSolver(full_piv_householder_qr_solver, A_ad);
const Eigen::CompleteOrthogonalDecomposition<TypeA>
complete_orthogonal_decomposition_solver(A_ad);
std::cout << "CompleteOrthogonalDecomposition solver\n";
CheckLinearSolver(complete_orthogonal_decomposition_solver, A_ad);
// BDCSVD and JacobiSVD don't support autodiffing.
return 0;
}
Steps to reproduce
- compile the code as
gcc -Ipath_to_eigen test.cc - run the generated binary
What is the current bug behavior?
When using LLT or LDLT solver, the computed solution doesn't have the right gradient, that A*x have non-zero derivatives, while the right-hand side b has zero derivatives.
What is the expected correct behavior?
Each solver should compute a result, such that A*x has zero derivatives.
Relevant logs
Anything else that might help
-
Have a plan to fix this issue.