CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
512 lines
19 KiB
C++
512 lines
19 KiB
C++
// Copyright Advanced Micro Devices, Inc., or its affiliates.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#pragma once
|
|
|
|
#include <functional>
|
|
#include <map>
|
|
#include <ranges>
|
|
#include <set>
|
|
#include <unordered_set>
|
|
#include <variant>
|
|
#include <vector>
|
|
|
|
#include <rocRoller/Graph/HypergraphIncidenceContainer.hpp>
|
|
#include <rocRoller/Graph/Hypergraph_fwd.hpp>
|
|
#include <rocRoller/Serialization/Base_fwd.hpp>
|
|
#include <rocRoller/Utilities/Concepts.hpp>
|
|
#include <rocRoller/Utilities/Generator.hpp>
|
|
#include <rocRoller/Utilities/Utils.hpp>
|
|
|
|
namespace rocRoller
|
|
{
|
|
namespace Graph
|
|
{
|
|
enum class ElementType : int
|
|
{
|
|
Node = 0,
|
|
Edge,
|
|
Count
|
|
};
|
|
|
|
std::string toString(ElementType e);
|
|
|
|
/**
|
|
* @brief Returns the complementary type to `t`.
|
|
*/
|
|
ElementType getConnectingType(ElementType t);
|
|
|
|
enum class Direction : int
|
|
{
|
|
Upstream = 0,
|
|
Downstream,
|
|
Count
|
|
};
|
|
|
|
std::string toString(Direction d);
|
|
constexpr Direction opposite(Direction d);
|
|
|
|
enum class GraphModification : int
|
|
{
|
|
DeleteElement = 0,
|
|
AddElement,
|
|
SetElement,
|
|
Count
|
|
};
|
|
|
|
std::string toString(GraphModification m);
|
|
|
|
/**
|
|
* @brief A directed Hypergraph.
|
|
*
|
|
* @tparam Node What objects represent the nodes in the graph? Typically a std::variant
|
|
* @tparam Edge What objects represent the edges in the graph? Typically a std::variant
|
|
* @tparam Hyper A Hypergraph (true) is a graph where an edge can connect to any number of
|
|
* incoming and outgoing nodes. A "calm" graph (false) is an ordinary graph where an edge
|
|
* connects to at most one incoming node and at most one outgoing node.
|
|
*/
|
|
template <typename Node, typename Edge, bool Hyper = true>
|
|
class Hypergraph
|
|
{
|
|
public:
|
|
using Element = std::variant<Node, Edge>;
|
|
|
|
inline static constexpr bool IsHyper = Hyper;
|
|
|
|
static std::string ElementName(Element const& el);
|
|
|
|
struct Location
|
|
{
|
|
int tag;
|
|
std::vector<int> incoming;
|
|
std::vector<int> outgoing;
|
|
|
|
Element element;
|
|
|
|
constexpr inline bool operator==(Location const& rhs) const;
|
|
};
|
|
|
|
bool exists(int tag) const;
|
|
|
|
/**
|
|
* @brief Returns whether `tag` points to a node or an edge.
|
|
*/
|
|
ElementType getElementType(int tag) const;
|
|
|
|
template <typename T = Node>
|
|
T getNode(int tag) const;
|
|
|
|
template <typename T = Edge>
|
|
T getEdge(int tag) const;
|
|
|
|
/**
|
|
* @brief Returns whether `e` is a node or an edge.
|
|
*/
|
|
ElementType getElementType(Element const& e) const;
|
|
|
|
virtual void clearCache(GraphModification modification);
|
|
|
|
template <typename T>
|
|
int addElement(T&& element);
|
|
|
|
/**
|
|
* Adds each element to the graph and returns a tuple of int.
|
|
*/
|
|
template <typename T, typename... Ts>
|
|
auto addElements(T&& element, Ts&&... rest);
|
|
|
|
/**
|
|
* @brief Set (overwrite) existing element.
|
|
*/
|
|
template <typename T>
|
|
void setElement(int tag, T&& element);
|
|
|
|
template <typename T>
|
|
int addElement(T&& element,
|
|
std::initializer_list<int> inputs,
|
|
std::initializer_list<int> outputs);
|
|
|
|
template <typename T, CForwardRangeOf<int> T_Inputs, CForwardRangeOf<int> T_Outputs>
|
|
int addElement(T&& element, T_Inputs const& inputs, T_Outputs const& outputs);
|
|
|
|
template <typename T, CForwardRangeOf<int> T_Inputs, CForwardRangeOf<int> T_Outputs>
|
|
void addElement(int tag, T&& element, T_Inputs const& inputs, T_Outputs const& outputs);
|
|
|
|
void deleteElement(int tag);
|
|
|
|
template <CForwardRangeOf<int> T_Inputs,
|
|
CForwardRangeOf<int> T_Outputs,
|
|
std::predicate<Edge const&> T_Predicate>
|
|
void deleteElement(T_Inputs const& inputs,
|
|
T_Outputs const& outputs,
|
|
T_Predicate edgePredicate);
|
|
|
|
template <typename T, CForwardRangeOf<int> T_Inputs, CForwardRangeOf<int> T_Outputs>
|
|
requires(std::constructible_from<Edge, T>) void deleteElement(T_Inputs const& inputs,
|
|
T_Outputs const& outputs);
|
|
|
|
size_t getElementCount() const;
|
|
|
|
Element const& getElement(int tag) const;
|
|
|
|
/**
|
|
* @brief Returns a Location info object detailing connections to the element `tag`.
|
|
*/
|
|
Location getLocation(int tag) const;
|
|
|
|
/**
|
|
* @brief Yields element tag without any incoming connections.
|
|
*/
|
|
Generator<int> roots() const;
|
|
|
|
/**
|
|
* @brief Yields element tag without any outgoing connections.
|
|
*/
|
|
Generator<int> leaves() const;
|
|
|
|
/**
|
|
* @brief Yields element tag that are the child nodes of a given element
|
|
*/
|
|
Generator<int> childNodes(int parent) const;
|
|
|
|
/**
|
|
* @brief Yields element tag that are the parent nodes of a given element
|
|
*/
|
|
Generator<int> parentNodes(int child) const;
|
|
|
|
Generator<int> allElements() const;
|
|
|
|
/**
|
|
* @brief Yields element tags connected in the specified direction to start, in
|
|
* depth-first order
|
|
*/
|
|
Generator<int> depthFirstVisit(int start, Direction dir = Direction::Downstream) const;
|
|
|
|
/**
|
|
* @brief Yields node tag connected in the specified direction to start, that satisfy
|
|
* the node selector.
|
|
*/
|
|
template <std::predicate<int> Predicate>
|
|
Generator<int> findNodes(int start,
|
|
Predicate nodeSelector,
|
|
Direction dir = Direction::Downstream) const;
|
|
|
|
/**
|
|
* @brief Yields node tag connected in the specified direction to start, that satisfy
|
|
* the node selector.
|
|
*/
|
|
template <CForwardRangeOf<int> Range, std::predicate<int> Predicate>
|
|
Generator<int> findNodes(Range const& starts,
|
|
Predicate nodeSelector,
|
|
Direction dir = Direction::Downstream) const;
|
|
|
|
/**
|
|
* @brief Yields node tag that satisfy the node selector.
|
|
*/
|
|
template <std::predicate<int> Predicate>
|
|
Generator<int> findElements(Predicate nodeSelector) const;
|
|
|
|
/**
|
|
* @brief Yields element tags connected in the specified direction to starts, in
|
|
* depth-first order
|
|
*/
|
|
template <CForwardRangeOf<int> Range>
|
|
Generator<int> depthFirstVisit(Range const& starts,
|
|
Direction dir = Direction::Downstream) const;
|
|
|
|
/**
|
|
* @brief Yields element tags connected in the specified direction to starts, in
|
|
* depth-first order.
|
|
*
|
|
* Will only visit through edges if the edgePredicate returns true.
|
|
*/
|
|
template <CForwardRangeOf<int> Range, std::predicate<int> Predicate>
|
|
Generator<int> depthFirstVisit(Range const& starts,
|
|
Predicate edgePredicate,
|
|
Direction dir = Direction::Downstream) const;
|
|
|
|
/**
|
|
* @brief Yields element tags connected in the specified direction to the start, in
|
|
* depth-first order.
|
|
*
|
|
* Will only visit through edges if the edgePredicate returns true.
|
|
*/
|
|
template <std::predicate<int> Predicate>
|
|
Generator<int> depthFirstVisit(int start, Predicate edgePredicate, Direction dir) const;
|
|
|
|
/**
|
|
* @brief Yields element tags connected in the specified direction to start, in
|
|
* depth-first order.
|
|
*
|
|
* Will not yield any nodes in `visitedNodes`, and will insert nodes `visitedNodes` to
|
|
* track already visited nodes.
|
|
*/
|
|
template <Direction Dir>
|
|
Generator<int> depthFirstVisit(int start, std::unordered_set<int>& visitedNodes) const;
|
|
|
|
template <Direction Dir, std::predicate<int> Predicate>
|
|
Generator<int> depthFirstVisit(int start,
|
|
Predicate edgePredicate,
|
|
std::unordered_set<int>& visitedNodes) const;
|
|
|
|
/**
|
|
* @brief Yields element tags connected in the specified direction of start, in
|
|
* breadth-first order.
|
|
*/
|
|
Generator<int> breadthFirstVisit(int start,
|
|
Direction dir = Direction::Downstream) const;
|
|
|
|
/**
|
|
* @brief Yields element tag (both nodes and edges) that form the paths
|
|
* from the starts to the ends
|
|
*/
|
|
template <Direction Dir,
|
|
CForwardRangeOf<int> RangeStart,
|
|
CForwardRangeOf<int> RangeEnd,
|
|
std::predicate<int> Predicate>
|
|
Generator<int> path(RangeStart const& starts,
|
|
RangeEnd const& ends,
|
|
Predicate edgeSelector,
|
|
std::map<int, bool>& visitedElements) const;
|
|
|
|
/**
|
|
* @brief Yields element tag (both nodes and edges) that form the paths
|
|
* from the starts to the ends
|
|
*/
|
|
template <Direction Dir,
|
|
CForwardRangeOf<int> RangeStart,
|
|
CForwardRangeOf<int> RangeEnd,
|
|
std::predicate<int> Predicate>
|
|
Generator<int>
|
|
path(RangeStart const& starts, RangeEnd const& ends, Predicate edgeSelector) const;
|
|
|
|
/**
|
|
* @brief Yields element tag (both nodes and edges) that form the paths
|
|
* from the starts to the ends
|
|
*/
|
|
template <Direction Dir, CForwardRangeOf<int> RangeStart, CForwardRangeOf<int> RangeEnd>
|
|
Generator<int> path(RangeStart const& starts, RangeEnd const& ends) const;
|
|
|
|
/**
|
|
* @brief Yields element tags of immediately connecting elements in the direction
|
|
* specified
|
|
*/
|
|
template <Direction Dir>
|
|
std::vector<int> getNeighbours(int const tag) const;
|
|
|
|
/**
|
|
* @brief Yields element tags of immediately connecting elements in the direction
|
|
* specified
|
|
*/
|
|
std::vector<int> getNeighbours(int const tag, Direction Dir) const;
|
|
|
|
/**
|
|
* @brief Return edges in topological order.
|
|
*
|
|
* Traversing edges in topological order preserves edge
|
|
* dependencies.
|
|
*/
|
|
Generator<int> topologicalSort() const;
|
|
|
|
/**
|
|
* @brief Return edges in reverse topological order.
|
|
*
|
|
* Traversing edges in reverse topological order can preserves edge
|
|
* dependencies.
|
|
*/
|
|
Generator<int> reverseTopologicalSort() const;
|
|
|
|
std::string toDOT(std::string const& prefix = "", bool standalone = true) const;
|
|
|
|
static bool identity(Edge const&)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
template <std::predicate<Edge const&> Predicate>
|
|
std::string toDOT(Predicate edgePredicate = identity) const;
|
|
|
|
/**
|
|
* @brief Yields all element tags that match the supplied element type
|
|
*
|
|
* @tparam T Type of element to filter by. Can be Node, Edge, or a subvariant of those.
|
|
*/
|
|
template <typename T>
|
|
requires(std::constructible_from<Node, T> || std::constructible_from<Edge, T>)
|
|
Generator<int> getElements()
|
|
const;
|
|
|
|
/**
|
|
* @brief Yields tags of all Nodes
|
|
*
|
|
* @tparam T Subvariant of Node to filter by. Returns all Node tags by default.
|
|
*/
|
|
template <typename T = Node>
|
|
requires(std::constructible_from<Node, T>) Generator<int> getNodes()
|
|
const;
|
|
|
|
/**
|
|
* @brief Yields tags of all Edges
|
|
*
|
|
* @tparam T Subvariant of Edge to filter by. Returns all Edge tags by default.
|
|
*/
|
|
template <typename T = Edge>
|
|
requires(std::constructible_from<Edge, T>) Generator<int> getEdges()
|
|
const;
|
|
|
|
/**
|
|
* @brief Yields tags of nodes immediately connected to `dst` through Edges of type T,
|
|
* in direction Dir.
|
|
*/
|
|
template <typename T, Direction Dir>
|
|
requires(std::constructible_from<Edge, T>) Generator<int> getConnectedNodeIndices(
|
|
int const dst)
|
|
const;
|
|
|
|
/**
|
|
* @brief Yields tags of nodes immediately connected to `dst` through Edges that satisfy
|
|
* the edgePredicate, in direction Dir.
|
|
*/
|
|
template <Direction Dir, std::predicate<Edge const&> Predicate>
|
|
Generator<int> getConnectedNodeIndices(int const dst, Predicate edgePredicate) const;
|
|
|
|
/**
|
|
* @brief Yields tags of nodes that immediately preceed `dst` where the Edges are of
|
|
* type T.
|
|
*/
|
|
template <typename T>
|
|
requires(std::constructible_from<Edge, T>) Generator<int> getInputNodeIndices(
|
|
int const dst)
|
|
const;
|
|
|
|
/**
|
|
* @brief Yields tags of nodes that immediately preceed `dst` where the Edges satisfy
|
|
* the edgePredicate.
|
|
*/
|
|
template <std::predicate<Edge const&> Predicate>
|
|
Generator<int> getInputNodeIndices(int const dst, Predicate edgePredicate) const;
|
|
|
|
Generator<std::tuple<int, Edge>> getInputNodesAndEdges(int dst);
|
|
|
|
/**
|
|
* @brief Yields tags of nodes that immediately follow `src` where the Edges are of type
|
|
* T.
|
|
*/
|
|
template <typename T>
|
|
requires(std::constructible_from<Edge, T>) Generator<int> getOutputNodeIndices(
|
|
int const src)
|
|
const;
|
|
|
|
/**
|
|
* @brief Yields tags of nodes that immediately follow `src` where the Edges satisfy the
|
|
* edgePredicate.
|
|
*/
|
|
template <std::predicate<Edge const&> Predicate>
|
|
Generator<int> getOutputNodeIndices(int const src, Predicate edgePredicate) const;
|
|
|
|
/**
|
|
* @brief Finds all downstream node tags that are connected to `candidates` via the
|
|
* specified Edge type. The set of original candidates is included in the returned set.
|
|
*
|
|
* Note that this function recursively follows edges.
|
|
*
|
|
* @param candidates Set of Node tags
|
|
* @return std::set<int> Set of Node tags expanded
|
|
*/
|
|
template <typename T>
|
|
requires(std::constructible_from<Edge, T>) std::set<int> followEdges(
|
|
std::set<int> const& candidates)
|
|
const;
|
|
|
|
/**
|
|
* @brief Find an edge that connects two nodes, if one exists.
|
|
*
|
|
* @param tail Tag of Node that is downstream of Edge
|
|
* @param head Tag of Node that is upstream of Edge
|
|
* @return std::optional<int> Tag of connecting Edge, if one exists.
|
|
*/
|
|
std::optional<int> findEdge(int tail, int head) const;
|
|
|
|
/**
|
|
* This function is called to disallow certain operations
|
|
* (add/delete certain elements).
|
|
*/
|
|
virtual bool isModificationAllowed(int) const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// clang-format off
|
|
private:
|
|
// clang-format on
|
|
|
|
template <typename T1, typename T2, typename T3>
|
|
friend struct rocRoller::Serialization::MappingTraits;
|
|
|
|
/**
|
|
* @brief Map of Element tags and Elements
|
|
*
|
|
*/
|
|
std::map<int, Element> m_elements;
|
|
|
|
/**
|
|
* @brief Container holding the incident connections between Hypergraph Elements
|
|
*
|
|
*/
|
|
HypergraphIncidenceContainer m_incidence;
|
|
|
|
template <Direction Dir>
|
|
bool edgeSatisfied(int const edge, std::map<int, bool> const& visitedElements) const;
|
|
|
|
/**
|
|
* @brief Gets a tag that hasn't been used in the Hypergraph for a new Element
|
|
*
|
|
* @return int Next available tag that can be used to store an Element
|
|
*/
|
|
int nextAvailableTag() const;
|
|
};
|
|
|
|
template <typename Node, typename Edge, bool Hyper>
|
|
std::ostream& operator<<(std::ostream& stream, Hypergraph<Node, Edge, Hyper> const& graph);
|
|
|
|
template <typename Cls>
|
|
std::string variantToString(Cls const& el)
|
|
{
|
|
return std::visit([](auto const& v) { return toString(v); }, el);
|
|
}
|
|
|
|
/**
|
|
* Yields nodes connected to start:
|
|
*
|
|
* - In direction `Dir`
|
|
* - Connected to `start` by edges satisfying `edgePredicate` and nodes satisfying
|
|
* `nodePredicate`
|
|
* - The nodes that are yielded must satisfy destNodePredicate.
|
|
*
|
|
* @param graph A graph
|
|
* @param start The starting node
|
|
* @param nodePredicate Only traverse nodes that satisfy this predicate.
|
|
* @param edgePredicate Only traverse edges that satisfy this predicate.
|
|
* @param destNodePredicate Only yield nodes that satisfy this predicate.
|
|
*/
|
|
template <Graph::Direction Dir, typename Node, typename Edge, bool Hyper>
|
|
Generator<int> reachableNodes(Graph::Hypergraph<Node, Edge, Hyper> const& graph,
|
|
int start,
|
|
auto nodePredicate,
|
|
auto edgePredicate,
|
|
auto destNodePredicate);
|
|
|
|
/**
|
|
* @brief A Hypergraph is a graph where an edge can connect to any number of incoming and
|
|
* outgoing nodes. A "calm" graph is an ordinary graph where an edge connects to exactly one
|
|
* incoming node and exactly one outgoing node.
|
|
*
|
|
* @tparam T The graph to test
|
|
*/
|
|
template <typename T>
|
|
concept CCalmGraph = !T::IsHyper;
|
|
}
|
|
}
|
|
|
|
#include <rocRoller/Graph/Hypergraph_impl.hpp>
|