Statistics
| Branch: | Revision:

iof-tools / networkxMiCe / networkx-master / networkx / classes / coreviews.py @ 5cef0f13

History | View | Annotate | Download (13.4 KB)

1
#    Copyright (C) 2004-2019 by
2
#    Aric Hagberg <hagberg@lanl.gov>
3
#    Dan Schult <dschult@colgate.edu>
4
#    Pieter Swart <swart@lanl.gov>
5
#    All rights reserved.
6
#    BSD license.
7
#
8
# Authors: Aric Hagberg (hagberg@lanl.gov),
9
#          Pieter Swart (swart@lanl.gov),
10
#          Dan Schult(dschult@colgate.edu)
11
"""
12
"""
13
from collections.abc import Mapping
14
import networkx as nx
15

    
16
__all__ = ['AtlasView', 'AdjacencyView', 'MultiAdjacencyView',
17
           'UnionAtlas', 'UnionAdjacency',
18
           'UnionMultiInner', 'UnionMultiAdjacency',
19
           'FilterAtlas', 'FilterAdjacency',
20
           'FilterMultiInner', 'FilterMultiAdjacency',
21
           ]
22

    
23

    
24
class AtlasView(Mapping):
25
    """An AtlasView is a Read-only Mapping of Mappings.
26

27
    It is a View into a dict-of-dict data structure.
28
    The inner level of dict is read-write. But the
29
    outer level is read-only.
30

31
    See Also
32
    ========
33
    AdjacencyView - View into dict-of-dict-of-dict
34
    MultiAdjacencyView - View into dict-of-dict-of-dict-of-dict
35
    """
36
    __slots__ = ('_atlas',)
37

    
38
    def __getstate__(self):
39
        return {'_atlas': self._atlas}
40

    
41
    def __setstate__(self, state):
42
        self._atlas = state['_atlas']
43

    
44
    def __init__(self, d):
45
        self._atlas = d
46

    
47
    def __len__(self):
48
        return len(self._atlas)
49

    
50
    def __iter__(self):
51
        return iter(self._atlas)
52

    
53
    def __getitem__(self, key):
54
        return self._atlas[key]
55

    
56
    def copy(self):
57
        return {n: self[n].copy() for n in self._atlas}
58

    
59
    def __str__(self):
60
        return str(self._atlas)  # {nbr: self[nbr] for nbr in self})
61

    
62
    def __repr__(self):
63
        return '%s(%r)' % (self.__class__.__name__, self._atlas)
64

    
65

    
66
class AdjacencyView(AtlasView):
67
    """An AdjacencyView is a Read-only Map of Maps of Maps.
68

69
    It is a View into a dict-of-dict-of-dict data structure.
70
    The inner level of dict is read-write. But the
71
    outer levels are read-only.
72

73
    See Also
74
    ========
75
    AtlasView - View into dict-of-dict
76
    MultiAdjacencyView - View into dict-of-dict-of-dict-of-dict
77
    """
78
    __slots__ = ()   # Still uses AtlasView slots names _atlas
79

    
80
    def __getitem__(self, name):
81
        return AtlasView(self._atlas[name])
82

    
83
    def copy(self):
84
        return {n: self[n].copy() for n in self._atlas}
85

    
86

    
87
class MultiAdjacencyView(AdjacencyView):
88
    """An MultiAdjacencyView is a Read-only Map of Maps of Maps of Maps.
89

90
    It is a View into a dict-of-dict-of-dict-of-dict data structure.
91
    The inner level of dict is read-write. But the
92
    outer levels are read-only.
93

94
    See Also
95
    ========
96
    AtlasView - View into dict-of-dict
97
    AdjacencyView - View into dict-of-dict-of-dict
98
    """
99
    __slots__ = ()   # Still uses AtlasView slots names _atlas
100

    
101
    def __getitem__(self, name):
102
        return AdjacencyView(self._atlas[name])
103

    
104
    def copy(self):
105
        return {n: self[n].copy() for n in self._atlas}
