26template <
typename DerivedX>
auto compute_dx(
const Eigen::MatrixBase<DerivedX> &x) {
27 return (x.tail(x.size() - 1) - x.head(x.size() - 1)).eval();
31template <
typename Derived>
32auto slice(
const Eigen::MatrixBase<Derived> &m, Eigen::Index start, Eigen::Index end) {
36 Eigen::Index n = m.size();
37 Eigen::Index s = (start < 0) ? (n + start) : start;
38 Eigen::Index e = (end < 0) ? (n + end) : end;
39 if (e == 0 && end < 0)
46 return m.head(0).eval();
48 return m.segment(s, e - s).eval();
51template <
typename DerivedA,
typename DerivedB>
52auto concatenate(
const Eigen::MatrixBase<DerivedA> &a,
const Eigen::MatrixBase<DerivedB> &b) {
53 using Scalar =
typename DerivedA::Scalar;
56 res.head(a.size()) = a;
57 res.tail(b.size()) = b;
63template <
typename DerivedF,
typename DerivedX>
65 const Eigen::MatrixBase<DerivedX> &x) {
66 auto x1 =
slice(x, 0, -2);
67 auto x2 =
slice(x, 1, -1);
68 auto x3 =
slice(x, 2, x.size());
70 auto f1 =
slice(f, 0, -2);
71 auto f2 =
slice(f, 1, -1);
72 auto f3 =
slice(f, 2, f.size());
75 auto h = (x2 - x1).
eval();
76 auto hp = (x3 - x2).
eval();
79 auto q3 = (1.0 + hp.array() / h.array()).eval();
83 auto num = f1.array() - f3.array() + 3.0 * q3.square() * (f1.array() + f2.array()) -
84 2.0 * q3 * (2.0 * f1.array() + f2.array());
85 auto den = 6.0 * q3 * (q3 - 1.0);
87 return (num / den).matrix().eval();
90template <
typename DerivedF,
typename DerivedX>
92 const Eigen::MatrixBase<DerivedX> &x) {
93 auto x1 =
slice(x, 0, -2);
94 auto x2 =
slice(x, 1, -1);
95 auto x3 =
slice(x, 2, x.size());
97 auto f1 =
slice(f, 0, -2);
98 auto f2 =
slice(f, 1, -1);
99 auto f3 =
slice(f, 2, f.size());
101 auto h = (x3 - x2).
eval();
102 auto hm = (x2 - x1).
eval();
105 auto q1 = (-hm.array() / h.array()).eval();
108 auto num = f2.array() - f1.array() + 3.0 * q1.square() * (f2.array() + f3.array()) -
109 2.0 * q1 * (2.0 * f2.array() + f3.array());
110 auto den = 6.0 * q1 * (q1 - 1.0);
112 return (num / den).matrix().eval();
115template <
typename DerivedF,
typename DerivedX>
116auto integrate_cubic(
const Eigen::MatrixBase<DerivedF> &f,
const Eigen::MatrixBase<DerivedX> &x) {
119 auto x1 =
slice(x, 0, -3);
120 auto x2 =
slice(x, 1, -2);
121 auto x3 =
slice(x, 2, -1);
122 auto x4 =
slice(x, 3, x.size());
124 auto f1 =
slice(f, 0, -3);
125 auto f2 =
slice(f, 1, -2);
126 auto f3 =
slice(f, 2, -1);
127 auto f4 =
slice(f, 3, f.size());
129 auto h = (x3 - x2).
eval();
130 auto hm = (x2 - x1).
eval();
131 auto hp = (x4 - x3).
eval();
134 auto q1 = (-hm.array() / h.array()).eval();
135 auto q4 = (1.0 + hp.array() / h.array()).eval();
145 auto q1_2 = q1.square();
146 auto q1_3 = q1_2 * q1;
147 auto q4_2 = q4.square();
148 auto q4_3 = q4_2 * q4;
150 auto f2_arr = f2.array();
151 auto f3_arr = f3.array();
152 auto f1_arr = f1.array();
153 auto f4_arr = f4.array();
155 auto num = 6.0 * q1_3 * q4_2 * (f2_arr + f3_arr) - 4.0 * q1_3 * q4 * (2.0 * f2_arr + f3_arr) +
156 2.0 * q1_3 * (f2_arr - f4_arr) - 6.0 * q1_2 * q4_3 * (f2_arr + f3_arr) +
157 3.0 * q1_2 * q4 * (3.0 * f2_arr + f3_arr) + 3.0 * q1_2 * (f4_arr - f2_arr) +
158 4.0 * q1 * q4_3 * (2.0 * f2_arr + f3_arr) -
159 3.0 * q1 * q4_2 * (3.0 * f2_arr + f3_arr) + q1 * (f2_arr - f4_arr) +
160 2.0 * q4_3 * (f1_arr - f2_arr) + 3.0 * q4_2 * (f2_arr - f1_arr) +
161 q4 * (f1_arr - f2_arr);
163 auto den = 12.0 * q1 * q4 * (q1 - 1.0) * (q1 - q4) * (q4 - 1.0);
165 return (num / den).matrix().eval();
182template <
typename DerivedF,
typename DerivedX>
185 const Eigen::MatrixBase<DerivedX> &x,
bool multiply_by_dx =
true,
186 const std::string &method =
"trapezoidal",
187 const std::string &method_endpoints =
"lower_order") {
188 using Scalar =
typename DerivedF::Scalar;
190 Eigen::Index n_points = f.size();
200 std::string m = method;
201 std::transform(m.begin(), m.end(), m.begin(), ::tolower);
203 std::replace(m.begin(), m.end(),
' ',
'_');
205 if (m ==
"forward_euler" || m ==
"forward" || m ==
"euler_forward") {
207 }
else if (m ==
"backward_euler" || m ==
"backward" || m ==
"euler_backward") {
209 }
else if (m ==
"trapezoidal" || m ==
"trapezoid" || m ==
"trapz") {
212 avg_f = (f_left + f_right) * 0.5;
213 }
else if (m ==
"forward_simpson" || m ==
"simpson_forward") {
221 }
else if (m ==
"backward_simpson" || m ==
"simpson_backward") {
224 }
else if (m ==
"simpson") {
245 }
else if (m.find(
"simpson") != std::string::npos && m !=
"simpson") {
248 }
else if (m ==
"cubic" || m ==
"cubic_spline") {
255 }
else if (m !=
"forward_euler" && m !=
"backward_euler" && m !=
"trapezoidal" &&
256 m !=
"forward" && m !=
"backward" && m !=
"euler_forward" && m !=
"euler_backward" &&
257 m !=
"trapz" && m !=
"trapezoid") {
259 "unknown method: " + method +
260 ". Use forward_euler, backward_euler, trapezoidal, simpson, or cubic.");
265 int remaining_start = 0;
266 int remaining_end = 0;
269 if (m.find(
"forward_simpson") != std::string::npos) {
272 }
else if (m.find(
"backward_simpson") != std::string::npos) {
275 }
else if (m.find(
"cubic") != std::string::npos) {
279 }
else if (m.find(
"euler") != std::string::npos) {
283 std::string eff_endpoints = method_endpoints;
285 if (eff_endpoints ==
"lower_order") {
287 std::string fallback_method =
"trapezoidal";
289 fallback_method =
"simpson";
296 if (remaining_start > 0) {
311 if (remaining_end > 0) {
314 detail::slice(x, -(1 + remaining_end), x.size()),
false,
"trapezoidal",
"ignore");
318 }
else if (eff_endpoints ==
"ignore") {
325 Eigen::Index current_size = avg_f.size();
326 if (current_size < dx.size()) {
331 if (m.find(
"forward_simpson") != std::string::npos) {
333 }
else if (m.find(
"backward_simpson") != std::string::npos) {
338 if (multiply_by_dx) {
339 return (avg_f.array() * dx.array()).matrix();
357template <
typename DerivedF,
typename DerivedX>
360 const Eigen::MatrixBase<DerivedX> &x,
361 const std::string &method =
"simpson") {
362 using Scalar =
typename DerivedF::Scalar;
364 Eigen::Index n_points = f.size();
369 std::string m = method;
370 std::transform(m.begin(), m.end(), m.begin(), ::tolower);
371 std::replace(m.begin(), m.end(),
' ',
'_');
373 if (m ==
"simpson") {
383 auto h = (x3 - x2).
eval();
384 auto hp = (x4 - x3).
eval();
386 auto df = (f3 - f2).
eval();
387 auto dfp = (f4 - f3).
eval();
390 auto numer = (df.array() * hp.array() - dfp.array() * h.array()).square();
391 auto denom = h.array() * hp.array().square() * (h.array() + hp.array()).square();
392 auto res_forward = (4.0 * numer / denom).
eval();
403 auto h_b = (x3_b - x2_b).
eval();
404 auto hm_b = (x2_b - x1_b).
eval();
406 auto dfm_b = (f2_b - f1_b).
eval();
407 auto df_b = (f3_b - f2_b).
eval();
410 auto numer_b = (df_b.array() * hm_b.array() - dfm_b.array() * h_b.array()).square();
411 auto denom_b = h_b.array() * hm_b.array().square() * (h_b.array() + hm_b.array()).square();
412 auto res_backward = (4.0 * numer_b / denom_b).
eval();
415 auto first_interval =
detail::slice(res_forward.matrix(), 0, 1);
416 auto last_interval =
detail::slice(res_backward.matrix(), -1, res_backward.size());
419 auto b =
detail::slice(res_forward.matrix(), 1, res_forward.size());
427 }
else if (m ==
"hybrid_simpson_cubic") {
439 (dfdx1.array().
square() + dfdx1.array() * dfdx2.array() + dfdx2.array().square()) /
441 auto term2 = 12.0 * df.array() / h.array().square() *
442 (df.array() / h.array() - dfdx1.array() - dfdx2.array());
444 return (term1 + term2).matrix();
447 ". Use 'simpson' or 'hybrid_simpson_cubic'.");
Scalar and element-wise arithmetic functions (abs, sqrt, pow, exp, log, etc.).
Numerical differentiation and integration (gradient, trapz, cumtrapz, diff).
C++20 concepts constraining valid Janus scalar types.
Custom exception hierarchy for Janus framework.
Core type aliases for numeric and symbolic Eigen/CasADi interop.
Conditional selection, comparison, and logical operations.
Integration/ODE solver errors.
Definition JanusError.hpp:61
Smooth approximation of ReLU function: softplus(x) = (1/beta) * log(1 + exp(beta * x)).
Definition Diagnostics.hpp:131
auto slice(const Eigen::MatrixBase< Derived > &m, Eigen::Index start, Eigen::Index end)
Definition IntegrateDiscrete.hpp:32
auto concatenate(const Eigen::MatrixBase< DerivedA > &a, const Eigen::MatrixBase< DerivedB > &b)
Definition IntegrateDiscrete.hpp:52
auto compute_dx(const Eigen::MatrixBase< DerivedX > &x)
Definition IntegrateDiscrete.hpp:26
constexpr double rms_fusion_epsilon
Small epsilon to prevent division by zero in RMS fusion.
Definition IntegrateDiscrete.hpp:23
auto integrate_forward_simpson(const Eigen::MatrixBase< DerivedF > &f, const Eigen::MatrixBase< DerivedX > &x)
Definition IntegrateDiscrete.hpp:64
auto integrate_backward_simpson(const Eigen::MatrixBase< DerivedF > &f, const Eigen::MatrixBase< DerivedX > &x)
Definition IntegrateDiscrete.hpp:91
auto integrate_cubic(const Eigen::MatrixBase< DerivedF > &f, const Eigen::MatrixBase< DerivedX > &x)
Definition IntegrateDiscrete.hpp:116
Definition Diagnostics.hpp:19
auto gradient(const Eigen::MatrixBase< DerivedF > &f, const Spacing &dx=1.0, int edge_order=1, int n=1)
Computes gradient using second-order accurate central differences.
Definition Calculus.hpp:178
T square(const T &x)
Computes x^2 (more efficient than pow(x, 2)).
Definition Arithmetic.hpp:739
T sqrt(const T &x)
Computes the square root of a scalar.
Definition Arithmetic.hpp:46
JanusVector< typename DerivedF::Scalar > integrate_discrete_squared_curvature(const Eigen::MatrixBase< DerivedF > &f, const Eigen::MatrixBase< DerivedX > &x, const std::string &method="simpson")
Computes the integral of squared curvature over each interval.
Definition IntegrateDiscrete.hpp:359
JanusVector< typename DerivedF::Scalar > integrate_discrete_intervals(const Eigen::MatrixBase< DerivedF > &f, const Eigen::MatrixBase< DerivedX > &x, bool multiply_by_dx=true, const std::string &method="trapezoidal", const std::string &method_endpoints="lower_order")
Integrates discrete samples using reconstruction methods.
Definition IntegrateDiscrete.hpp:184
auto eval(const Eigen::MatrixBase< Derived > &mat)
Evaluate a symbolic matrix to a numeric Eigen matrix.
Definition JanusIO.hpp:62
Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > JanusVector
Dynamic-size column vector for both numeric and symbolic backends.
Definition JanusTypes.hpp:49