#ifndef LEARNER_AUTOGRAD_H #define LEARNER_AUTOGRAD_H #include #include #include #include #include namespace Learner::Autograd::UnivariateStatic { template struct Identity { using type = T; }; template using Id = typename Identity::type; template struct VariableParameter { using ValueType = T; VariableParameter() { } template T value(const std::tuple& args) const { return std::get(args); } template T grad(const std::tuple&) const { return T(1.0); } }; template struct ConstantParameter { using ValueType = T; ConstantParameter() { } template T value(const std::tuple& args) const { return std::get(args); } template T grad(const std::tuple&) const { return T(0.0); } }; template struct Constant { using ValueType = T; Constant(T x) : m_x(std::move(x)) { } template T value(const std::tuple&) const { return m_x; } template T grad(const std::tuple&) const { return T(0.0); } private: T m_x; }; template struct Sum { using ValueType = T; Sum(LhsT lhs, RhsT rhs) : m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) { } template T value(const std::tuple& args) const { return m_lhs.value(args) + m_rhs.value(args); } template T grad(const std::tuple& args) const { return m_lhs.grad(args) + m_rhs.grad(args); } private: LhsT m_lhs; RhsT m_rhs; }; template auto operator+(LhsT lhs, RhsT rhs) { return Sum(std::move(lhs), std::move(rhs)); } template auto operator+(LhsT lhs, Id rhs) { return Sum(std::move(lhs), Constant(rhs)); } template auto operator+(Id lhs, RhsT rhs) { return Sum(Constant(lhs), std::move(rhs)); } template struct Difference { using ValueType = T; Difference(LhsT lhs, RhsT rhs) : m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) { } template T value(const std::tuple& args) const { return m_lhs.value(args) - m_rhs.value(args); } template T grad(const std::tuple& args) const { return m_lhs.grad(args) - m_rhs.grad(args); } private: LhsT m_lhs; RhsT m_rhs; }; template auto operator-(LhsT lhs, RhsT rhs) { return Difference(std::move(lhs), std::move(rhs)); } template auto operator-(LhsT lhs, Id rhs) { return Difference(std::move(lhs), Constant(rhs)); } template auto operator-(Id lhs, RhsT rhs) { return Difference(Constant(lhs), std::move(rhs)); } template struct Product { using ValueType = T; Product(LhsT lhs, RhsT rhs) : m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) { } template T value(const std::tuple& args) const { return m_lhs.value(args) * m_rhs.value(args); } template T grad(const std::tuple& args) const { return m_lhs.grad(args) * m_rhs.value(args) + m_lhs.value(args) * m_rhs.grad(args); } private: LhsT m_lhs; RhsT m_rhs; }; template auto operator*(LhsT lhs, RhsT rhs) { return Product(std::move(lhs), std::move(rhs)); } template auto operator*(LhsT lhs, Id rhs) { return Product(std::move(lhs), Constant(rhs)); } template auto operator*(Id lhs, RhsT rhs) { return Product(Constant(lhs), std::move(rhs)); } template struct Sigmoid { using ValueType = T; explicit Sigmoid(ArgT x) : m_x(std::move(x)) { } template T value(const std::tuple& args) const { return value_(m_x.value(args)); } template T grad(const std::tuple& args) const { return m_x.grad(args) * grad_(m_x.value(args)); } private: ArgT m_x; T value_(T x) const { return 1.0 / (1.0 + std::exp(-x)); } T grad_(T x) const { return value_(x) * (1.0 - value_(x)); } }; template auto sigmoid(ArgT x) { return Sigmoid(std::move(x)); } template struct Pow { using ValueType = T; explicit Pow(ArgT x, Id exponent) : m_x(std::move(x)), m_exponent(std::move(exponent)) { } template T value(const std::tuple& args) const { return std::pow(m_x.value(args), m_exponent); } template T grad(const std::tuple& args) const { return m_exponent * std::pow(m_x.value(args), m_exponent - T(1.0)) * m_x.grad(args); } private: ArgT m_x; T m_exponent; }; template auto pow(ArgT x, Id exp) { return Pow(std::move(x), std::move(exp)); } template struct Log { using ValueType = T; explicit Log(ArgT x) : m_x(std::move(x)) { } template T value(const std::tuple& args) const { return value_(m_x.value(args)); } template T grad(const std::tuple& args) const { return m_x.grad(args) * grad_(m_x.value(args)); } private: ArgT m_x; T value_(T x) const { return std::log(x); } T grad_(T x) const { return 1.0 / x; } }; template auto log(ArgT x) { return Log(std::move(x)); } } #endif