106

    
107

    
108
class UnionAtlas(Mapping):
109
    """A read-only union of two atlases (dict-of-dict).
110

111
    The two dict-of-dicts represent the inner dict of
112
    an Adjacency:  `G.succ[node]` and `G.pred[node]`.
113
    The inner level of dict of both hold attribute key:value
114
    pairs and is read-write. But the outer level is read-only.
115

116
    See Also
117
    ========
118
    UnionAdjacency - View into dict-of-dict-of-dict
119
    UnionMultiAdjacency - View into dict-of-dict-of-dict-of-dict
120
    """
121
    __slots__ = ('_succ', '_pred')
122

    
123
    def __getstate__(self):
124
        return {'_succ': self._succ, '_pred': self._pred}
125

    
126
    def __setstate__(self, state):
127
        self._succ = state['_succ']
128
        self._pred = state['_pred']
129

    
130
    def __init__(self, succ, pred):
131
        self._succ = succ
132
        self._pred = pred
133

    
134
    def __len__(self):
135
        return len(self._succ) + len(self._pred)
136

    
137
    def __iter__(self):
138
        return iter(set(self._succ.keys()) | set(self._pred.keys()))
139

    
140
    def __getitem__(self, key):
141
        try:
142
            return self._succ[key]
143
        except KeyError:
144
            return self._pred[key]
145

    
146
    def copy(self):
147
        result = {nbr: dd.copy() for nbr, dd in self._succ.items()}
148
        for nbr, dd in self._pred.items():
149
            if nbr in result:
150
                result[nbr].update(dd)
151
            else:
152
                result[nbr] = dd.copy()
153
        return result
154

    
155
    def __str__(self):
156
        return str({nbr: self[nbr] for nbr in self})
157

    
158
    def __repr__(self):
159
        return '%s(%r, %r)' % (self.__class__.__name__, self._succ, self._pred)
160

    
161

    
162
class UnionAdjacency(Mapping):
163
    """A read-only union of dict Adjacencies as a Map of Maps of Maps.
164

165
    The two input dict-of-dict-of-dicts represent the union of
166
    `G.succ` and `G.pred`. Return values are UnionAtlas
167
    The inner level of dict is read-write. But the
168
    middle and outer levels are read-only.
169

170
    succ : a dict-of-dict-of-dict {node: nbrdict}
171
    pred : a dict-of-dict-of-dict {node: nbrdict}
172
    The keys for the two dicts should be the same
173

174
    See Also
175
    ========
176
    UnionAtlas - View into dict-of-dict
177
    UnionMultiAdjacency - View into dict-of-dict-of-dict-of-dict
178
    """
179
    __slots__ = ('_succ', '_pred')
180

    
181
    def __getstate__(self):
182
        return {'_succ': self._succ, '_pred': self._pred}
183

    
184
    def __setstate__(self, state):
185
        self._succ = state['_succ']
186
        self._pred = state['_pred']
187

    
188
    def __init__(self, succ, pred):
189
        # keys must be the same for two input dicts
190
        assert(len(set(succ.keys()) ^ set(pred.keys())) == 0)
191
        self._succ = succ
192
        self._pred = pred
193

    
194
    def __len__(self):
195
        return len(self._succ)  # length of each dict should be the same
196

    
197
    def __iter__(self):
198
        return iter(self._succ)
199

    
200
    def __getitem__(self, nbr):
201
        return UnionAtlas(self._succ[nbr], self._pred[nbr])
202

    
203
    def copy(self):
204
        return {n: self[n].copy() for n in self._succ}
205

    
206
    def __str__(self):
207
        return str({nbr: self[nbr] for nbr in self})
208

    
209
    def __repr__(self):
210
        return '%s(%r, %r)' % (self.__class__.__name__, self._succ, self._pred)
211

    
212

    
213
class UnionMultiInner(UnionAtlas):
214
    """A read-only union of two inner dicts of MultiAdjacencies.
215

216
    The two input dict-of-dict-of-dicts represent the union of
217
    `G.succ[node]` and `G.pred[node]` for MultiDiGraphs.
218
    Return values are UnionAtlas.
219
    The inner level of dict is read-write. But the outer levels are read-only.
220

221
    See Also
222
    ========
223
    UnionAtlas - View into dict-of-dict
224
    UnionAdjacency - View into dict-of-dict-of-dict
225
    UnionMultiAdjacency - View into dict-of-dict-of-dict-of-dict
226
    """
