8#include <Eigen/SparseCore>
9#include <gch/small_vector.hpp>
11#include "sleipnir/autodiff/expression.hpp"
12#include "sleipnir/autodiff/expression_type.hpp"
14namespace slp::detail {
19template <
typename Scalar>
20using ExpressionGraph = gch::small_vector<Expression<Scalar>*>;
28template <
typename Scalar>
29ExpressionGraph<Scalar> topological_sort(
const ExpressionPtr<Scalar>& root) {
30 ExpressionGraph<Scalar> list;
33 if (root ==
nullptr || root->type() == ExpressionType::CONSTANT) {
38 gch::small_vector<Expression<Scalar>*> stack;
43 stack.emplace_back(root.get());
44 while (!stack.empty()) {
45 auto node = stack.back();
48 for (
auto& arg : node->args) {
50 if (arg !=
nullptr && ++arg->scratch == 0) {
51 stack.push_back(arg.get());
62 stack.emplace_back(root.get());
63 while (!stack.empty()) {
64 auto node = stack.back();
67 list.emplace_back(node);
69 for (
auto& arg : node->args) {
71 if (arg !=
nullptr && --arg->scratch == -1) {
72 stack.push_back(arg.get());
85template <
typename Scalar>
86void update_values(
const ExpressionGraph<Scalar>& list) {
88 for (
auto& node : list | std::views::reverse) {
89 auto& lhs = node->args[0];
90 auto& rhs = node->args[1];
93 node->val = node->value(lhs->val, rhs ? rhs->val : Scalar(0));
106template <
typename Scalar>
108 const ExpressionGraph<Scalar>& top_list,
109 const gch::small_vector<std::pair<
int, detail::Expression<Scalar>*>>&
111 gch::small_vector<Eigen::Triplet<Scalar>>& triplets,
int row) {
115 if (top_list.empty()) {
120 top_list[0]->adjoint = Scalar(1);
123 for (
auto& node : top_list | std::views::drop(1)) {
124 node->adjoint = Scalar(0);
131 for (
const auto& node : top_list) {
132 auto& lhs = node->args[0];
133 auto& rhs = node->args[1];
135 if (lhs !=
nullptr) {
136 if (rhs !=
nullptr) {
138 lhs->adjoint += node->grad_l(lhs->val, rhs->val);
139 rhs->adjoint += node->grad_r(lhs->val, rhs->val);
142 lhs->adjoint += node->grad_l(lhs->val, Scalar(0));
149 for (
const auto& [col, node] : output_list) {
151 triplets.emplace_back(row, col, node->adjoint);