ialdev-core 0.1.0__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.
Files changed (48) hide show
  1. iad/core/__init__.py +9 -0
  2. iad/core/array.py +1961 -0
  3. iad/core/binary.py +377 -0
  4. iad/core/cache.py +903 -0
  5. iad/core/codetools.py +203 -0
  6. iad/core/datatools.py +671 -0
  7. iad/core/docs/locators.ipynb +754 -0
  8. iad/core/dotstyle.py +99 -0
  9. iad/core/env.py +271 -0
  10. iad/core/events.py +650 -0
  11. iad/core/filesproc.py +1046 -0
  12. iad/core/fnctools.py +390 -0
  13. iad/core/label.py +240 -0
  14. iad/core/logs.py +182 -0
  15. iad/core/nptools.py +449 -0
  16. iad/core/one_dark.puml +881 -0
  17. iad/core/param/__init__.py +17 -0
  18. iad/core/param/confargparse.py +55 -0
  19. iad/core/param/paramaze.py +339 -0
  20. iad/core/param/tbox.py +277 -0
  21. iad/core/paths.py +563 -0
  22. iad/core/pdtools.py +2570 -0
  23. iad/core/pydantools/__init__.py +5 -0
  24. iad/core/pydantools/fixed_pydantic_yaml/__init__.py +32 -0
  25. iad/core/pydantools/fixed_pydantic_yaml/compat/__init__.py +0 -0
  26. iad/core/pydantools/fixed_pydantic_yaml/compat/hacks.py +76 -0
  27. iad/core/pydantools/fixed_pydantic_yaml/compat/old_enums.py +37 -0
  28. iad/core/pydantools/fixed_pydantic_yaml/compat/representers.py +92 -0
  29. iad/core/pydantools/fixed_pydantic_yaml/compat/types.py +122 -0
  30. iad/core/pydantools/fixed_pydantic_yaml/compat/yaml_lib.py +104 -0
  31. iad/core/pydantools/fixed_pydantic_yaml/ext/__init__.py +1 -0
  32. iad/core/pydantools/fixed_pydantic_yaml/ext/semver.py +152 -0
  33. iad/core/pydantools/fixed_pydantic_yaml/ext/versioned_model.py +113 -0
  34. iad/core/pydantools/fixed_pydantic_yaml/main.py +30 -0
  35. iad/core/pydantools/fixed_pydantic_yaml/mixin.py +281 -0
  36. iad/core/pydantools/fixed_pydantic_yaml/model.py +20 -0
  37. iad/core/pydantools/fixed_pydantic_yaml/py.typed +1 -0
  38. iad/core/pydantools/fixed_pydantic_yaml/version.py +1 -0
  39. iad/core/pydantools/models.py +560 -0
  40. iad/core/regexp.py +348 -0
  41. iad/core/short.py +308 -0
  42. iad/core/strings.py +635 -0
  43. iad/core/unc_panda.py +270 -0
  44. iad/core/units.py +58 -0
  45. iad/core/wrap.py +420 -0
  46. ialdev_core-0.1.0.dist-info/METADATA +73 -0
  47. ialdev_core-0.1.0.dist-info/RECORD +48 -0
  48. ialdev_core-0.1.0.dist-info/WHEEL +4 -0