227
    __slots__ = ()   # Still uses UnionAtlas slots names _succ, _pred
228

    
229
    def __getitem__(self, node):
230
        in_succ = node in self._succ
231
        in_pred = node in self._pred
232
        if in_succ:
233
            if in_pred:
234
                return UnionAtlas(self._succ[node], self._pred[node])
235
            return UnionAtlas(self._succ[node], {})
236
        return UnionAtlas({}, self._pred[node])
237

    
238
    def copy(self):
239
        nodes = set(self._succ.keys()) | set(self._pred.keys())
240
        return {n: self[n].copy() for n in nodes}
241

    
242

    
243
class UnionMultiAdjacency(UnionAdjacency):
244
    """A read-only union of two dict MultiAdjacencies.
245

246
    The two input dict-of-dict-of-dict-of-dicts represent the union of
247
    `G.succ` and `G.pred` for MultiDiGraphs. Return values are UnionAdjacency.
248
    The inner level of dict is read-write. But the outer levels are read-only.
249

250
    See Also
251
    ========
252
    UnionAtlas - View into dict-of-dict
253
    UnionMultiInner - View into dict-of-dict-of-dict
254
    """
255
    __slots__ = ()   # Still uses UnionAdjacency slots names _succ, _pred
256

    
257
    def __getitem__(self, node):
258
        return UnionMultiInner(self._succ[node], self._pred[node])
259

    
260

    
261
class FilterAtlas(Mapping):  # nodedict, nbrdict, keydict
262
    def __init__(self, d, NODE_OK):
263
        self._atlas = d
264
        self.NODE_OK = NODE_OK
265

    
266
    def __len__(self):
267
        return sum(1 for n in self)
268

    
269
    def __iter__(self):
270
        try:  # check that NODE_OK has attr 'nodes'
271
            node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas)
272
        except AttributeError:
273
            node_ok_shorter = False
274
        if node_ok_shorter:
275
            return (n for n in self.NODE_OK.nodes if n in self._atlas)
276
        return (n for n in self._atlas if self.NODE_OK(n))
277

    
278
    def __getitem__(self, key):
279
        if key in self._atlas and self.NODE_OK(key):
280
            return self._atlas[key]
281
        raise KeyError("Key {} not found".format(key))
282

    
283
    def copy(self):
284
        try:  # check that NODE_OK has attr 'nodes'
285
            node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas)
286
        except AttributeError:
287
            node_ok_shorter = False
288
        if node_ok_shorter:
289
            return {u: self._atlas[u] for u in self.NODE_OK.nodes
290
                    if u in self._atlas}
291
        return {u: d for u, d in self._atlas.items()
292
                if self.NODE_OK(u)}
293

    
294
    def __str__(self):
295
        return str({nbr: self[nbr] for nbr in self})
296

    
297
    def __repr__(self):
298
        return '%s(%r, %r)' % (self.__class__.__name__, self._atlas,
299
                               self.NODE_OK)
300

    
301

    
302
class FilterAdjacency(Mapping):   # edgedict
303
    def __init__(self, d, NODE_OK, EDGE_OK):
304
        self._atlas = d
305
        self.NODE_OK = NODE_OK
306
        self.EDGE_OK = EDGE_OK
307

    
308
    def __len__(self):
309
        return sum(1 for n in self)
310

    
311
    def __iter__(self):
312
        try:  # check that NODE_OK has attr 'nodes'
313
            node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas)
314
        except AttributeError:
315
            node_ok_shorter = False
316
        if node_ok_shorter:
317
            return (n for n in self.NODE_OK.nodes if n in self._atlas)
318
        return (n for n in self._atlas if self.NODE_OK(n))
319

    
320
    def __getitem__(self, node):
321
        if node in self._atlas and self.NODE_OK(node):
322
            def new_node_ok(nbr):
323
                return self.NODE_OK(nbr) and self.EDGE_OK(node, nbr)
