26 static_assert(std::is_convertible_v<typename Dual::Scalar, Scalar>,
"The chosen Jet and Scalar types are not compatible.");
27 static_assert(std::is_convertible_v<Scalar, typename Dual::Scalar>,
"The chosen Jet and Scalar types are not compatible.");
32 if (jacobian ==
nullptr) {
33 return function(parameters, residuals);
36 std::vector<Dual> inputs(function.NumParameters());
37 for (
size_t i = 0; i < inputs.size(); ++i) {
38 inputs[i].a = parameters[i];
39 inputs[i].v.setZero();
41 std::vector<Dual> outputs(function.NumResiduals());
43 static auto constexpr D{Dual::DIMENSION};
44 Eigen::Map<Eigen::Matrix<
Scalar, -1, -1, JacobianLayout>> jmap(jacobian, outputs.size(), inputs.size());
46 for (
int s = 0; s < inputs.size(); s += D) {
47 int r = std::min(
static_cast<int>(inputs.size()), s + D);
49 for (
int i = s; i < r; ++i) {
50 inputs[i].v[i - s] = 1.0;
53 if (!function(inputs.data(), outputs.data())) {
57 for (
int i = s; i < r; ++i) {
58 inputs[i].v[i - s] = 0.0;
62 if constexpr (JacobianLayout == Eigen::ColMajor) {
63 for (
int i = s; i < r; ++i) {
64 std::transform(outputs.cbegin(), outputs.cend(), jmap.col(i).data(), [&](
auto const& jet) { return jet.v[i - s]; });
67 for (
auto i = 0; i < outputs.size(); ++i) {
68 std::copy_n(outputs[i].v.data(), r - s, jmap.row(i).data() + s);
72 if (residuals !=
nullptr) {
73 std::transform(std::cbegin(outputs), std::cend(outputs), residuals, [](
auto const& jet) {
return jet.a; });