Skip to content

Commit a3568bb

Browse files
Merge pull request #26 from andyquinterom/syms
Adds NodeVec and Symbols
2 parents c1cefdc + dd1b340 commit a3568bb

20 files changed

+402
-356
lines changed

.Rbuildignore

+3
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,6 @@
2929
^src/rust/\.cargo$
3030
^src/orbweaver\.so$
3131
^Makefile
32+
33+
^benchmarks/
34+
^assets/

DESCRIPTION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: orbweaver
22
Title: Fast and Efficient Graph Data Structures
3-
Version: 0.11.0
3+
Version: 0.12.0
44
Authors@R:
55
c(person(given = "ixpantia, SRL",
66
role = "cph",

NAMESPACE

+5
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
S3method("$",DirectedAcyclicGraph)
44
S3method("$",DirectedGraph)
55
S3method("$",DirectedGraphBuilder)
6+
S3method("$",NodeVec)
67
S3method("[[",DirectedAcyclicGraph)
78
S3method("[[",DirectedGraph)
89
S3method("[[",DirectedGraphBuilder)
10+
S3method("[[",NodeVec)
11+
S3method(as.character,NodeVec)
912
S3method(children,DirectedAcyclicGraph)
1013
S3method(children,DirectedGraph)
1114
S3method(find_all_paths,DirectedAcyclicGraph)
@@ -29,10 +32,12 @@ S3method(least_common_parents,DirectedGraph)
2932
S3method(length,DirectedAcyclicGraph)
3033
S3method(length,DirectedGraph)
3134
S3method(length,DirectedGraphBuilder)
35+
S3method(length,NodeVec)
3236
S3method(parents,DirectedAcyclicGraph)
3337
S3method(parents,DirectedGraph)
3438
S3method(print,DirectedAcyclicGraph)
3539
S3method(print,DirectedGraph)
40+
S3method(print,NodeVec)
3641
S3method(subset,DirectedAcyclicGraph)
3742
S3method(subset,DirectedGraph)
3843
export(add_edge)

R/extendr-wrappers.R

+14
Original file line numberDiff line numberDiff line change
@@ -122,5 +122,19 @@ DirectedGraphBuilder$build_acyclic <- function() .Call(wrap__DirectedGraphBuilde
122122
#' @export
123123
`[[.DirectedGraphBuilder` <- `$.DirectedGraphBuilder`
124124

125+
NodeVec <- new.env(parent = emptyenv())
126+
127+
NodeVec$print <- function() invisible(.Call(wrap__NodeVec__print, self))
128+
129+
NodeVec$as_character <- function() .Call(wrap__NodeVec__as_character, self)
130+
131+
NodeVec$len <- function() .Call(wrap__NodeVec__len, self)
132+
133+
#' @export
134+
`$.NodeVec` <- function (self, name) { func <- NodeVec[[name]]; environment(func) <- environment(); func }
135+
136+
#' @export
137+
`[[.NodeVec` <- `$.NodeVec`
138+
125139

126140
# nolint end

R/nodevec.R

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#' @export
2+
print.NodeVec <- function(x, ...) {
3+
x$print()
4+
}
5+
6+
#' @export
7+
as.character.NodeVec <- function(x, ...) {
8+
x$as_character()
9+
}
10+
11+
#' @export
12+
length.NodeVec <- function(x, ...) {
13+
x$len()
14+
}

README.md

+15-6
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,27 @@
88

99
## Overview
1010

11-
A fast R library for working with Nodes in a graph. This library
12-
modifies graphs in place, similar to how [data.table](https://github.com/Rdatatable/data.table)
13-
modifies data.frames in place. This allows for fast and memory efficient
14-
graph operations.
11+
A fast R library for working with Nodes in a graph.
1512

1613
## Features
1714

18-
- Nodes can store arbitrary data
15+
- Find shortest paths between nodes in a graph
1916
- Find the common parents between selected nodes
20-
- Modify graphs in place
2117
- Directed Graph
2218
- Directed Acyclic Graph
19+
- It is quite fast
20+
21+
## Why not igraph?
22+
23+
[igraph](https://igraph.org/) is an amazing network analysis package.
24+
igraph is much more mature and orbweaver focuses on extreme performance
25+
and low latency operations. If you need super high performance
26+
and do not require weighted graphs, orbweaver may be for you.
27+
28+
![igraph vs orbweaver benchmark](assets/benchmark.png)
29+
30+
> We may add weighted graph in the future but for not
31+
> it is not in the short-term road map.
2332
2433
## Installation
2534

assets/benchmark.png

131 KB
Loading

benchmarks/bench.R

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
library(igraph)
2+
library(orbweaver)
3+
library(microbenchmark)
4+
5+
# Download the dataset from the orbweaver-rs repo
6+
edges <- readr::read_tsv("https://raw.githubusercontent.com/ixpantia/orbweaver-rs/main/assets/medium.txt", col_names = c("parent", "child"))
7+
8+
# Function to convert dataframe to orbweaver graph
9+
df_to_orbweaver <- function(edges) {
10+
graph_builder() |>
11+
populate_edges(edges, parent, child) |>
12+
build_acyclic()
13+
}
14+
15+
# Function to convert dataframe to igraph graph
16+
df_to_igraph <- function(edges) {
17+
graph_from_data_frame(edges, directed = TRUE)
18+
}
19+
20+
find_paths_orbweaver <- function(graph, from, to) {
21+
orbweaver::find_all_paths(graph, from, to)
22+
}
23+
24+
find_paths_igraph <- function(graph, from, to) {
25+
igraph::all_shortest_paths(graph, from, to)
26+
}
27+
28+
find_path_orbweaver <- function(graph, from, to) {
29+
orbweaver::find_path(graph, from, to)
30+
}
31+
32+
find_path_igraph <- function(graph, from, to) {
33+
igraph::shortest_paths(graph, from, to)$vpath
34+
}
35+
36+
get_nodes_orbweaver <- function(graph) {
37+
orbweaver::nodes(graph)
38+
}
39+
40+
get_nodes_igraph <- function(graph) {
41+
igraph::V(graph)
42+
}
43+
44+
get_leaves_under_orbweaver <- function(graph, node) {
45+
orbweaver::get_leaves_under(graph, node)
46+
}
47+
48+
get_leaves_under_igraph <- function(graph, node) {
49+
descendants <- igraph::ego(graph, order = length(V(graph)), nodes = node, mode = "out")[[1]]
50+
descendants[igraph::degree(graph, v = descendants, mode = "out") == 0]
51+
}
52+
53+
get_roots_over_orbweaver <- function(graph, node) {
54+
orbweaver::get_roots_over(graph, node)
55+
}
56+
57+
get_roots_over_igraph <- function(graph, node) {
58+
ancestors <- igraph::ego(graph, order = length(V(graph)), nodes = node, mode = "in")[[1]]
59+
ancestors[igraph::degree(graph, v = ancestors, mode = "in") == 0]
60+
}
61+
62+
least_common_parents_orbweaver <- function(graph, nodes) {
63+
orbweaver::least_common_parents(graph, nodes)
64+
}
65+
66+
least_common_parents_igraph <- function(graph, nodes) {
67+
subgraph <- igraph::induced_subgraph(graph, nodes)
68+
igraph::V(subgraph)[igraph::degree(subgraph, mode = "in") == 0]
69+
}
70+
71+
subset_orbweaver <- function(graph, node) {
72+
subset(graph, node)
73+
}
74+
75+
subset_igraph <- function(graph, node) {
76+
reachable_nodes <- igraph::ego(graph, order = length(igraph::V(graph)), nodes = node, mode = "out")[[1]]
77+
igraph::induced_subgraph(graph, reachable_nodes)
78+
}
79+
80+
# Create orbweaver and igraph graphs
81+
g_orb <- df_to_orbweaver(edges)
82+
g_ig <- df_to_igraph(edges)
83+
84+
# Benchmark the functions
85+
microbenchmark(
86+
find_all_paths_orbweaver = find_paths_orbweaver(g_orb, "1781f676dedf5767f3243db0a9738b35", "eb85851afd251bd7c7eaf725d0d19360"),
87+
find_all_paths_igraph = find_paths_igraph(g_ig, "1781f676dedf5767f3243db0a9738b35", "eb85851afd251bd7c7eaf725d0d19360"),
88+
find_path_orbweaver = find_path_orbweaver(g_orb, "1781f676dedf5767f3243db0a9738b35", "eb85851afd251bd7c7eaf725d0d19360"),
89+
find_path_igraph = find_path_igraph(g_ig, "1781f676dedf5767f3243db0a9738b35", "eb85851afd251bd7c7eaf725d0d19360"),
90+
get_leaves_under_orbweaver = get_leaves_under_orbweaver(g_orb, "1781f676dedf5767f3243db0a9738b35"),
91+
get_leaves_under_igraph = get_leaves_under_igraph(g_ig, "1781f676dedf5767f3243db0a9738b35"),
92+
get_roots_over_orbweaver = get_roots_over_orbweaver(g_orb, "eb85851afd251bd7c7eaf725d0d19360"),
93+
get_roots_over_igraph = get_roots_over_igraph(g_ig, "eb85851afd251bd7c7eaf725d0d19360"),
94+
least_common_parents_orbweaver = least_common_parents_orbweaver(g_orb, edges$parent[1:100]),
95+
least_common_parents_igraph = least_common_parents_igraph(g_ig, edges$parent[1:100]),
96+
subset_orbweaver = subset_orbweaver(g_orb, "1781f676dedf5767f3243db0a9738b35"),
97+
subset_igraph = subset_igraph(g_ig, "1781f676dedf5767f3243db0a9738b35"),
98+
times = 100
99+
)

src/rust/Cargo.lock

+10-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/rust/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ name = 'orbweaver'
1010
[dependencies]
1111
# extendr-api = { version = "0.6", features = ["serde"] }
1212
extendr-api = { git = "https://github.com/extendr/extendr.git", rev = "cb85a21a90c3fcb538a40fcea03058454edb3dac" }
13-
orbweaver = { version = "0.11.0" }
13+
orbweaver = { version = "0.12.0" }
14+
#orbweaver = { git = "https://github.com/ixpantia/orbweaver-rs.git", branch = "main" }
1415

1516
# This will help us filter the platforms
1617
# we support to make the final bundle size

0 commit comments

Comments
 (0)