| 192 | DifferentiabilityMode TMode = DifferentiabilityMode::First, |
| 193 | int TDimension = Eigen::Dynamic> |
| 194 | struct FunctionExpr { |
| 195 | static constexpr int Dimension = TDimension; |
| 196 | using ScalarType = TScalar; |
| 197 | using VectorType = Eigen::Matrix<TScalar, Dimension, 1>; |
| 198 | using MatrixType = Eigen::Matrix<TScalar, Dimension, Dimension>; |
| 199 | static constexpr DifferentiabilityMode Differentiability = TMode; |
| 200 | |
| 201 | std::unique_ptr<FunctionInterface<TScalar, TMode, TDimension>> ptr; |
| 202 | |
| 203 | // Converting constructor. Accepts any non-FunctionExpr expression |
| 204 | // whose differentiability is at least as strong as `TMode` -- that is, |
| 205 | // we let a `Second`-mode source land in a `First`-mode wrapper (or a |
| 206 | // `First`-mode source land in a `None`-mode wrapper), discarding the |
| 207 | // extra derivative information. The static_asserts refuse upgrades. |
| 208 | template <typename F, typename = std::enable_if_t< |
| 209 | !std::is_same_v<std::decay_t<F>, FunctionExpr>>> |
| 210 | FunctionExpr(const F& f) { |
| 211 | static_assert( |
| 212 | static_cast<int>(F::Differentiability) >= static_cast<int>(TMode), |
| 213 | "Differentiability mode mismatch: source must supply at " |
| 214 | "least as much derivative information as the target mode " |
| 215 | "requires (downgrades are accepted, upgrades are not)."); |
| 216 | static_assert(F::Dimension == TDimension, "Dimension mismatch"); |
| 217 | static_assert(std::is_same<typename F::ScalarType, ScalarType>::value, |
| 218 | "Compile-time scalar-type mismatch"); |
| 219 | if constexpr (F::Differentiability == TMode) { |
| 220 | ptr = f.clone(); |
| 221 | } else { |
| 222 | // Downgrade adapter: wrap the stronger-mode clone so the stored |
| 223 | // pointer type matches `FunctionInterface<TScalar, TMode, Dim>`. |
| 224 | auto source = |
| 225 | f.clone(); // unique_ptr<FunctionInterface<T, F::Mode, Dim>> |
| 226 | ptr = std::make_unique<ModeDowngradeAdapter<TScalar, F::Differentiability, |
| 227 | TMode, TDimension>>( |
| 228 | std::move(source)); |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | // Copy constructor. |
| 233 | FunctionExpr(const FunctionExpr& other) |
| 234 | : ptr(other.ptr ? other.ptr->clone() : nullptr) {} |
| 235 | |
| 236 | // Copy assignment. |
| 237 | FunctionExpr& operator=(const FunctionExpr& other) { |
| 238 | if (this != &other) ptr = other.ptr ? other.ptr->clone() : nullptr; |
| 239 | return *this; |
| 240 | } |
| 241 | |
| 242 | // Default move constructor/assignment. |
| 243 | FunctionExpr(FunctionExpr&&) noexcept = default; |
| 244 | FunctionExpr& operator=(FunctionExpr&&) noexcept = default; |
| 245 | |
| 246 | // Call operator. |
| 247 | ScalarType operator()(const VectorType& x, VectorType* grad = nullptr, |
| 248 | MatrixType* hess = nullptr) const { |
| 249 | return (*ptr)(x, grad, hess); |
| 250 | } |
| 251 | |