Skip to content
This repository has been archived by the owner on Dec 10, 2024. It is now read-only.

Core: New split path algo #139

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 19 additions & 14 deletions src/faebryk/core/cpp/include/graph/graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class GraphInterface {

template <typename T> static std::shared_ptr<T> factory();
std::unordered_set<GI_ref_weak> get_gif_edges();
std::unordered_map<GI_ref_weak, Link_ref> &get_edges();
Map<GI_ref_weak, Link_ref> &get_edges();
std::optional<Link_ref> is_connected(GI_ref_weak to);
Graph_ref get_graph();
std::unordered_set<Node_ref> get_connected_nodes(std::vector<nb::type_object> types);
Expand Down Expand Up @@ -200,23 +200,28 @@ class Path {
public:
Path(/*const*/ GI_ref_weak path_head);
Path(std::vector<GI_ref_weak> path);
Path(std::vector<GI_ref_weak> path, GI_ref_weak head);
Path(const Path &other);
Path(Path &&other);
~Path();

std::vector</*const*/ GI_ref_weak> path;
const std::vector</*const*/ GI_ref_weak> path;

/*const*/ Link_weak_ref get_link(Edge edge) /*const*/;
std::optional<Edge> last_edge() /*const*/;
std::optional<TriEdge> last_tri_edge() /*const*/;
/*const*/ GI_ref_weak last() /*const*/;
/*const*/ GI_ref_weak first() /*const*/;
/*const*/ GI_ref_weak operator[](int idx) /*const*/;
size_t size() /*const*/;
bool contains(/*const*/ GI_ref_weak gif) /*const*/;
void iterate_edges(std::function<bool(Edge &)> visitor) /*const*/;
/*const*/ std::vector</*const*/ GI_ref_weak> &get_path() /*const*/;
size_t index(/*const*/ GI_ref_weak gif) /*const*/;
/*const*/ Link_weak_ref get_link(Edge edge) const;
std::optional<Edge> last_edge() const;
std::optional<TriEdge> last_tri_edge() const;
/*const*/ GI_ref_weak last() const;
/*const*/ GI_ref_weak first() const;
/*const*/ GI_ref_weak operator[](int idx) const;
size_t size() const;
bool contains(/*const*/ GI_ref_weak gif) const;
void iterate_edges(std::function<bool(Edge &)> visitor) const;
const std::vector</*const*/ GI_ref_weak> &get_path() const;
std::vector</*const*/ GI_ref_weak> get_path_mut() const;
size_t index(/*const*/ GI_ref_weak gif) const;

bool operator==(const Path &other) const;
bool starts_with(const Path &other) const;

std::string str() const;
};
Expand All @@ -237,7 +242,7 @@ class Graph {
static Graph_ref merge_graphs(Graph_ref g1, Graph_ref g2);

std::unordered_set<GI_ref_weak> get_gif_edges(GI_ref_weak from);
std::unordered_map<GI_ref_weak, Link_ref> &get_edges(GI_ref_weak from);
Map<GI_ref_weak, Link_ref> &get_edges(GI_ref_weak from);

Graph();
~Graph();
Expand Down
54 changes: 51 additions & 3 deletions src/faebryk/core/cpp/include/pathfinder/bfs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ struct PathStackElement {
Node::Type parent_type;
Node::Type child_type;
/*const*/ GI_parent_ref_weak parent_gif;
GI_parent_ref_weak child_gif;
std::string name;
bool up;

Expand All @@ -37,21 +38,68 @@ using UnresolvedStack = std::vector<UnresolvedStackElement>;
struct PathData {
UnresolvedStack unresolved_stack;
PathStack split_stack;
bool not_complete = false;
};

class BFSPath : public Path {
namespace std {
template <> struct hash<Path> {
size_t operator()(const Path &p) const noexcept {
const GI_refs_weak &path = p.get_path();
size_t hash = 0;
for (auto &gif : path) {
hash = hash * 31 + std::hash<GI_ref_weak>{}(gif);
}
return hash;
}
};
} // namespace std

class BFSPath : public Path, public std::enable_shared_from_this<BFSPath> {
std::shared_ptr<PathData> path_data;

public:
/**
* @brief Confidence that this path might become 'valid' path
*
* 0 < confidence <= 1
*
* confidence < 1 := weak path
*/
double confidence = 1.0;
/**
* @brief Removes the path from the search
*
*/
bool filtered = false;
/**
* @brief Hibernates the path
*
* Hibernated BFS paths are not visited as long as they are hibernated.
*/
bool hibernated = false;
/**
* @brief Stops the BFS search
*
*/
bool stop = false;

/**
* @brief Notifies BFS that it woke up other paths
*
*/
bool wake_signal = false;

/**
* @brief Notifies BFS that the path has become strong after being weak
*
*/
bool strong_signal = false;

BFSPath(/*const*/ GI_ref_weak path_head);
BFSPath(const BFSPath &other);
BFSPath(const BFSPath &other, /*const*/ GI_ref_weak new_head);
BFSPath(BFSPath &&other);
BFSPath operator+(/*const*/ GI_ref_weak gif);
BFSPath(BFSPath &&other) = delete;
std::shared_ptr<BFSPath> operator+(/*const*/ GI_ref_weak gif);

PathData &get_path_data_mut();
PathData &get_path_data() /*const*/;
Expand Down
47 changes: 45 additions & 2 deletions src/faebryk/core/cpp/include/pathfinder/pathfinder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,64 @@ struct Filter {
bool exec(PathFinder *pf, BFSPath &p);
};

struct SplitState {

/**
* @brief Path that led to this split
*
*/
Path split_prefix;

/**
* @brief Branch complete
*
* All children have complete suffix path from here on
*/
bool complete = false;

bool waiting = false;

/**
* @brief All paths that are from this split on complete further (& fully valid)
*
*/
Map<GI_ref_weak, std::vector<std::shared_ptr<BFSPath>>> suffix_complete_paths;

/**
* @brief All paths that are hibernated per child
*
*/
Map<GI_ref_weak, std::vector<std::shared_ptr<BFSPath>>> wait_paths;

SplitState(const BFSPath &path);

/**
* @brief Parent gif of this split
*
* (always split_prefix.last())
*/
GI_ref_weak split_point() const;
};

class PathFinder {
std::vector<BFSPath> multi_paths;
// TODO I think we should use PathStack (slightly modified) instead of Path
// since non-hierarchical links have no influence on the split
Map<GI_ref_weak, Map<Path, SplitState>> split;
size_t path_cnt = 0;

bool _count(BFSPath &p);
bool _filter_path_by_node_type(BFSPath &p);
bool _filter_path_gif_type(BFSPath &p);
bool _filter_path_by_dead_end_split(BFSPath &p);
bool _build_path_stack(BFSPath &p);
bool _build_path_stack_and_handle_splits(BFSPath &p);
bool _filter_path_by_end_in_self_gif(BFSPath &p);
bool _filter_path_same_end_type(BFSPath &p);
bool _filter_path_by_stack(BFSPath &p);
bool _filter_shallow(BFSPath &p);
bool _filter_conditional_link(BFSPath &p);
bool _handle_valid_split_branch(BFSPath &p);
std::vector<BFSPath> _filter_paths_by_split_join(std::vector<BFSPath> &paths);
bool _filter_incomplete(BFSPath &p);

public:
PathFinder();
Expand Down
12 changes: 12 additions & 0 deletions src/faebryk/core/cpp/include/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
#pragma once

#include <cxxabi.h>
#include <functional>
#include <memory>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>

#if GLOBAL_PRINTF_DEBUG
#else
Expand Down Expand Up @@ -53,4 +56,13 @@ inline std::string formatted_ptr(void *ptr) {
// return ss.str();
//}

template <typename T, typename U>
inline std::unordered_map<U, std::vector<T>> groupby(const std::vector<T> &vec,
std::function<U(T)> f) {
std::unordered_map<U, std::vector<T>> out;
for (auto &t : vec) {
out[f(t)].push_back(t);
}
return out;
}
} // namespace util
2 changes: 1 addition & 1 deletion src/faebryk/core/cpp/src/graph/graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ std::unordered_set<GI_ref_weak> Graph::get_gif_edges(GI_ref_weak from) {
return this->e_cache_simple[from];
}

std::unordered_map<GI_ref_weak, Link_ref> &Graph::get_edges(GI_ref_weak from) {
Map<GI_ref_weak, Link_ref> &Graph::get_edges(GI_ref_weak from) {
return this->e_cache[from];
}

Expand Down
2 changes: 1 addition & 1 deletion src/faebryk/core/cpp/src/graph/graphinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Set<GI_ref_weak> GraphInterface::get_gif_edges() {
return this->G->get_gif_edges(this);
}

std::unordered_map<GI_ref_weak, Link_ref> &GraphInterface::get_edges() {
Map<GI_ref_weak, Link_ref> &GraphInterface::get_edges() {
return this->G->get_edges(this);
}

Expand Down
15 changes: 15 additions & 0 deletions src/faebryk/core/cpp/src/graph/links.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,13 @@ LinkDirectConditional::LinkDirectConditional(FilterF filter,
: LinkDirect()
, filter(filter)
, needs_only_first_in_path(needs_only_first_in_path) {

// TODO 1 actually check implied is on
// TODO 2 implement this
// not easy, needs some changes in how split paths are handled
if (!needs_only_first_in_path) {
throw std::runtime_error("No support for path conditions with implied links on");
}
}

LinkDirectConditional::LinkDirectConditional(FilterF filter,
Expand All @@ -216,6 +223,14 @@ LinkDirectConditional::LinkDirectConditional(FilterF filter,
: LinkDirect(from, to)
, filter(filter)
, needs_only_first_in_path(needs_only_first_in_path) {

// TODO 1 actually check implied is on
// TODO 2 implement this
// not easy, needs some changes in how split paths are handled
if (!needs_only_first_in_path) {
throw std::runtime_error("No support for path conditions with implied links on");
}

this->set_connections(from, to);
}

Expand Down
47 changes: 35 additions & 12 deletions src/faebryk/core/cpp/src/graph/path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,38 +22,46 @@ Path::Path(Path &&other)
: path(std::move(other.path)) {
}

Path::Path(std::vector<GI_ref_weak> path, GI_ref_weak head)
: path([&path, &head]() {
auto new_path = path;
new_path.push_back(head);
return new_path;
}()) {
}

Path::~Path() {
}

/*const*/ Link_weak_ref Path::get_link(Edge edge) /*const*/ {
/*const*/ Link_weak_ref Path::get_link(Edge edge) const {
auto out = edge.from->is_connected(edge.to);
assert(out);
return out->get();
}

std::optional<Edge> Path::last_edge() /*const*/ {
std::optional<Edge> Path::last_edge() const {
if (path.size() < 2) {
return {};
}
return Edge{path[path.size() - 2], path.back()};
}

std::optional<TriEdge> Path::last_tri_edge() /*const*/ {
std::optional<TriEdge> Path::last_tri_edge() const {
if (path.size() < 3) {
return {};
}
return std::make_tuple(path[path.size() - 3], path[path.size() - 2], path.back());
}

/*const*/ GI_ref_weak Path::last() /*const*/ {
/*const*/ GI_ref_weak Path::last() const {
return path.back();
}

/*const*/ GI_ref_weak Path::first() /*const*/ {
/*const*/ GI_ref_weak Path::first() const {
return path.front();
}

/*const*/ GI_ref_weak Path::operator[](int idx) /*const*/ {
/*const*/ GI_ref_weak Path::operator[](int idx) const {
if (idx < 0) {
idx = path.size() + idx;
}
Expand All @@ -63,15 +71,15 @@ std::optional<TriEdge> Path::last_tri_edge() /*const*/ {
return path[idx];
}

size_t Path::size() /*const*/ {
size_t Path::size() const {
return path.size();
}

bool Path::contains(/*const*/ GI_ref_weak gif) /*const*/ {
bool Path::contains(/*const*/ GI_ref_weak gif) const {
return std::find(path.begin(), path.end(), gif) != path.end();
}

void Path::iterate_edges(std::function<bool(Edge &)> visitor) /*const*/ {
void Path::iterate_edges(std::function<bool(Edge &)> visitor) const {
for (size_t i = 1; i < path.size(); i++) {
Edge edge{path[i - 1], path[i]};
bool res = visitor(edge);
Expand All @@ -81,11 +89,15 @@ void Path::iterate_edges(std::function<bool(Edge &)> visitor) /*const*/ {
}
}

/*const*/ std::vector</*const*/ GI_ref_weak> &Path::get_path() /*const*/ {
return path;
const std::vector</*const*/ GI_ref_weak> &Path::get_path() const {
return this->path;
}

size_t Path::index(/*const*/ GI_ref_weak gif) /*const*/ {
std::vector</*const*/ GI_ref_weak> Path::get_path_mut() const {
return std::vector<GI_ref_weak>(this->path);
}

size_t Path::index(/*const*/ GI_ref_weak gif) const {
return std::distance(path.begin(), std::find(path.begin(), path.end(), gif));
}

Expand All @@ -99,3 +111,14 @@ std::string Path::str() const {
ss << "]";
return ss.str();
}

bool Path::operator==(const Path &other) const {
return this->path == other.path;
}

bool Path::starts_with(const Path &other) const {
if (other.path.size() > this->path.size()) {
return false;
}
return std::equal(other.path.begin(), other.path.end(), this->path.begin());
}
Loading
Loading