spatial-graph 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spatial_graph/__init__.py +15 -0
- spatial_graph/dtypes.py +130 -0
- spatial_graph/graph/__init__.py +3 -0
- spatial_graph/graph/graph.py +226 -0
- spatial_graph/graph/src/LICENSE.txt +7 -0
- spatial_graph/graph/src/graph_lite.h +1357 -0
- spatial_graph/graph/wrapper_template.pyx +654 -0
- spatial_graph/rtree/__init__.py +5 -0
- spatial_graph/rtree/line_rtree.py +156 -0
- spatial_graph/rtree/point_rtree.py +6 -0
- spatial_graph/rtree/rtree.py +125 -0
- spatial_graph/rtree/src/ARCHITECTURE.md +162 -0
- spatial_graph/rtree/src/LICENSE +20 -0
- spatial_graph/rtree/src/config.h +13 -0
- spatial_graph/rtree/src/rtree.c +1021 -0
- spatial_graph/rtree/src/rtree.h +97 -0
- spatial_graph/rtree/wrapper_template.pyx +356 -0
- spatial_graph/spatial_graph.py +95 -0
- spatial_graph-0.0.1.dist-info/METADATA +130 -0
- spatial_graph-0.0.1.dist-info/RECORD +22 -0
- spatial_graph-0.0.1.dist-info/WHEEL +4 -0
- spatial_graph-0.0.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,654 @@
|
|
|
1
|
+
from cython cimport view
|
|
2
|
+
from cython.operator cimport dereference as deref, preincrement as inc
|
|
3
|
+
from libc.stdint cimport *
|
|
4
|
+
from libcpp.utility cimport pair
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
cdef extern from *:
|
|
9
|
+
"""
|
|
10
|
+
#include "src/graph_lite.h"
|
|
11
|
+
|
|
12
|
+
// partial template instantiation of graph_lite::Graph as
|
|
13
|
+
// GraphTmpl
|
|
14
|
+
template<typename NodeType, typename NodeData, typename EdgeData>
|
|
15
|
+
class GraphTmpl : public graph_lite::Graph<
|
|
16
|
+
NodeType,
|
|
17
|
+
NodeData,
|
|
18
|
+
EdgeData,
|
|
19
|
+
%if $directed
|
|
20
|
+
graph_lite::EdgeDirection::DIRECTED,
|
|
21
|
+
%else
|
|
22
|
+
graph_lite::EdgeDirection::UNDIRECTED,
|
|
23
|
+
%end if
|
|
24
|
+
graph_lite::MultiEdge::DISALLOWED,
|
|
25
|
+
graph_lite::SelfLoop::DISALLOWED,
|
|
26
|
+
graph_lite::Map::UNORDERED_MAP,
|
|
27
|
+
graph_lite::Container::VEC
|
|
28
|
+
> {};
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
cdef cppclass GraphTmpl[NodeType, NodeData, EdgeData]:
|
|
32
|
+
|
|
33
|
+
cppclass Iterator:
|
|
34
|
+
NodeType operator*()
|
|
35
|
+
Iterator operator++()
|
|
36
|
+
bint operator==(Iterator)
|
|
37
|
+
bint operator!=(Iterator)
|
|
38
|
+
|
|
39
|
+
cppclass EdgePropIterWrap[ED]:
|
|
40
|
+
ED& prop()
|
|
41
|
+
|
|
42
|
+
cppclass NeighborsIterator:
|
|
43
|
+
pair[NodeType, EdgePropIterWrap[EdgeData]] operator*()
|
|
44
|
+
NeighborsIterator operator++()
|
|
45
|
+
bint operator==(NeighborsIterator)
|
|
46
|
+
bint operator!=(NeighborsIterator)
|
|
47
|
+
|
|
48
|
+
int add_node_with_prop(NodeType& node, NodeData& prop)
|
|
49
|
+
|
|
50
|
+
int add_edge_with_prop(NodeType& source, NodeType& target, EdgeData& prop)
|
|
51
|
+
|
|
52
|
+
NodeData& node_prop[T](T& node) except +
|
|
53
|
+
|
|
54
|
+
EdgeData& edge_prop[T](T& u, T& v) except +
|
|
55
|
+
|
|
56
|
+
%if $directed
|
|
57
|
+
pair[NeighborsIterator, NeighborsIterator] out_neighbors(Iterator& node)
|
|
58
|
+
pair[NeighborsIterator, NeighborsIterator] out_neighbors(NodeType& node)
|
|
59
|
+
pair[NeighborsIterator, NeighborsIterator] in_neighbors(Iterator& node)
|
|
60
|
+
pair[NeighborsIterator, NeighborsIterator] in_neighbors(NodeType& node)
|
|
61
|
+
%else
|
|
62
|
+
pair[NeighborsIterator, NeighborsIterator] neighbors(Iterator& node)
|
|
63
|
+
pair[NeighborsIterator, NeighborsIterator] neighbors(NodeType& node)
|
|
64
|
+
%end if
|
|
65
|
+
|
|
66
|
+
int remove_nodes(NodeType& node)
|
|
67
|
+
|
|
68
|
+
%if $directed
|
|
69
|
+
int count_in_neighbors(NodeType& node)
|
|
70
|
+
int count_out_neighbors(NodeType& node)
|
|
71
|
+
%else
|
|
72
|
+
int count_neighbors(NodeType& node)
|
|
73
|
+
%end if
|
|
74
|
+
|
|
75
|
+
size_t size() const
|
|
76
|
+
|
|
77
|
+
size_t num_edges() const
|
|
78
|
+
|
|
79
|
+
Iterator begin()
|
|
80
|
+
|
|
81
|
+
Iterator end()
|
|
82
|
+
|
|
83
|
+
ctypedef $node_dtype.to_pyxtype() NodeType
|
|
84
|
+
|
|
85
|
+
%for class_name, dtypes in [
|
|
86
|
+
("NodeData", $node_attr_dtypes),
|
|
87
|
+
("EdgeData", $edge_attr_dtypes)
|
|
88
|
+
]
|
|
89
|
+
cdef extern from *:
|
|
90
|
+
"""
|
|
91
|
+
class $class_name {
|
|
92
|
+
public:
|
|
93
|
+
${class_name}() {};
|
|
94
|
+
%if $dtypes
|
|
95
|
+
${class_name}(
|
|
96
|
+
%set $sep=""
|
|
97
|
+
%for name, dtype in $dtypes.items()
|
|
98
|
+
$sep$dtype.to_c_decl("_" + $name)
|
|
99
|
+
%set $sep=", "
|
|
100
|
+
%end for
|
|
101
|
+
) :
|
|
102
|
+
%set $sep=""
|
|
103
|
+
%for name, dtype in $dtypes.items()
|
|
104
|
+
$sep
|
|
105
|
+
%if $dtype.is_array
|
|
106
|
+
${name}{
|
|
107
|
+
%set $isep=""
|
|
108
|
+
%for i in range($dtype.size)
|
|
109
|
+
${isep}_${name}[$i]
|
|
110
|
+
%set $isep=", "
|
|
111
|
+
%end for
|
|
112
|
+
}
|
|
113
|
+
%else
|
|
114
|
+
${name}(_$name)%slurp
|
|
115
|
+
%end if
|
|
116
|
+
%set $sep=", "
|
|
117
|
+
%end for
|
|
118
|
+
{};
|
|
119
|
+
%end if
|
|
120
|
+
|
|
121
|
+
%for name, dtype in $dtypes.items()
|
|
122
|
+
$dtype.to_c_decl($name);
|
|
123
|
+
%end for
|
|
124
|
+
};
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
cdef cppclass $class_name:
|
|
128
|
+
|
|
129
|
+
${class_name}(
|
|
130
|
+
%set $sep=""
|
|
131
|
+
%for name, dtype in $dtypes.items()
|
|
132
|
+
$sep$dtype.to_c_decl("_" + $name)
|
|
133
|
+
%set $sep=", "
|
|
134
|
+
%end for
|
|
135
|
+
) except +
|
|
136
|
+
|
|
137
|
+
%for name, dtype in $dtypes.items()
|
|
138
|
+
$dtype.to_pyxtype() $name
|
|
139
|
+
%end for
|
|
140
|
+
|
|
141
|
+
cdef class ${class_name}View:
|
|
142
|
+
|
|
143
|
+
cdef $class_name* _ptr
|
|
144
|
+
|
|
145
|
+
cdef set_ptr(self, $class_name* ptr):
|
|
146
|
+
self._ptr = ptr
|
|
147
|
+
|
|
148
|
+
%for name, dtype in $dtypes.items():
|
|
149
|
+
@property
|
|
150
|
+
def ${name}(self):
|
|
151
|
+
%if $dtype.is_array
|
|
152
|
+
return <${dtype.base_c_type}[:${dtype.size}]>(self._ptr.${name})
|
|
153
|
+
%else
|
|
154
|
+
return self._ptr.$name
|
|
155
|
+
%end if
|
|
156
|
+
|
|
157
|
+
@${name}.setter
|
|
158
|
+
def ${name}(self, value):
|
|
159
|
+
self._ptr.$name = value
|
|
160
|
+
|
|
161
|
+
%end for
|
|
162
|
+
|
|
163
|
+
%end for
|
|
164
|
+
|
|
165
|
+
ctypedef GraphTmpl[NodeType, NodeData, EdgeData] GraphType
|
|
166
|
+
ctypedef GraphType.Iterator NodeIterator
|
|
167
|
+
ctypedef GraphType.NeighborsIterator NeighborsIterator
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
cdef class Graph:
|
|
171
|
+
|
|
172
|
+
cdef GraphType _graph
|
|
173
|
+
|
|
174
|
+
%for kind, Kind, dtypes in [
|
|
175
|
+
("node", "Node", $node_attr_dtypes),
|
|
176
|
+
("edge", "Edge", $edge_attr_dtypes)
|
|
177
|
+
]
|
|
178
|
+
def add_${kind}(
|
|
179
|
+
self,
|
|
180
|
+
%if kind == "node"
|
|
181
|
+
NodeType node,
|
|
182
|
+
%else
|
|
183
|
+
NodeType[:] edge,
|
|
184
|
+
%end if
|
|
185
|
+
%set sep=""
|
|
186
|
+
%for name, dtype in $dtypes.items()
|
|
187
|
+
$sep${dtype.to_pyxtype(use_memory_view=True)} $name
|
|
188
|
+
%set $sep=", "
|
|
189
|
+
%end for
|
|
190
|
+
):
|
|
191
|
+
|
|
192
|
+
%for name, dtype in $dtypes.items()
|
|
193
|
+
%if dtype.is_array
|
|
194
|
+
cdef ${dtype.to_pyxtype()} _p_${name} = &${name}[0]
|
|
195
|
+
%end if
|
|
196
|
+
%end for
|
|
197
|
+
|
|
198
|
+
return self._graph.add_${kind}_with_prop(
|
|
199
|
+
%if kind == "node"
|
|
200
|
+
node,
|
|
201
|
+
%else
|
|
202
|
+
edge[0], edge[1],
|
|
203
|
+
%end if
|
|
204
|
+
${Kind}Data(
|
|
205
|
+
%set sep=""
|
|
206
|
+
%for name, dtype in $dtypes.items()
|
|
207
|
+
%if $dtype.is_array
|
|
208
|
+
${sep}_p_${name}%slurp
|
|
209
|
+
%else
|
|
210
|
+
${sep}${name}%slurp
|
|
211
|
+
%end if
|
|
212
|
+
%set sep=", "
|
|
213
|
+
%end for
|
|
214
|
+
|
|
215
|
+
)
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
def add_${kind}s(
|
|
219
|
+
self,
|
|
220
|
+
%if kind == "node"
|
|
221
|
+
NodeType[::1] nodes,
|
|
222
|
+
%else
|
|
223
|
+
NodeType[:, :] edges,
|
|
224
|
+
%end if
|
|
225
|
+
%set sep=""
|
|
226
|
+
%for name, dtype in $dtypes.items()
|
|
227
|
+
$sep${dtype.to_pyxtype(use_memory_view=True, add_dim=True)} $name
|
|
228
|
+
%set $sep=", "
|
|
229
|
+
%end for
|
|
230
|
+
):
|
|
231
|
+
|
|
232
|
+
%for name, dtype in $dtypes.items()
|
|
233
|
+
%if dtype.is_array
|
|
234
|
+
cdef ${dtype.to_pyxtype()} _p_${name}
|
|
235
|
+
%end if
|
|
236
|
+
%end for
|
|
237
|
+
|
|
238
|
+
cdef size_t num_added = 0
|
|
239
|
+
for i in range(len(${kind}s)):
|
|
240
|
+
%for name, dtype in $dtypes.items()
|
|
241
|
+
%if $dtype.is_array
|
|
242
|
+
_p_${name} = &${name}[i, 0]
|
|
243
|
+
%end if
|
|
244
|
+
%end for
|
|
245
|
+
num_added += self._graph.add_${kind}_with_prop(
|
|
246
|
+
%if kind == "node"
|
|
247
|
+
nodes[i],
|
|
248
|
+
%else
|
|
249
|
+
edges[i, 0], edges[i, 1],
|
|
250
|
+
%end if
|
|
251
|
+
${Kind}Data(
|
|
252
|
+
%set sep=""
|
|
253
|
+
%for name, dtype in $dtypes.items()
|
|
254
|
+
%if $dtype.is_array
|
|
255
|
+
${sep}_p_${name}%slurp
|
|
256
|
+
%else
|
|
257
|
+
${sep}${name}[i]%slurp
|
|
258
|
+
%end if
|
|
259
|
+
%set $sep=", "
|
|
260
|
+
%end for
|
|
261
|
+
|
|
262
|
+
)
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
return num_added
|
|
266
|
+
|
|
267
|
+
%end for
|
|
268
|
+
|
|
269
|
+
def nodes(self):
|
|
270
|
+
"""Get all node IDs."""
|
|
271
|
+
|
|
272
|
+
cdef NodeIterator it = self._graph.begin()
|
|
273
|
+
cdef NodeIterator end = self._graph.end()
|
|
274
|
+
node_ids = np.empty((self._graph.size(),), dtype="$node_dtype.base")
|
|
275
|
+
|
|
276
|
+
for i in range(self._graph.size()):
|
|
277
|
+
node_ids[i] = deref(it)
|
|
278
|
+
inc(it)
|
|
279
|
+
|
|
280
|
+
# graph_lite iterates over nodes in reverse order of addition, fix that
|
|
281
|
+
# here
|
|
282
|
+
return node_ids[::-1]
|
|
283
|
+
|
|
284
|
+
%if $directed
|
|
285
|
+
%set $prefixes=["in_", "out_"]
|
|
286
|
+
%else
|
|
287
|
+
%set $prefixes=[""]
|
|
288
|
+
%end if
|
|
289
|
+
%for prefix in $prefixes
|
|
290
|
+
def ${prefix}edges(self, node=None, bint data=False):
|
|
291
|
+
|
|
292
|
+
if node is not None:
|
|
293
|
+
for neighbor in self._${prefix}neighbors(<NodeType>node, data):
|
|
294
|
+
if data:
|
|
295
|
+
%if $prefix == "in_"
|
|
296
|
+
yield (neighbor[0], node), data
|
|
297
|
+
%else
|
|
298
|
+
yield (node, neighbor[0]), data
|
|
299
|
+
%end if
|
|
300
|
+
else:
|
|
301
|
+
%if $prefix == "in_"
|
|
302
|
+
yield (neighbor, node)
|
|
303
|
+
%else
|
|
304
|
+
yield (node, neighbor)
|
|
305
|
+
%end if
|
|
306
|
+
return
|
|
307
|
+
|
|
308
|
+
cdef NodeIterator node_it = self._graph.begin()
|
|
309
|
+
cdef NodeIterator node_end = self._graph.end()
|
|
310
|
+
cdef pair[NeighborsIterator, NeighborsIterator] view
|
|
311
|
+
cdef NodeType u, v
|
|
312
|
+
cdef EdgeDataView edge_data = EdgeDataView()
|
|
313
|
+
|
|
314
|
+
while node_it != node_end:
|
|
315
|
+
view = self._graph.${prefix}neighbors(node_it)
|
|
316
|
+
u = deref(node_it)
|
|
317
|
+
it = view.first
|
|
318
|
+
end = view.second
|
|
319
|
+
while it != end:
|
|
320
|
+
v = deref(it).first
|
|
321
|
+
%if not $directed
|
|
322
|
+
# avoid double-reporting undirected edges by returning only
|
|
323
|
+
# edges where u < v
|
|
324
|
+
if u >= v:
|
|
325
|
+
inc(it)
|
|
326
|
+
continue
|
|
327
|
+
%end if
|
|
328
|
+
%if $prefix == "in_"
|
|
329
|
+
edge = (v, u)
|
|
330
|
+
%else
|
|
331
|
+
edge = (u, v)
|
|
332
|
+
%end if
|
|
333
|
+
if data:
|
|
334
|
+
edge_data.set_ptr(&deref(it).second.prop())
|
|
335
|
+
yield edge, edge_data
|
|
336
|
+
else:
|
|
337
|
+
yield edge
|
|
338
|
+
inc(it)
|
|
339
|
+
inc(node_it)
|
|
340
|
+
|
|
341
|
+
# same as above, but for fast access to edges incident to an array of nodes
|
|
342
|
+
# NOTE: this will double-report edges between "nodes"
|
|
343
|
+
def ${prefix}edges_by_nodes(self, NodeType[::1] nodes):
|
|
344
|
+
|
|
345
|
+
cdef pair[NeighborsIterator, NeighborsIterator] view
|
|
346
|
+
cdef NodeType u, v
|
|
347
|
+
cdef Py_ssize_t i = 0
|
|
348
|
+
|
|
349
|
+
num_edges = self._num_${prefix}edges(nodes)
|
|
350
|
+
data = np.empty(shape=(num_edges, 2), dtype="$node_dtype.base")
|
|
351
|
+
cdef NodeType[:, ::1] edges = data
|
|
352
|
+
|
|
353
|
+
for u in nodes:
|
|
354
|
+
view = self._graph.${prefix}neighbors(u)
|
|
355
|
+
it = view.first
|
|
356
|
+
end = view.second
|
|
357
|
+
while it != end:
|
|
358
|
+
v = deref(it).first
|
|
359
|
+
%if $prefix == "in_"
|
|
360
|
+
edges[i, 0] = v
|
|
361
|
+
edges[i, 1] = u
|
|
362
|
+
%else
|
|
363
|
+
edges[i, 0] = u
|
|
364
|
+
edges[i, 1] = v
|
|
365
|
+
%end if
|
|
366
|
+
i += 1
|
|
367
|
+
inc(it)
|
|
368
|
+
|
|
369
|
+
return data[:i]
|
|
370
|
+
%end for
|
|
371
|
+
|
|
372
|
+
# generator access to node and edge data
|
|
373
|
+
|
|
374
|
+
def nodes_data(self, NodeType[::1] nodes = None):
|
|
375
|
+
cdef NodeIterator node_it = self._graph.begin()
|
|
376
|
+
cdef NodeIterator node_end = self._graph.end()
|
|
377
|
+
cdef NodeDataView node_data = NodeDataView()
|
|
378
|
+
if nodes is None:
|
|
379
|
+
while node_it != node_end:
|
|
380
|
+
node_data.set_ptr(&self._graph.node_prop(node_it))
|
|
381
|
+
yield deref(node_it), node_data
|
|
382
|
+
inc(node_it)
|
|
383
|
+
else:
|
|
384
|
+
for node in nodes:
|
|
385
|
+
node_data.set_ptr(&self._graph.node_prop(node))
|
|
386
|
+
yield node, node_data
|
|
387
|
+
|
|
388
|
+
def edges_data(self, NodeType[::1] us, NodeType[::1] vs):
|
|
389
|
+
cdef EdgeDataView edge_data = EdgeDataView()
|
|
390
|
+
num_edges = len(us)
|
|
391
|
+
for i in range(num_edges):
|
|
392
|
+
edge_data.set_ptr(&self._graph.edge_prop(us[i], vs[i]))
|
|
393
|
+
yield edge_data
|
|
394
|
+
|
|
395
|
+
# access to individual attributes (single and multiple nodes/edges)
|
|
396
|
+
|
|
397
|
+
%for name, dtype in $node_attr_dtypes.items()
|
|
398
|
+
def get_node_data_${name}(self, NodeType node):
|
|
399
|
+
%if $dtype.is_array
|
|
400
|
+
return np.array(self._graph.node_prop(node).${name})
|
|
401
|
+
%else
|
|
402
|
+
return self._graph.node_prop(node).${name}
|
|
403
|
+
%end if
|
|
404
|
+
|
|
405
|
+
def get_nodes_data_${name}(self, NodeType[:] nodes):
|
|
406
|
+
|
|
407
|
+
cdef NodeIterator node_it = self._graph.begin()
|
|
408
|
+
cdef NodeIterator node_end = self._graph.end()
|
|
409
|
+
cdef Py_ssize_t i = 0
|
|
410
|
+
cdef NodeData* node_data
|
|
411
|
+
|
|
412
|
+
# allocate array for data
|
|
413
|
+
cdef Py_ssize_t num_nodes = 0
|
|
414
|
+
if nodes is None:
|
|
415
|
+
num_nodes = self._graph.size()
|
|
416
|
+
else:
|
|
417
|
+
num_nodes = len(nodes)
|
|
418
|
+
data = np.empty(shape=(num_nodes,) + $dtype.shape, dtype="$dtype.base")
|
|
419
|
+
cdef $dtype.to_pyxtype(add_dim=True) view = data
|
|
420
|
+
|
|
421
|
+
# all nodes requested
|
|
422
|
+
if nodes is None:
|
|
423
|
+
while node_it != node_end:
|
|
424
|
+
%if $dtype.is_array
|
|
425
|
+
node_data = &self._graph.node_prop(node_it)
|
|
426
|
+
%for j in range($dtype.size)
|
|
427
|
+
view[i, $j] = node_data.${name}[$j]
|
|
428
|
+
%end for
|
|
429
|
+
%else
|
|
430
|
+
view[i] = self._graph.node_prop(node_it).${name}
|
|
431
|
+
%end if
|
|
432
|
+
inc(node_it)
|
|
433
|
+
i += 1
|
|
434
|
+
else:
|
|
435
|
+
for i in range(num_nodes):
|
|
436
|
+
%if $dtype.is_array
|
|
437
|
+
node_data = &self._graph.node_prop(nodes[i])
|
|
438
|
+
%for j in range($dtype.size)
|
|
439
|
+
view[i, $j] = node_data.${name}[$j]
|
|
440
|
+
%end for
|
|
441
|
+
%else
|
|
442
|
+
view[i] = self._graph.node_prop(nodes[i]).${name}
|
|
443
|
+
%end if
|
|
444
|
+
|
|
445
|
+
return data
|
|
446
|
+
|
|
447
|
+
def set_node_data_${name}(
|
|
448
|
+
self,
|
|
449
|
+
NodeType node,
|
|
450
|
+
$dtype.to_pyxtype(use_memory_view=True) $name):
|
|
451
|
+
%if $dtype.is_array
|
|
452
|
+
%for j in range($dtype.size)
|
|
453
|
+
self._graph.node_prop(node).${name}[$j] = ${name}[$j]
|
|
454
|
+
%end for
|
|
455
|
+
%else
|
|
456
|
+
self._graph.node_prop(node).${name} = $name
|
|
457
|
+
%end if
|
|
458
|
+
|
|
459
|
+
def set_nodes_data_${name}(
|
|
460
|
+
self,
|
|
461
|
+
NodeType[:] nodes,
|
|
462
|
+
$dtype.to_pyxtype(add_dim=True) $name):
|
|
463
|
+
|
|
464
|
+
cdef NodeIterator node_it = self._graph.begin()
|
|
465
|
+
cdef NodeIterator node_end = self._graph.end()
|
|
466
|
+
cdef Py_ssize_t i = 0
|
|
467
|
+
|
|
468
|
+
# all nodes requested
|
|
469
|
+
if nodes is None:
|
|
470
|
+
while node_it != node_end:
|
|
471
|
+
%if $dtype.is_array
|
|
472
|
+
node_data = &self._graph.node_prop(node_it)
|
|
473
|
+
%for j in range($dtype.size)
|
|
474
|
+
node_data.${name}[$j] = ${name}[i, $j]
|
|
475
|
+
%end for
|
|
476
|
+
%else
|
|
477
|
+
self._graph.node_prop(node_it).$name = ${name}[i]
|
|
478
|
+
%end if
|
|
479
|
+
inc(node_it)
|
|
480
|
+
i += 1
|
|
481
|
+
else:
|
|
482
|
+
assert len(nodes) == len($name)
|
|
483
|
+
for i in range(len(nodes)):
|
|
484
|
+
%if dtype.is_array
|
|
485
|
+
node_data = &self._graph.node_prop(nodes[i])
|
|
486
|
+
%for j in range($dtype.size)
|
|
487
|
+
node_data.${name}[$j] = ${name}[i, $j]
|
|
488
|
+
%end for
|
|
489
|
+
%else
|
|
490
|
+
self._graph.node_prop(nodes[i]).$name = ${name}[i]
|
|
491
|
+
%end if
|
|
492
|
+
%end for
|
|
493
|
+
|
|
494
|
+
%for name, dtype in $edge_attr_dtypes.items()
|
|
495
|
+
def get_edge_data_${name}(self, NodeType u, NodeType v):
|
|
496
|
+
%if $dtype.is_array
|
|
497
|
+
return np.array(self._graph.edge_prop(u, v).${name})
|
|
498
|
+
%else
|
|
499
|
+
return self._graph.edge_prop(u, v).${name}
|
|
500
|
+
%end if
|
|
501
|
+
|
|
502
|
+
def get_edges_data_${name}(self, NodeType[::1] us, NodeType[::1] vs):
|
|
503
|
+
|
|
504
|
+
cdef Py_ssize_t i = 0
|
|
505
|
+
cdef Py_ssize_t num_edges = 0
|
|
506
|
+
cdef NodeIterator node_it = self._graph.begin()
|
|
507
|
+
cdef NodeIterator node_end = self._graph.end()
|
|
508
|
+
cdef pair[NeighborsIterator, NeighborsIterator] edges_view
|
|
509
|
+
cdef NodeType u, v
|
|
510
|
+
cdef EdgeData* edge_data
|
|
511
|
+
|
|
512
|
+
# allocate array for data
|
|
513
|
+
if us is None and vs is None:
|
|
514
|
+
num_edges = self._graph.num_edges()
|
|
515
|
+
elif us is None or vs is None:
|
|
516
|
+
raise RuntimeError("Either both us and vs are None, or neither")
|
|
517
|
+
else:
|
|
518
|
+
num_edges = len(us)
|
|
519
|
+
data = np.empty(shape=(num_edges,) + $dtype.shape, dtype="$dtype.base")
|
|
520
|
+
cdef $dtype.to_pyxtype(add_dim=True) view = data
|
|
521
|
+
|
|
522
|
+
if us is None:
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
while node_it != node_end:
|
|
526
|
+
%if $directed
|
|
527
|
+
# iterate over all edges by iterating over all nodes u and
|
|
528
|
+
# their out neighbors
|
|
529
|
+
edges_view = self._graph.out_neighbors(node_it)
|
|
530
|
+
%else
|
|
531
|
+
# iterate over all edges by iterating over all nodes u and
|
|
532
|
+
# their neighbors v with u < v
|
|
533
|
+
edges_view = self._graph.neighbors(node_it)
|
|
534
|
+
%end if
|
|
535
|
+
u = deref(node_it)
|
|
536
|
+
it = edges_view.first
|
|
537
|
+
end = edges_view.second
|
|
538
|
+
while it != end:
|
|
539
|
+
v = deref(it).first
|
|
540
|
+
if ${directed} or u < v:
|
|
541
|
+
%if $dtype.is_array
|
|
542
|
+
edge_data = &deref(it).second.prop()
|
|
543
|
+
%for j in range($dtype.size)
|
|
544
|
+
view[i, $j] = edge_data.${name}[$j]
|
|
545
|
+
%end for
|
|
546
|
+
%else
|
|
547
|
+
view[i] = deref(it).second.prop().$name
|
|
548
|
+
%end if
|
|
549
|
+
i += 1
|
|
550
|
+
inc(it)
|
|
551
|
+
inc(node_it)
|
|
552
|
+
|
|
553
|
+
else:
|
|
554
|
+
for i in range(num_edges):
|
|
555
|
+
%if $dtype.is_array
|
|
556
|
+
edge_data = &self._graph.edge_prop(us[i], vs[i])
|
|
557
|
+
%for j in range($dtype.size)
|
|
558
|
+
view[i, $j] = edge_data.${name}[$j]
|
|
559
|
+
%end for
|
|
560
|
+
%else
|
|
561
|
+
view[i] = self._graph.edge_prop(us[i], vs[i]).$name
|
|
562
|
+
%end if
|
|
563
|
+
|
|
564
|
+
return data
|
|
565
|
+
|
|
566
|
+
def set_edge_data_${name}(
|
|
567
|
+
self,
|
|
568
|
+
NodeType u, NodeType v,
|
|
569
|
+
$dtype.to_pyxtype(use_memory_view=True) $name):
|
|
570
|
+
%if dtype.is_array
|
|
571
|
+
edge_data = &self._graph.edge_prop(u, v)
|
|
572
|
+
%for j in range($dtype.size)
|
|
573
|
+
edge_data.${name}[$j] = ${name}[$j]
|
|
574
|
+
%end for
|
|
575
|
+
%else
|
|
576
|
+
self._graph.edge_prop(u, v).${name} = $name
|
|
577
|
+
%end if
|
|
578
|
+
|
|
579
|
+
def set_edges_data_${name}(
|
|
580
|
+
self,
|
|
581
|
+
NodeType[::1] us, NodeType[::1] vs,
|
|
582
|
+
$dtype.to_pyxtype(add_dim=True) $name):
|
|
583
|
+
|
|
584
|
+
cdef Py_ssize_t i = 0
|
|
585
|
+
cdef Py_ssize_t num_edges = 0
|
|
586
|
+
|
|
587
|
+
assert len(us) == len(vs)
|
|
588
|
+
num_edges = len(us)
|
|
589
|
+
|
|
590
|
+
for i in range(num_edges):
|
|
591
|
+
%if $dtype.is_array
|
|
592
|
+
edge_data = &self._graph.edge_prop(us[i], vs[i])
|
|
593
|
+
%for j in range($dtype.size)
|
|
594
|
+
edge_data.${name}[$j] = ${name}[i, $j]
|
|
595
|
+
%end for
|
|
596
|
+
%else
|
|
597
|
+
self._graph.edge_prop(us[i], vs[i]).$name = ${name}[i]
|
|
598
|
+
%end if
|
|
599
|
+
%end for
|
|
600
|
+
|
|
601
|
+
# modify graph
|
|
602
|
+
|
|
603
|
+
def remove_node(self, NodeType node):
|
|
604
|
+
self._graph.remove_nodes(node)
|
|
605
|
+
|
|
606
|
+
def remove_nodes(self, NodeType[::1] nodes):
|
|
607
|
+
for i in range(len(nodes)):
|
|
608
|
+
self._graph.remove_nodes(nodes[i])
|
|
609
|
+
|
|
610
|
+
# read-only graph properties
|
|
611
|
+
|
|
612
|
+
%if $directed
|
|
613
|
+
%set $prefixes=["in_", "out_"]
|
|
614
|
+
%else
|
|
615
|
+
%set $prefixes=[""]
|
|
616
|
+
%end if
|
|
617
|
+
%for prefix in $prefixes
|
|
618
|
+
def count_${prefix}neighbors(self, NodeType[:] nodes):
|
|
619
|
+
num_nodes = len(nodes)
|
|
620
|
+
cdef int[:] counts = view.array(
|
|
621
|
+
shape=(num_nodes,),
|
|
622
|
+
itemsize=sizeof(int),
|
|
623
|
+
format="i")
|
|
624
|
+
for i in range(num_nodes):
|
|
625
|
+
counts[i] = self._graph.count_${prefix}neighbors(nodes[i])
|
|
626
|
+
return counts
|
|
627
|
+
|
|
628
|
+
def _${prefix}neighbors(self, NodeType node, bint data):
|
|
629
|
+
|
|
630
|
+
cdef pair[NeighborsIterator, NeighborsIterator] view = \
|
|
631
|
+
self._graph.${prefix}neighbors(node)
|
|
632
|
+
cdef NeighborsIterator it = view.first
|
|
633
|
+
cdef NeighborsIterator end = view.second
|
|
634
|
+
cdef EdgeDataView edge_data = EdgeDataView()
|
|
635
|
+
|
|
636
|
+
if data:
|
|
637
|
+
while it != end:
|
|
638
|
+
edge_data.set_ptr(&deref(it).second.prop())
|
|
639
|
+
yield deref(it).first, edge_data
|
|
640
|
+
inc(it)
|
|
641
|
+
else:
|
|
642
|
+
while it != end:
|
|
643
|
+
yield deref(it).first
|
|
644
|
+
inc(it)
|
|
645
|
+
|
|
646
|
+
def _num_${prefix}edges(self, NodeType[::1] nodes):
|
|
647
|
+
return np.sum(self.count_${prefix}neighbors(nodes))
|
|
648
|
+
%end for
|
|
649
|
+
|
|
650
|
+
def __len__(self):
|
|
651
|
+
return self._graph.size()
|
|
652
|
+
|
|
653
|
+
def num_edges(self):
|
|
654
|
+
return self._graph.num_edges()
|