comparison env/lib/python3.9/site-packages/networkx/utils/misc.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 """
2 Miscellaneous Helpers for NetworkX.
3
4 These are not imported into the base networkx namespace but
5 can be accessed, for example, as
6
7 >>> import networkx
8 >>> networkx.utils.is_list_of_ints([1, 2, 3])
9 True
10 >>> networkx.utils.is_list_of_ints([1, 2, "spam"])
11 False
12 """
13
14 from collections import defaultdict
15 from collections import deque
16 import warnings
17 import sys
18 import uuid
19 from itertools import tee, chain
20 import networkx as nx
21
22
23 # some cookbook stuff
24 # used in deciding whether something is a bunch of nodes, edges, etc.
25 # see G.add_nodes and others in Graph Class in networkx/base.py
26
27
28 def is_string_like(obj): # from John Hunter, types-free version
29 """Check if obj is string."""
30 msg = (
31 "is_string_like is deprecated and will be removed in 3.0."
32 "Use isinstance(obj, str) instead."
33 )
34 warnings.warn(msg, DeprecationWarning)
35 return isinstance(obj, str)
36
37
38 def iterable(obj):
39 """ Return True if obj is iterable with a well-defined len()."""
40 if hasattr(obj, "__iter__"):
41 return True
42 try:
43 len(obj)
44 except:
45 return False
46 return True
47
48
49 def empty_generator():
50 """ Return a generator with no members """
51 yield from ()
52
53
54 def flatten(obj, result=None):
55 """ Return flattened version of (possibly nested) iterable object. """
56 if not iterable(obj) or is_string_like(obj):
57 return obj
58 if result is None:
59 result = []
60 for item in obj:
61 if not iterable(item) or is_string_like(item):
62 result.append(item)
63 else:
64 flatten(item, result)
65 return obj.__class__(result)
66
67
68 def make_list_of_ints(sequence):
69 """Return list of ints from sequence of integral numbers.
70
71 All elements of the sequence must satisfy int(element) == element
72 or a ValueError is raised. Sequence is iterated through once.
73
74 If sequence is a list, the non-int values are replaced with ints.
75 So, no new list is created
76 """
77 if not isinstance(sequence, list):
78 result = []
79 for i in sequence:
80 errmsg = f"sequence is not all integers: {i}"
81 try:
82 ii = int(i)
83 except ValueError:
84 raise nx.NetworkXError(errmsg) from None
85 if ii != i:
86 raise nx.NetworkXError(errmsg)
87 result.append(ii)
88 return result
89 # original sequence is a list... in-place conversion to ints
90 for indx, i in enumerate(sequence):
91 errmsg = f"sequence is not all integers: {i}"
92 if isinstance(i, int):
93 continue
94 try:
95 ii = int(i)
96 except ValueError:
97 raise nx.NetworkXError(errmsg) from None
98 if ii != i:
99 raise nx.NetworkXError(errmsg)
100 sequence[indx] = ii
101 return sequence
102
103
104 def is_list_of_ints(intlist):
105 """ Return True if list is a list of ints. """
106 if not isinstance(intlist, list):
107 return False
108 for i in intlist:
109 if not isinstance(i, int):
110 return False
111 return True
112
113
114 def make_str(x):
115 """Returns the string representation of t."""
116 msg = "make_str is deprecated and will be removed in 3.0. Use str instead."
117 warnings.warn(msg, DeprecationWarning)
118 return str(x)
119
120
121 def generate_unique_node():
122 """ Generate a unique node label."""
123 return str(uuid.uuid1())
124
125
126 def default_opener(filename):
127 """Opens `filename` using system's default program.
128
129 Parameters
130 ----------
131 filename : str
132 The path of the file to be opened.
133
134 """
135 from subprocess import call
136
137 cmds = {
138 "darwin": ["open"],
139 "linux": ["xdg-open"],
140 "linux2": ["xdg-open"],
141 "win32": ["cmd.exe", "/C", "start", ""],
142 }
143 cmd = cmds[sys.platform] + [filename]
144 call(cmd)
145
146
147 def dict_to_numpy_array(d, mapping=None):
148 """Convert a dictionary of dictionaries to a numpy array
149 with optional mapping."""
150 try:
151 return dict_to_numpy_array2(d, mapping)
152 except (AttributeError, TypeError):
153 # AttributeError is when no mapping was provided and v.keys() fails.
154 # TypeError is when a mapping was provided and d[k1][k2] fails.
155 return dict_to_numpy_array1(d, mapping)
156
157
158 def dict_to_numpy_array2(d, mapping=None):
159 """Convert a dictionary of dictionaries to a 2d numpy array
160 with optional mapping.
161
162 """
163 import numpy
164
165 if mapping is None:
166 s = set(d.keys())
167 for k, v in d.items():
168 s.update(v.keys())
169 mapping = dict(zip(s, range(len(s))))
170 n = len(mapping)
171 a = numpy.zeros((n, n))
172 for k1, i in mapping.items():
173 for k2, j in mapping.items():
174 try:
175 a[i, j] = d[k1][k2]
176 except KeyError:
177 pass
178 return a
179
180
181 def dict_to_numpy_array1(d, mapping=None):
182 """Convert a dictionary of numbers to a 1d numpy array
183 with optional mapping.
184
185 """
186 import numpy
187
188 if mapping is None:
189 s = set(d.keys())
190 mapping = dict(zip(s, range(len(s))))
191 n = len(mapping)
192 a = numpy.zeros(n)
193 for k1, i in mapping.items():
194 i = mapping[k1]
195 a[i] = d[k1]
196 return a
197
198
199 def is_iterator(obj):
200 """Returns True if and only if the given object is an iterator
201 object.
202
203 """
204 has_next_attr = hasattr(obj, "__next__") or hasattr(obj, "next")
205 return iter(obj) is obj and has_next_attr
206
207
208 def arbitrary_element(iterable):
209 """Returns an arbitrary element of `iterable` without removing it.
210
211 This is most useful for "peeking" at an arbitrary element of a set,
212 but can be used for any list, dictionary, etc., as well::
213
214 >>> arbitrary_element({3, 2, 1})
215 1
216 >>> arbitrary_element("hello")
217 'h'
218
219 This function raises a :exc:`ValueError` if `iterable` is an
220 iterator (because the current implementation of this function would
221 consume an element from the iterator)::
222
223 >>> iterator = iter([1, 2, 3])
224 >>> arbitrary_element(iterator)
225 Traceback (most recent call last):
226 ...
227 ValueError: cannot return an arbitrary item from an iterator
228
229 """
230 if is_iterator(iterable):
231 raise ValueError("cannot return an arbitrary item from an iterator")
232 # Another possible implementation is ``for x in iterable: return x``.
233 return next(iter(iterable))
234
235
236 # Recipe from the itertools documentation.
237 def consume(iterator):
238 "Consume the iterator entirely."
239 # Feed the entire iterator into a zero-length deque.
240 deque(iterator, maxlen=0)
241
242
243 # Recipe from the itertools documentation.
244 def pairwise(iterable, cyclic=False):
245 "s -> (s0, s1), (s1, s2), (s2, s3), ..."
246 a, b = tee(iterable)
247 first = next(b, None)
248 if cyclic is True:
249 return zip(a, chain(b, (first,)))
250 return zip(a, b)
251
252
253 def groups(many_to_one):
254 """Converts a many-to-one mapping into a one-to-many mapping.
255
256 `many_to_one` must be a dictionary whose keys and values are all
257 :term:`hashable`.
258
259 The return value is a dictionary mapping values from `many_to_one`
260 to sets of keys from `many_to_one` that have that value.
261
262 For example::
263
264 >>> from networkx.utils import groups
265 >>> many_to_one = {"a": 1, "b": 1, "c": 2, "d": 3, "e": 3}
266 >>> groups(many_to_one) # doctest: +SKIP
267 {1: {'a', 'b'}, 2: {'c'}, 3: {'d', 'e'}}
268
269 """
270 one_to_many = defaultdict(set)
271 for v, k in many_to_one.items():
272 one_to_many[k].add(v)
273 return dict(one_to_many)
274
275
276 def to_tuple(x):
277 """Converts lists to tuples.
278
279 For example::
280
281 >>> from networkx.utils import to_tuple
282 >>> a_list = [1, 2, [1, 4]]
283 >>> to_tuple(a_list)
284 (1, 2, (1, 4))
285
286 """
287 if not isinstance(x, (tuple, list)):
288 return x
289 return tuple(map(to_tuple, x))
290
291
292 def create_random_state(random_state=None):
293 """Returns a numpy.random.RandomState instance depending on input.
294
295 Parameters
296 ----------
297 random_state : int or RandomState instance or None optional (default=None)
298 If int, return a numpy.random.RandomState instance set with seed=int.
299 if numpy.random.RandomState instance, return it.
300 if None or numpy.random, return the global random number generator used
301 by numpy.random.
302 """
303 import numpy as np
304
305 if random_state is None or random_state is np.random:
306 return np.random.mtrand._rand
307 if isinstance(random_state, np.random.RandomState):
308 return random_state
309 if isinstance(random_state, int):
310 return np.random.RandomState(random_state)
311 msg = (
312 f"{random_state} cannot be used to generate a numpy.random.RandomState instance"
313 )
314 raise ValueError(msg)
315
316
317 class PythonRandomInterface:
318 try:
319
320 def __init__(self, rng=None):
321 import numpy
322
323 if rng is None:
324 self._rng = numpy.random.mtrand._rand
325 self._rng = rng
326
327 except ImportError:
328 msg = "numpy not found, only random.random available."
329 warnings.warn(msg, ImportWarning)
330
331 def random(self):
332 return self._rng.random_sample()
333
334 def uniform(self, a, b):
335 return a + (b - a) * self._rng.random_sample()
336
337 def randrange(self, a, b=None):
338 return self._rng.randint(a, b)
339
340 def choice(self, seq):
341 return seq[self._rng.randint(0, len(seq))]
342
343 def gauss(self, mu, sigma):
344 return self._rng.normal(mu, sigma)
345
346 def shuffle(self, seq):
347 return self._rng.shuffle(seq)
348
349 # Some methods don't match API for numpy RandomState.
350 # Commented out versions are not used by NetworkX
351
352 def sample(self, seq, k):
353 return self._rng.choice(list(seq), size=(k,), replace=False)
354
355 def randint(self, a, b):
356 return self._rng.randint(a, b + 1)
357
358 # exponential as expovariate with 1/argument,
359 def expovariate(self, scale):
360 return self._rng.exponential(1 / scale)
361
362 # pareto as paretovariate with 1/argument,
363 def paretovariate(self, shape):
364 return self._rng.pareto(shape)
365
366
367 # weibull as weibullvariate multiplied by beta,
368 # def weibullvariate(self, alpha, beta):
369 # return self._rng.weibull(alpha) * beta
370 #
371 # def triangular(self, low, high, mode):
372 # return self._rng.triangular(low, mode, high)
373 #
374 # def choices(self, seq, weights=None, cum_weights=None, k=1):
375 # return self._rng.choice(seq
376
377
378 def create_py_random_state(random_state=None):
379 """Returns a random.Random instance depending on input.
380
381 Parameters
382 ----------
383 random_state : int or random number generator or None (default=None)
384 If int, return a random.Random instance set with seed=int.
385 if random.Random instance, return it.
386 if None or the `random` package, return the global random number
387 generator used by `random`.
388 if np.random package, return the global numpy random number
389 generator wrapped in a PythonRandomInterface class.
390 if np.random.RandomState instance, return it wrapped in
391 PythonRandomInterface
392 if a PythonRandomInterface instance, return it
393 """
394 import random
395
396 try:
397 import numpy as np
398
399 if random_state is np.random:
400 return PythonRandomInterface(np.random.mtrand._rand)
401 if isinstance(random_state, np.random.RandomState):
402 return PythonRandomInterface(random_state)
403 if isinstance(random_state, PythonRandomInterface):
404 return random_state
405 except ImportError:
406 pass
407
408 if random_state is None or random_state is random:
409 return random._inst
410 if isinstance(random_state, random.Random):
411 return random_state
412 if isinstance(random_state, int):
413 return random.Random(random_state)
414 msg = f"{random_state} cannot be used to generate a random.Random instance"
415 raise ValueError(msg)