324
            return FilterAtlas(self._atlas[node], new_node_ok)
325
        raise KeyError("Key {} not found".format(node))
326

    
327
    def copy(self):
328
        try:  # check that NODE_OK has attr 'nodes'
329
            node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas)
330
        except AttributeError:
331
            node_ok_shorter = False
332
        if node_ok_shorter:
333
            return {u: {v: d for v, d in self._atlas[u].items()
334
                        if self.NODE_OK(v) if self.EDGE_OK(u, v)}
335
                    for u in self.NODE_OK.nodes if u in self._atlas}
336
        return {u: {v: d for v, d in nbrs.items() if self.NODE_OK(v)
337
                    if self.EDGE_OK(u, v)}
338
                for u, nbrs in self._atlas.items()
339
                if self.NODE_OK(u)}
340

    
341
    def __str__(self):
342
        return str({nbr: self[nbr] for nbr in self})
343

    
344
    def __repr__(self):
345
        return '%s(%r, %r, %r)' % (self.__class__.__name__, self._atlas,
346
                                   self.NODE_OK, self.EDGE_OK)
347

    
348

    
349
class FilterMultiInner(FilterAdjacency):  # muliedge_seconddict
350
    def __iter__(self):
351
        try:  # check that NODE_OK has attr 'nodes'
352
            node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas)
353
        except AttributeError:
354
            node_ok_shorter = False
355
        if node_ok_shorter:
356
            my_nodes = (n for n in self.NODE_OK.nodes if n in self._atlas)
357
        else:
358
            my_nodes = (n for n in self._atlas if self.NODE_OK(n))
359
        for n in my_nodes:
360
            some_keys_ok = False
361
            for key in self._atlas[n]:
362
                if self.EDGE_OK(n, key):
363
                    some_keys_ok = True
364
                    break
365
            if some_keys_ok is True:
366
                yield n
367

    
368
    def __getitem__(self, nbr):
369
        if nbr in self._atlas and self.NODE_OK(nbr):
370
            def new_node_ok(key):
371
                return self.EDGE_OK(nbr, key)
372
            return FilterAtlas(self._atlas[nbr], new_node_ok)
373
        raise KeyError("Key {} not found".format(nbr))
374

    
375
    def copy(self):
376
        try:  # check that NODE_OK has attr 'nodes'
377
            node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas)
378
        except AttributeError:
379
            node_ok_shorter = False
380
        if node_ok_shorter:
381
            return {v: {k: d for k, d in self._atlas[v].items()
382
                        if self.EDGE_OK(v, k)}
383
                    for v in self.NODE_OK.nodes if v in self._atlas}
384
        return {v: {k: d for k, d in nbrs.items() if self.EDGE_OK(v, k)}
385
                for v, nbrs in self._atlas.items() if self.NODE_OK(v)}
386

    
387

    
388
class FilterMultiAdjacency(FilterAdjacency):  # multiedgedict
389
    def __getitem__(self, node):
390
        if node in self._atlas and self.NODE_OK(node):
391
            def edge_ok(nbr, key):
392
                return self.NODE_OK(nbr) and self.EDGE_OK(node, nbr, key)
393
            return FilterMultiInner(self._atlas[node], self.NODE_OK, edge_ok)
394
        raise KeyError("Key {} not found".format(node))
395

    
396
    def copy(self):
397
        try:  # check that NODE_OK has attr 'nodes'
398
            node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas)
399
        except AttributeError:
400
            node_ok_shorter = False
401
        if node_ok_shorter:
402
            my_nodes = self.NODE_OK.nodes
403
            return {u: {v: {k: d for k, d in kd.items()
404
                            if self.EDGE_OK(u, v, k)}
405
                        for v, kd in self._atlas[u].items() if v in my_nodes}
406
                    for u in my_nodes if u in self._atlas}
407
        return {u: {v: {k: d for k, d in kd.items()
408
                        if self.EDGE_OK(u, v, k)}
409
                    for v, kd in nbrs.items() if self.NODE_OK(v)}
410
                for u, nbrs in self._atlas.items() if self.NODE_OK(u)}