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 node->visit_args([&stack](
const auto& arg) {
50 if (++arg->scratch == 0) {
62 stack.emplace_back(root.get());
63 while (!stack.empty()) {
64 auto node = stack.back();
67 list.emplace_back(node);
69 node->visit_args([&stack](
const auto& arg) {
71 if (--arg->scratch == -1) {
85template <
typename Scalar>
86void update_values(
const ExpressionGraph<Scalar>& list) {
88 for (
auto& node : list | std::views::reverse) {
91 node->val = node->value();
104template <
typename Scalar>
106 const ExpressionGraph<Scalar>& top_list,
107 const gch::small_vector<std::pair<
int, detail::Expression<Scalar>*>>&
109 gch::small_vector<Eigen::Triplet<Scalar>>& triplets,
int row) {
113 if (top_list.empty()) {
118 top_list[0]->adj = Scalar(1);
121 for (
auto& node : top_list | std::views::drop(1)) {
122 node->adj = Scalar(0);
129 for (
const auto& node : top_list) {
131 if (!node->is_leaf) {
132 node->accumulate_adjoints();
138 for (
const auto& [col, node] : output_list) {
140 triplets.emplace_back(row, col, node->adj);