iad/core/binary.py ADDED
@@ -0,0 +1,377 @@
1
+ import logging
2
+ import warnings
3
+ from math import *
4
+
5
+ import numpy as np
6
+
7
+ _log = logging.getLogger(__name__)
8
+
9
+
10
+ class Bin(int):
11
+ @staticmethod
12
+ def _test_range(val, bits):
13
+ val_bits = int(val).bit_length()
14
+ if bits and bits < val_bits:
15
+ raise ValueError('%d bits of %d exceeds bits limit of %d' % (val_bits, val, bits))
16
+
17
+ def __new__(cls, val, bits=None):
18
+ if hasattr(val, '__len__'):
19
+ return np.array([Bin(v, bits) for v in val], dtype='O')
20
+ Bin._test_range(val, bits)
21
+ return super(Bin, cls).__new__(cls, val)
22
+
23
+ def __init__(self, _, bits: object = None):
24
+ self.bits = bits # type: int
25
+
26
+ def __str__(self):
27
+ return bstr(int(self), bits=self.bits, dec=True)
28
+
29
+ def __repr__(self):
30
+ return self.__str__()
31
+
32
+ def __add__(self, other):
33
+ return Bin(int(self) + int(other),
34
+ max(bits_num(self), bits_num(other)) + 1
35
+ if self.bits or isinstance(other, Bin) and other.bits else None)
36
+
37
+ def __radd__(self, other):
38
+ return self.__add__(other)
39
+
40
+ def __sub__(self, other):
41
+ return Bin(int(self) - int(other),
42
+ max(bits_num(self), bits_num(other)) + 1
43
+ if self.bits or isinstance(other, Bin) and other.bits else None)
44
+
45
+ def __rsub__(self, other):
46
+ return Bin(int(other) - int(self),
47
+ max(bits_num(self), bits_num(other)) + 1
48
+ if self.bits or isinstance(other, Bin) and other.bits else None)
49
+
50
+ def __mul__(self, other):
51
+ return Bin(int(self) * int(other),
52
+ bits_num(self) + bits_num(other)
53
+ if self.bits or isinstance(other, Bin) and other.bits else None)
54
+
55
+ def __rmul__(self, other):
56
+ return self.__mul__(other)
57
+
58
+ def __lshift__(self, n: int):
59
+ return Bin(int(self) << n, self.bits + n if self.bits else None)
60
+
61
+ def __rshift__(self, n):
62
+ return Bin(int(self) >> n, self.bits - n if self.bits else None)
63
+
64
+ def __floordiv__(self, other):
65
+ return Bin(int(self) // int(other),
66
+ (self.bits if isinstance(other, Bin) else (2**self.bits-1) // int(other))
67
+ if self.bits else None)
68
+
69
+ def __rfloordiv__(self, other):
70
+ return Bin(int(other) // int(self), bits_num(other))
71
+
72
+ def __truediv__(self, other):
73
+ raise NotImplementedError('True Division not implemented for Bin')
74
+
75
+ def __pow__(self, n: int):
76
+ return Bin(int(self) ** n, self.bits * n if self.bits else None)
77
+
78
+
79
+ def set_bits(reg_val, field_val, start_bit, bit_len):
80
+ """ Set bit field of bit_len (start_bit - included) to the reg_val
81
+
82
+ :param reg_val: initial value - a number of integer type
83
+ :param field_val: field value to be set
84
+ :param start_bit: the first bit of field
85
+ :param bit_len: number of field bits
86
+ :return: final reg_val
87
+ """
88
+ # mask = ~(((1 << bit_len) - 1) << start_bit)
89
+ # if field_val < 0:
90
+ # field_val &= 0xffffffff
91
+ # return (reg_val & mask) | (field_val << start_bit)
92
+
93
+ mask_f = (1 << bit_len) - 1
94
+ if field_val < 0:
95
+ field_val &= mask_f
96
+ mask_0 = ~(mask_f << start_bit)
97
+ return (reg_val & mask_0) | (field_val << start_bit)
98
+
99
+
100
+ def get_bits(data, start_bit, bit_len):
101
+ """ Extract bit field of bit_len (start_bit - included) from the data
102
+
103
+ :param data: a number of integer type
104
+ :param start_bit: the first bit to extract
105
+ :param bit_len: number of bits to extract
106
+ :return: resulted data
107
+ """
108
+ mask = (1 << bit_len) - 1
109
+ return (data >> start_bit) & mask
110
+
111
+
112
+ def extract_bits(data, lsb, msb):
113
+ """ Eextract specific range of bits (from lsb to msb - included) from the data
114
+
115
+ :param data: a number of ndarray (integer types)
116
+ :param lsb: the first bit to extract
117
+ :param msb: the last bit to extract
118
+ :return: resulted data
119
+ """
120
+ return (((1 << (msb - lsb + 1)) - 1) << lsb & data) >> lsb
121
+
122
+
123
+ def split_bits(data, bits):
124
+ """ Extract data channels encoded in bits into separate arrays
125
+
126
+ :param data: ndarray or number (integer types)
127
+ :param bits: numbers of bits in each array - from low to high
128
+ :return:
129
+ """
130
+ if isinstance(data, np.ndarray) and data.dtype.kind not in ['i', 'u']:
131
+ raise TypeError('Integer type expected')
132
+
133
+ offsets = None
134
+ if type(bits[0]) == tuple:
135
+ offsets = list(list(zip(*bits))[1])
136
+ bits = list(list(zip(*bits))[0])
137
+
138
+ res, off = [], 0
139
+ for i, b in enumerate(bits):
140
+ if offsets is not None:
141
+ off = offsets[i]
142
+ res.append((((1 << b) - 1) << off & data) >> off)
143
+ off += b
144
+ return res
145
+
146
+
147
+ def check_valid_offsets(zip_bits):
148
+ """ Check whether the offsets and the bit numbers are valid
149
+
150
+ :param zip_bits: list of tuples in the fio [(stream_bits_size, stream_offset), ...]
151
+ :return:
152
+ """
153
+ zip_bits = sorted(zip_bits, key=lambda x: x[1])
154
+ print(zip_bits)
155
+ for i in range(len(zip_bits)-1):
156
+ if sum(zip_bits[i]) > zip_bits[i+1][1]:
157
+ raise AssertionError('You are writing twice on the same place..')
158
+
159
+
160
+ def join_bits(bits, streams, check_clip=False):
161
+ """ Pack together bits of the streams
162
+
163
+ :param bits:
164
+ :param streams:
165
+ :param check_clip:
166
+ :param offsets: pre-known offsets of the bits. same fio like bits
167
+ :return:
168
+ """
169
+ assert len(bits) == len(streams)
170
+
171
+ offsets = None
172
+ if type(bits[0]) == tuple:
173
+ check_valid_offsets(bits)
174
+ offsets = list(list(zip(*bits))[1])
175
+ bits = list(list(zip(*bits))[0])
176
+
177
+ res = np.zeros_like(streams[0], dtype='uint64')
178
+ shift = 0
179
+ for i,b in enumerate(bits):
180
+ a = streams[i]
181
+ masked_a = a & max_val(b)
182
+ if check_clip and (masked_a != a).any():
183
+ raise OverflowError('bitwise and clipped values')
184
+ if offsets is not None:
185
+ shift = offsets[i]
186
+ res |= (masked_a.astype(res.dtype) << shift)
187
+ shift += b
188
+
189
+ if offsets is not None:
190
+ shift = max(offset + bit for offset, bit in zip(offsets,bits))
191
+ return res.astype(fit_bits_uint(shift))
192
+
193
+
194
+ def max_val(bits):
195
+ return 2**bits-1
196
+
197
+
198
+ def bits_num(val):
199
+ """ Count the minimal number of bits required to represent the given value
200
+
201
+ :param val:
202
+ :return: number of bits
203
+ """
204
+ return val.bits if isinstance(val, Bin) and val.bits else val.bit_length()
205
+
206
+
207
+ def bstr(num: int, bits=0, dec=0, msb=True, template='{dec}<{exc}{cnt}{bin}>'):
208
+ """ String representation of number in binary form.
209
+
210
+ Optionally decimal representation may be added.
211
+ If actual bits exceed declared number exclamation mark is added according to the template
212
+ Format template
213
+ :param num: the number to represent
214
+ :param bits: number of bits filled by 0 from the left
215
+ :param dec: positions for decimal representation. If not - will not appear
216
+ :param msb show position of the most significant bit
217
+ :param template: template for the output
218
+ :return: string representation
219
+ """
220
+
221
+ return template.format(
222
+ dec='{0:%d}' % dec if dec else '',
223
+ bin='{0:0%db}|%d' % (bits, bits) if bits else '{0:b}',
224
+ cnt='%d|' % int(num).bit_length() if msb and not bits else '',
225
+ exc='' if not bits or len(('{0:0%db}' % bits).format(num)) == bits else '!').format(num)
226
+
227
+
228
+ def encode_array(bits, a, range_weight=0.01, steps=500, show=False):
229
+ """ Encodes array of numbers into array of fixed bits elements
230
+ optimizing the bits utilization and encoding accuracy.
231
+
232
+ :param bits: number of bits to allocate for each element
233
+ :param a: array of numbers to encode
234
+ :param range_weight: factor diminishing cost of the range utilization
235
+ :param steps: number of steps (resolution of the search) range is [0 1.5*max_fitted]
236
+ :param show: if true displays some internals of the algorithms
237
+
238
+ Algorithm scans for a factor minimizing the total cost of the accuracy and range lost
239
+ after the original elements are multiplied by this factors and rounded to the required bits.
240
+ """
241
+
242
+ a_double = np.array(a, dtype='double')
243
+ max_rng = 2 ** bits - 1
244
+
245
+ # find index of a minimal non zero element
246
+ nzi = a_double.nonzero()[0]
247
+ mi = nzi[np.argmin(a_double[nzi])]
248
+ assert a[mi]
249
+
250
+ original_ratios = a_double / a_double.mean()
251
+
252
+ def pack(factor):
253
+ new_a = (a_double * factor).astype('uint64')
254
+ new_a[new_a > max_rng] = max_rng
255
+ return new_a
256
+
257
+ def rounding_error(factor):
258
+ a_k = pack(factor).astype('double')
259
+ avr = a_k.mean()
260
+ ratio_error = (((a_k / avr - original_ratios) * max_rng) ** 2).sum() if avr else np.inf
261
+ range_error = ((a_k - max_rng) ** 2).sum()
262
+ return np.array([ratio_error, range_error, ratio_error + range_weight * range_error])
263
+
264
+ k_range = np.arange(1, steps) * (max_rng * 1.5) / max(a_double) / (steps - 1)
265
+ errors = np.stack(np.vectorize(rounding_error, otypes='O')(k_range))
266
+
267
+ if show:
268
+ import matplotlib.pyplot as plt
269
+ plt.figure()
270
+ errors = np.sqrt(errors)
271
+ labels = ['ratio', 'range', 'total']
272
+
273
+ plt.plot(k_range, errors, '-')
274
+ plt.hold(True)
275
+ print('costs factor range total results')
276
+ print('-----------------------------------------------------')
277
+ y_max = 2 * np.nanmean(errors[errors < np.inf])
278
+ for j, label in zip(range(errors.shape[1]), labels):
279
+ i = np.argmin(errors[:, j])
280
+ k = k_range[i]
281
+ astr = ' '.join('{: 4g}'.format(x) for x in pack(k))
282
+ print(
283
+ '{}: {:.3f} {:.3f} {:.3f} [{} ]'.format(label, k, errors[i, 0], errors[i, 2], astr))
284
+ plt.plot(k_range[i], errors[i, j] + y_max * 0.02, 'v' + 'gbr'[j])
285
+ print('-----------------------------------------------------')
286
+ print('original values: [%s ]' % ' '.join('{: 4g}'.format(x) for x in a))
287
+ plt.ylim(0, y_max)
288
+ plt.xlim(k_range[[0, -1]])
289
+ plt.title('Bits Packing Errors')
290
+ plt.legend(labels)
291
+ plt.xlabel('coefficient (k)')
292
+ plt.ylabel('errors')
293
+ plt.show()
294
+
295
+ return Bin(pack(k_range[np.argmin(errors[:, 2])]), bits)
296
+
297
+
298
+ def align_type_bits(num_bits):
299
+ """ Align given bits to the bits of the minimal standard container type (8, 16, 32, 64)"""
300
+
301
+ if num_bits < 8:
302
+ return 8
303
+ elif num_bits > 64:
304
+ raise ValueError('%d exceeds maximal supported bits %d' % (num_bits, 64))
305
+ else:
306
+ return 2 ** ceil(log(num_bits, 2))
307
+
308
+
309
+ def fit_bits_uint(x):
310
+ """ Return numpy style type name of the minimal uint container for the given bits numbers."""
311
+ return 'uint%s' % align_type_bits(x)
312
+
313
+
314
+ def parse_fxp_bits(fxp_bits):
315
+ """ Parse fix bits string """
316
+ return [int(d) for d in fxp_bits.split('.')] if isinstance(fxp_bits, str) else fxp_bits
317
+
318
+
319
+ def to_fxp(data: np.ndarray, fxp_bits, inv_flp='max', inv_fxp='max_int'):
320
+ """ Convert data into fixed point fio - that is integer with last bits denoting a fractional part.
321
+ Convert invalid values if inv_fxp is not None.
322
+
323
+ :param data: any ndarray
324
+ :param fxp_bits: may be string ('8.6') or tuple-like (8, 6)
325
+ :param inv_flp: invalid code in the source data:
326
+ 'max' - maximal for this data type,
327
+ None - don't bother
328
+ or a specific value
329
+ :param inv_fxp: invalid data code in the output array:
330
+ 'max' - maximal integer value
331
+ 'max_int' - maximal integer part of the fixed point
332
+ None - don't convert invalids
333
+ or a specific value encoding the invalids
334
+ """
335
+ i_bits, f_bits = parse_fxp_bits(fxp_bits)
336
+ max_fxp = 2 ** (i_bits + f_bits) - 1
337
+ inv_options = {'max_int': 2 ** i_bits - 1, 'max': max_fxp}
338
+
339
+ if inv_flp == 'max':
340
+ inv_flp = np.finfo(data.dtype) if issubclass(data.dtype.type, np.float) else np.iinfo(data.dtype)
341
+ if inv_fxp in inv_options:
342
+ inv_fxp = inv_options[inv_fxp]
343
+ elif inv_fxp > max_fxp:
344
+ raise ValueError('Invalidation value %s exceeds the dynamic range %d' % (inv_fxp, max_fxp))
345
+
346
+ inv_mask = (data == inv_flp)
347
+ _log.info('Found %d invalids' % inv_mask.sum())
348
+
349
+ data *= 2 ** f_bits
350
+ sat_mask = (~inv_mask) * (data > max_fxp )
351
+ sat_num = sat_mask.sum()
352
+ if sat_num:
353
+ sat_range = (lambda sat: (sat.min(), sat.max()))(data[sat_mask])
354
+ warnings.warn('Conversion into %d.%d fio has saturated %d pixels in range %s.' %
355
+ (i_bits, f_bits, sat_num, sat_range))
356
+ data[sat_mask] = inv_fxp
357
+ if inv_fxp is not None:
358
+ data[inv_mask] = inv_fxp
359
+ return data.astype(fit_bits_uint(i_bits + f_bits))
360
+
361
+
362
+ if __name__ == '__main__':
363
+ pass
364
+
365
+ # Consider: to move testing to test_binar or remove
366
+ ba = np.random.randint(0, 4, size=(3, 4))
367
+ bb = np.random.randint(0, 8, size=(3, 4))
368
+
369
+ my_bits = [2, 3]
370
+
371
+ my_offsets = [3, 5]
372
+ my_bits = list(zip(my_bits, my_offsets))
373
+
374
+ joined = join_bits(my_bits, [ba, bb])
375
+ ra, rb = split_bits(joined, my_bits)
376
+
377
+ a=5