Skip to content

Commit f7e5fc1

Browse files
build Path (#20)
* not good * construct path * build path * fix * fix * fix * fix# Please enter the commit message for your changes. Lines starting * fix version --------- Co-authored-by: TANG ZHIXIONG <[email protected]>
1 parent b0dcb06 commit f7e5fc1

File tree

5 files changed

+120
-6
lines changed

5 files changed

+120
-6
lines changed

.vscode/settings.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"files.associations": {
3+
"*.py": "python",
34
"variant": "cpp",
45
"bitset": "cpp",
56
"chrono": "cpp",
@@ -9,6 +10,8 @@
910
"set": "cpp",
1011
"unordered_map": "cpp",
1112
"thread": "cpp",
12-
"__locale": "cpp"
13+
"__locale": "cpp",
14+
"stdexcept": "cpp",
15+
"cmath": "cpp"
1316
}
1417
}

docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@
5858
# built documents.
5959
#
6060
# The short X.Y version.
61-
version = '0.1.6'
61+
version = '0.1.7'
6262
# The full version, including alpha/beta/rc tags.
63-
release = '0.1.6'
63+
release = '0.1.7'
6464

6565
# The language for content autogenerated by Sphinx. Refer to documentation
6666
# for a list of supported languages.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ build-backend = "scikit_build_core.build"
55

66
[project]
77
name = "networkx_graph"
8-
version = "0.1.6"
8+
version = "0.1.7"
99
url = "https://github.com/cubao/networkx-graph"
1010
description = "Some customized graph algorithms"
1111
readme = "README.md"

src/main.cpp

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,19 @@ struct DiGraph
462462
{
463463
return indexer_.get_id(node);
464464
}
465+
std::optional<std::tuple<int64_t, double>>
466+
__node_length(const std::string &node) const
467+
{
468+
auto nid = __node_id(node);
469+
if (!nid) {
470+
return {};
471+
}
472+
auto len = lengths_.find(*nid);
473+
if (len == lengths_.end()) {
474+
return {};
475+
}
476+
return std::make_tuple(*nid, len->second);
477+
}
465478
std::string __node_id(int64_t node) const { return indexer_.id(node); }
466479
std::vector<std::string> __node_ids(const std::vector<int64_t> &nodes) const
467480
{
@@ -1957,6 +1970,64 @@ PYBIND11_MODULE(_core, m)
19571970
;
19581971

19591972
py::class_<Path>(m, "Path", py::module_local(), py::dynamic_attr()) //
1973+
.def_static(
1974+
"Build",
1975+
[](const DiGraph &graph, const std::vector<std::string> &nodes,
1976+
std::optional<double> start_offset = {},
1977+
std::optional<double> end_offset = {},
1978+
std::optional<std::tuple<std::string, Binding>> binding = {})
1979+
-> Path {
1980+
if (nodes.empty()) {
1981+
throw std::invalid_argument("not any nodes");
1982+
}
1983+
std::vector<int64_t> nids;
1984+
std::vector<double> lengths;
1985+
const auto N = nodes.size();
1986+
nids.reserve(N);
1987+
lengths.reserve(N);
1988+
for (auto &node : nodes) {
1989+
auto nid_len = graph.__node_length(node);
1990+
if (!nid_len) {
1991+
throw std::invalid_argument(
1992+
fmt::format("missing node {}", node));
1993+
}
1994+
nids.push_back(std::get<0>(*nid_len));
1995+
lengths.push_back(std::get<1>(*nid_len));
1996+
}
1997+
double dist = 0.0;
1998+
for (size_t i = 1; i < N - 1; ++i) {
1999+
dist += lengths[i];
2000+
}
2001+
if (start_offset) {
2002+
start_offset = CLIP(0.0, *start_offset, lengths.front());
2003+
dist += lengths.front() - *start_offset;
2004+
}
2005+
if (end_offset) {
2006+
end_offset = CLIP(0.0, *end_offset, lengths.back());
2007+
dist += *end_offset;
2008+
}
2009+
auto p = Path(&graph, dist, nids, start_offset, end_offset);
2010+
auto round_scale = graph.round_scale();
2011+
if (round_scale) {
2012+
p.round(*round_scale);
2013+
}
2014+
if (binding) {
2015+
auto node = std::get<0>(*binding);
2016+
auto nid = graph.__node_id(node);
2017+
if (!nid) {
2018+
throw std::invalid_argument(
2019+
fmt::format("invalid binding node {}", node));
2020+
}
2021+
p.binding = std::make_tuple(*nid, std::get<1>(*binding));
2022+
}
2023+
return p;
2024+
},
2025+
"graph"_a, "nodes"_a, //
2026+
py::kw_only(), //
2027+
"start_offset"_a = std::nullopt, //
2028+
"end_offset"_a = std::nullopt, //
2029+
"binding"_a = std::nullopt)
2030+
19602031
.def_property_readonly(
19612032
"graph", [](const Path &self) { return self.graph; },
19622033
rvp::reference_internal)
@@ -1982,7 +2053,11 @@ PYBIND11_MODULE(_core, m)
19822053
})
19832054
.def_property_readonly(
19842055
"binding",
1985-
[](const Path &self) {
2056+
[](const Path &self)
2057+
-> std::optional<std::tuple<std::string, Binding>> {
2058+
if (!self.binding) {
2059+
return {};
2060+
}
19862061
return std::make_tuple( //
19872062
self.graph->__node_id(std::get<0>(*self.binding)),
19882063
std::get<1>(*self.binding));

tests/test_basic.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717

1818
def test_version():
19-
assert m.__version__ == "0.1.6"
19+
assert m.__version__ == "0.1.7"
2020

2121

2222
def test_add():
@@ -1352,3 +1352,39 @@ def test_ubodt():
13521352
assert len(G2.nodes) == 0
13531353
spath = ShortestPathWithUbodt(G2, rows)
13541354
assert spath.path("w1", "w4").nodes == ["w1", "w3", "w4"]
1355+
1356+
path = spath.path("w1", "w4")
1357+
path2 = Path.Build(G, path.nodes)
1358+
assert path.to_dict() == path2.to_dict()
1359+
1360+
path2 = Path.Build(G, path.nodes, start_offset=5.0, end_offset=17.0)
1361+
assert path2.dist == 32.0
1362+
assert path2.nodes == path.nodes
1363+
assert path2.start == ("w1", 5.0)
1364+
assert path2.end == ("w4", 17.0)
1365+
path2 = Path.Build(G, path.nodes, start_offset=5.12345, end_offset=27.0)
1366+
assert path2.dist == 34.877
1367+
assert path2.start[1] == 5.123
1368+
assert path2.end[1] == 20.0
1369+
1370+
path2 = Path.Build(
1371+
G,
1372+
path.nodes,
1373+
start_offset=5.12345,
1374+
end_offset=27.0,
1375+
binding=("w3", (5.0, 5.0, "something")),
1376+
)
1377+
assert path2.binding == ("w3", (5.0, 5.0, "something"))
1378+
1379+
with pytest.raises(ValueError) as e: # noqa: PT011
1380+
path2 = Path.Build(G, ["w1", "w3", "no_such_road"])
1381+
assert "missing node no_such_road" in repr(e)
1382+
with pytest.raises(ValueError) as e: # noqa: PT011
1383+
path2 = Path.Build(
1384+
G,
1385+
path.nodes,
1386+
start_offset=5.12345,
1387+
end_offset=27.0,
1388+
binding=("no_such_road", (5.0, 5.0, "something")),
1389+
)
1390+
assert "invalid binding node no_such_road" in repr(e)

0 commit comments

Comments
 (0)