WPILibC++ 2027.0.0-alpha-2
Loading...
Searching...
No Matches
expression_graph.hpp
Go to the documentation of this file.
1// Copyright (c) Sleipnir contributors
2
3#pragma once
4
5#include <ranges>
6
8
10
11namespace slp::detail {
12
13/**
14 * Generate a topological sort of an expression graph from parent to child.
15 *
16 * https://en.wikipedia.org/wiki/Topological_sorting
17 *
18 * @param root The root node of the expression.
19 */
21 const ExpressionPtr& root) {
23
24 // If the root type is a constant, Update() is a no-op, so there's no work
25 // to do
26 if (root == nullptr || root->type() == ExpressionType::CONSTANT) {
27 return list;
28 }
29
30 // Stack of nodes to explore
32
33 // Enumerate incoming edges for each node via depth-first search
34 stack.emplace_back(root.get());
35 while (!stack.empty()) {
36 auto node = stack.back();
37 stack.pop_back();
38
39 for (auto& arg : node->args) {
40 // If the node hasn't been explored yet, add it to the stack
41 if (arg != nullptr && ++arg->incoming_edges == 1) {
42 stack.push_back(arg.get());
43 }
44 }
45 }
46
47 // Generate topological sort of graph from parent to child.
48 //
49 // A node is only added to the stack after all its incoming edges have been
50 // traversed. Expression::incoming_edges is a decrementing counter for
51 // tracking this.
52 //
53 // https://en.wikipedia.org/wiki/Topological_sorting
54 stack.emplace_back(root.get());
55 while (!stack.empty()) {
56 auto node = stack.back();
57 stack.pop_back();
58
59 list.emplace_back(node);
60
61 for (auto& arg : node->args) {
62 // If we traversed all this node's incoming edges, add it to the stack
63 if (arg != nullptr && --arg->incoming_edges == 0) {
64 stack.push_back(arg.get());
65 }
66 }
67 }
68
69 return list;
70}
71
72/**
73 * Update the values of all nodes in this graph based on the values of
74 * their dependent nodes.
75 *
76 * @param list Topological sort of graph from parent to child.
77 */
79 // Traverse graph from child to parent and update values
80 for (auto& node : list | std::views::reverse) {
81 auto& lhs = node->args[0];
82 auto& rhs = node->args[1];
83
84 if (lhs != nullptr) {
85 if (rhs != nullptr) {
86 node->val = node->value(lhs->val, rhs->val);
87 } else {
88 node->val = node->value(lhs->val, 0.0);
89 }
90 }
91 }
92}
93
94} // namespace slp::detail
constexpr T * get() const noexcept
Returns the internal pointer.
Definition intrusive_shared_ptr.hpp:201
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition SmallVector.h:1198
reference emplace_back(ArgTypes &&... Args)
Definition SmallVector.h:939
void pop_back()
Definition SmallVector.h:427
void push_back(const T &Elt)
Definition SmallVector.h:415
bool empty() const
Definition SmallVector.h:88
reference back()
Definition SmallVector.h:310
Definition expression_graph.hpp:11
gch::small_vector< Expression * > topological_sort(const ExpressionPtr &root)
Generate a topological sort of an expression graph from parent to child.
Definition expression_graph.hpp:20
void update_values(const gch::small_vector< Expression * > &list)
Update the values of all nodes in this graph based on the values of their dependent nodes.
Definition expression_graph.hpp:78
@ CONSTANT
The expression is a constant.
virtual ExpressionType type() const =0
Returns the type of this expression (constant, linear, quadratic, or nonlinear).
auto arg(const Char *name, const T &arg) -> detail::named_arg< Char, T >
Returns a named argument to be used in a formatting function.
Definition base.h:2844