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

Commit

Permalink
Fix path filtering & LinkConditionals
Browse files Browse the repository at this point in the history
  • Loading branch information
iopapamanoglou committed Nov 8, 2024
1 parent 9dc0974 commit 782c780
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 35 deletions.
4 changes: 1 addition & 3 deletions src/faebryk/core/cpp/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,7 @@ class LinkDirect(Link):
class LinkDirectConditional(LinkDirect):
def __init__(
self,
filter: Callable[
[GraphInterface, GraphInterface], LinkDirectConditionalFilterResult
],
filter: Callable[[Sequence[GraphInterface]], LinkDirectConditionalFilterResult],
needs_only_first_in_path: bool = False,
) -> None: ...

Expand Down
4 changes: 2 additions & 2 deletions src/faebryk/core/cpp/include/graph/links.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class LinkDirectConditional : public LinkDirect {
FILTER_FAIL_UNRECOVERABLE
};

using FilterF = std::function<FilterResult(GI_ref_weak from, GI_ref_weak to)>;
using FilterF = std::function<FilterResult(Path path)>;

struct LinkFilteredException : public std::runtime_error {
LinkFilteredException(std::string msg)
Expand All @@ -85,7 +85,7 @@ class LinkDirectConditional : public LinkDirect {
LinkDirectConditional(FilterF filter, bool needs_only_first_in_path,
GI_ref_weak from, GI_ref_weak to);
void set_connections(GI_ref_weak from, GI_ref_weak to) override;
FilterResult run_filter(GI_ref_weak from, GI_ref_weak to);
FilterResult run_filter(Path path);

bool needs_to_check_only_first_in_path();
};
Expand Down
6 changes: 5 additions & 1 deletion src/faebryk/core/cpp/include/pathfinder/bfs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ using Link_weak_ref = Link *;
struct Edge {
/*const*/ GI_ref_weak from;
/*const*/ GI_ref_weak to;

std::string str() const;
};

using TriEdge = std::tuple</*const*/ GI_ref_weak, /*const*/ GI_ref_weak,
Expand Down Expand Up @@ -75,6 +77,8 @@ class BFSPath {
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*/;

std::string str() const;
};

void bfs_visit(/*const*/ GI_ref_weak root, std::function<void(BFSPath)> visitor);
void bfs_visit(/*const*/ GI_ref_weak root, std::function<void(BFSPath &)> visitor);
17 changes: 8 additions & 9 deletions src/faebryk/core/cpp/src/graph/links.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,18 @@ LinkDirectConditional::LinkDirectConditional(FilterF filter,
}

void LinkDirectConditional::set_connections(GI_ref_weak from, GI_ref_weak to) {
if (this->filter(from, to) != FilterResult::FILTER_PASS) {
if (this->filter({from, to}) != FilterResult::FILTER_PASS) {
throw LinkFilteredException("LinkDirectConditional filtered");
}
LinkDirect::set_connections(from, to);
}

LinkDirectConditional::FilterResult LinkDirectConditional::run_filter(GI_ref_weak from,
GI_ref_weak to) {
return this->filter(from, to);
LinkDirectConditional::FilterResult LinkDirectConditional::run_filter(Path path) {
return this->filter(path);
}

bool LinkDirectConditional::needs_to_check_only_first_in_path() {
return this->needs_only_first_in_path;
}

// LinkDirectDerived -------------------------------------------------------------------
Expand All @@ -177,11 +180,7 @@ LinkDirectDerived::LinkDirectDerived(Path path, GI_ref_weak from, GI_ref_weak to

LinkDirectConditional::FilterF LinkDirectDerived::make_filter_from_path(Path path) {
// TODO
return [path](GI_ref_weak, GI_ref_weak) {
return [path](Path check_path) {
return LinkDirectConditional::FilterResult::FILTER_PASS;
};
}

bool LinkDirectConditional::needs_to_check_only_first_in_path() {
return this->needs_only_first_in_path;
}
23 changes: 20 additions & 3 deletions src/faebryk/core/cpp/src/pathfinder/bfs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
#include <deque>
#include <sstream>

std::string Edge::str() const {
std::stringstream ss;
ss << from->get_full_name(false) << "->" << to->get_full_name(false);
return ss.str();
}

std::string PathStackElement::str() /*const*/ {
std::stringstream ss;
if (up) {
Expand Down Expand Up @@ -53,6 +59,7 @@ BFSPath::BFSPath(const BFSPath &other, /*const*/ GI_ref_weak new_head)
, filtered(other.filtered)
, stop(other.stop) {
path.push_back(new_head);
assert(!other.filtered);
}

BFSPath::BFSPath(BFSPath &&other)
Expand Down Expand Up @@ -141,7 +148,7 @@ size_t BFSPath::index(/*const*/ GI_ref_weak gif) /*const*/ {
return std::distance(path.begin(), std::find(path.begin(), path.end(), gif));
}

void bfs_visit(/*const*/ GI_ref_weak root, std::function<void(BFSPath)> visitor) {
void bfs_visit(/*const*/ GI_ref_weak root, std::function<void(BFSPath &)> visitor) {
PerfCounterAccumulating pc, pc_search, pc_set_insert, pc_setup, pc_deque_insert,
pc_edges, pc_check_visited, pc_filter, pc_new_path;
pc_set_insert.pause();
Expand Down Expand Up @@ -187,8 +194,7 @@ void bfs_visit(/*const*/ GI_ref_weak root, std::function<void(BFSPath)> visitor)
};

pc_setup.pause();
auto root_path = BFSPath(root);
handle_path(root_path);
handle_path(std::move(BFSPath(root)));

pc_search.resume();
while (!open_path_queue.empty()) {
Expand Down Expand Up @@ -232,3 +238,14 @@ void bfs_visit(/*const*/ GI_ref_weak root, std::function<void(BFSPath)> visitor)
printf(" TIME: %3.2lf ms BFS Non-filter total\n", pc.ms());
printf(" TIME: %3.2lf ms BFS Filter total\n", pc_filter.ms());
}

std::string BFSPath::str() const {
std::stringstream ss;
ss << "BFSPath(" << path.size() << ")";
ss << "[";
for (auto &gif : path) {
ss << "\n " << gif->get_full_name(false);
}
ss << "]";
return ss.str();
}
21 changes: 12 additions & 9 deletions src/faebryk/core/cpp/src/pathfinder/pathfinder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ PathFinder::find_paths(Node_ref src, std::vector<Node_ref> dst) {

PerfCounter pc_bfs;

bfs_visit(src->get_self_gif().get(), [&](BFSPath p) {
bfs_visit(src->get_self_gif().get(), [&](BFSPath &p) {
bool res = total_counter.exec(this, &PathFinder::run_filters, p);
if (!res) {
return;
Expand All @@ -138,7 +138,7 @@ PathFinder::find_paths(Node_ref src, std::vector<Node_ref> dst) {
p.stop = true;
}
}
paths.push_back(std::move(p));
paths.push_back(std::move(BFSPath(p)));
});

printf("TIME: %3.2lf ms BFS\n", pc_bfs.ms());
Expand Down Expand Up @@ -307,20 +307,23 @@ bool PathFinder::_filter_conditional_link(BFSPath &p) {
return true;
}
/*const*/ auto linkobj = p.get_link(*edge);
// printf("Path: %s\n", p.str().c_str());
// printf("Edge: %s\n", edge->str().c_str());

// TODO theoretically have to check all links, not just the last
auto link_conditional = dynamic_cast<LinkDirectConditional *>(linkobj);
if (!link_conditional) {
return true;
}

// if (link_conditional->needs_to_check_only_first_in_path()) {
// if (p.size() > 1) {
// return true;
// }
// }

// TODO check recoverable?
return link_conditional->run_filter(edge->from, edge->to) ==

if (link_conditional->needs_to_check_only_first_in_path()) {
return link_conditional->run_filter(GI_refs_weak{p.first()}) ==
LinkDirectConditional::FilterResult::FILTER_PASS;
}

return link_conditional->run_filter(p.get_path()) ==
LinkDirectConditional::FilterResult::FILTER_PASS;
}

Expand Down
12 changes: 9 additions & 3 deletions src/faebryk/core/moduleinterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,18 @@ def has_no_parent_with_type(self, node: CNode):
parents = (p[0] for p in node.get_hierarchy()[:-1])
return not any(isinstance(p, self.test_type) for p in parents)

def check_path(self, path: Path) -> LinkDirectConditionalFilterResult:
out = (
LinkDirectConditionalFilterResult.FILTER_PASS
if self.has_no_parent_with_type(path[0].node)
else LinkDirectConditionalFilterResult.FILTER_FAIL_UNRECOVERABLE
)
return out

def __init__(self, test_type: type["ModuleInterface"]):
self.test_type = test_type
super().__init__(
lambda src, dst: LinkDirectConditionalFilterResult.FILTER_PASS
if self.has_no_parent_with_type(src.node)
else LinkDirectConditionalFilterResult.FILTER_FAIL_UNRECOVERABLE,
self.check_path,
needs_only_first_in_path=True,
)

Expand Down
4 changes: 2 additions & 2 deletions src/faebryk/core/pathfinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from faebryk.core.node import Node
from faebryk.libs.util import ConfigFlag

type Path = list[GraphInterface]
type Path = Sequence[GraphInterface]


# Also in C++
Expand All @@ -24,7 +24,7 @@
set_indiv_measure(bool(INDIV_MEASURE))


def find_paths(src: Node, dst: Sequence[Node]) -> list[Path]:
def find_paths(src: Node, dst: Sequence[Node]) -> Sequence[Path]:
paths, counters = find_paths_cpp(src, dst)

print(Counters(counters))
Expand Down
7 changes: 4 additions & 3 deletions src/faebryk/library/SignalElectrical.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ def test(self, node: CNode):

def __init__(self) -> None:
super().__init__(
lambda src, dst: LinkDirectConditionalFilterResult.FILTER_PASS
if self.test(dst.node)
else LinkDirectConditionalFilterResult.FILTER_FAIL_UNRECOVERABLE
lambda path: LinkDirectConditionalFilterResult.FILTER_PASS
if all(self.test(dst.node) for dst in path)
else LinkDirectConditionalFilterResult.FILTER_FAIL_UNRECOVERABLE,
needs_only_first_in_path=False,
)

# ----------------------------------------
Expand Down

0 comments on commit 782c780

Please sign in to comment.