#ifndef JET_HPP #define JET_HPP #include #include #include using Eigen::Vector; template struct jet { T value; constexpr static unsigned int n_vars = _n_vars; Eigen::Array deriv; jet() = default; jet(T v) : value(v), deriv(Eigen::Array::Zero()){} jet(T v, Eigen::Array d) : value(v), deriv(d){} jet(T v, T d) requires(n_vars == 1) : value(v), deriv(d){} operator T()const noexcept{ return value; } // Addition operator jet operator+(const jet& other) const { return {value + other.value, deriv + other.deriv}; } // Subtraction operator jet operator-(const jet& other) const { return {value - other.value, deriv - other.deriv}; } // Multiplication operator jet operator*(const jet& other) const { return {value * other.value, value * other.deriv + deriv * other.value}; } // Division operator jet operator/(const jet& other) const { T denominator = other.value * other.value; return {value / other.value, (deriv * other.value - value * other.deriv) / denominator}; } // Compound assignment operators // += jet& operator+=(const jet& other) { value += other.value; deriv += other.deriv; return *this; } // -= jet& operator-=(const jet& other) { value -= other.value; deriv -= other.deriv; return *this; } // *= jet& operator*=(const jet& other) { T oldValue = value; value *= other.value; deriv = oldValue * other.deriv + deriv * other.value; return *this; } // /= jet& operator/=(const jet& other) { T denominator = other.value * other.value; T oldValue = value; value /= other.value; deriv = (deriv * other.value - oldValue * other.deriv) / denominator; return *this; } template R> jet operator+(const R& scalar) const { return {value + scalar, deriv}; } // Subtraction operator with T value template R> jet operator-(const R& scalar) const { return {value - scalar, deriv}; } // Multiplication operator with T value template R> jet operator*(const R& scalar) const { return {value * scalar, deriv * scalar}; } // Division operator with T value template R> jet operator/(const R& scalar) const { return {value / scalar, deriv / scalar}; } // Compound assignment operators with T values // += template R> jet& operator+=(const R& scalar) { value += scalar; return *this; } // -= template R> jet& operator-=(const R& scalar) { value -= scalar; return *this; } // *= template R> jet& operator*=(const R& scalar) { value *= scalar; deriv *= scalar; return *this; } // /= template R> jet& operator/=(const R& scalar) { value /= scalar; deriv /= scalar; return *this; } template friend stream_t& operator<<(stream_t& str, const jet& j){ str << '(' << j.value << ", d/dx = " << j.deriv.transpose() << ')'; return str; } }; template jet sin(const jet& x) { using std::sin; using std::cos; return {sin(x.value), x.deriv * cos(x.value)}; } template jet cos(const jet& x) { using std::sin; using std::cos; return {cos(x.value), -x.deriv * sin(x.value)}; } template jet exp(const jet& x) { using std::exp; T expVal = exp(x.value); return {expVal, x.deriv * expVal}; } template jet log(const jet& x) { using std::log; return {log(x.value), x.deriv / x.value}; } template jet sqrt(const jet& x) { T sqrtVal = sqrt(x.value); return {sqrtVal, x.deriv / (T(2) * sqrtVal)}; } #endif