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/unc_panda.py ADDED
@@ -0,0 +1,270 @@
1
+ import warnings
2
+ from functools import wraps
3
+ from numbers import Number
4
+ from operator import itemgetter
5
+ from typing import Union
6
+
7
+ import numpy as np
8
+ import uncertainties as uncert
9
+ from uncertainties import unumpy as unp
10
+
11
+ from .pdtools import pd, DataTable
12
+
13
+ UV = Union[pd.DataFrame, pd.Series, np.ndarray, tuple, 'UncT']
14
+
15
+
16
+ class UncT(tuple):
17
+ def __new__(self, n, s=None):
18
+ if s is None:
19
+ n, s = split_unc(n)
20
+ #
21
+ # assert n.shape == s.shape
22
+ # assert not (is_unc_array(n) or is_unc_array(s) or is_unc_series(n) or is_unc_series(s))
23
+ # assert all(isinstance(n, t) and isinstance(s, t)
24
+ # for t in (pd.DataFrame, pd.Series, np.ndarray))
25
+ return tuple.__new__(UncT, (n, s))
26
+
27
+ def __repr__(self):
28
+ v = self.n
29
+ shape = "{}x{}".format(*v.shape) if v.ndim == 2 else f"{len(v)}"
30
+ return f"{self.__class__.__qualname__}<{self.n.__class__.__qualname__}>[{shape}]"
31
+
32
+ def __getattr__(self, item):
33
+ return UncT(getattr(self.n, item), getattr(self.s, item))
34
+
35
+ def join(self):
36
+ return join_unc(*self)
37
+
38
+ def __truediv__(self, other):
39
+ return divide(self, other)
40
+
41
+ def __mul__(self, other):
42
+ return multiply(self, other)
43
+
44
+ def __add__(self, other):
45
+ return add(self, other)
46
+
47
+ def __neg__(self):
48
+ return UncT(-self[0], self[1])
49
+
50
+ def __sub__(self, other):
51
+ return add(self, -other)
52
+
53
+ def __pow__(self, power, modulo=None):
54
+ return pow(self, power, sep=False)
55
+
56
+ def divide(self, other, axis=0, eps=0, sep=True):
57
+ return divide(self, other, axis=axis, eps=eps, sepr=sep)
58
+
59
+ def conv(self, other, axis=0, sep=True):
60
+ return conv(self, other, axis=axis, sep=sep)
61
+
62
+ def sum(self, axis=0, **kws):
63
+ return sum(self, axis=axis, **kws)
64
+
65
+
66
+ UncT.n = UncT.nominal_value = property(itemgetter(0))
67
+ UncT.s = UncT.std_dev = property(itemgetter(1))
68
+
69
+
70
+ def is_unc_array(v):
71
+ return isinstance(v, np.ndarray) and v.dtype == 'O' and isinstance(next(v.flat), uncert.UFloat)
72
+
73
+
74
+ def is_unc_series(s):
75
+ return isinstance(s, pd.Series) and s.dtype == 'O' and isinstance(s[0], uncert.UFloat)
76
+
77
+
78
+ def is_unc_df(s):
79
+ return isinstance(s, pd.DataFrame) and any(map(lambda _, x: is_unc_series(x), s.iteritems()))
80
+
81
+
82
+ def is_unc_cont(v):
83
+ return is_unc_series(v) or is_unc_array(v) or is_unc_df(v)
84
+
85
+
86
+ def join_unc(dfn, dfs, cls=None):
87
+ cls = cls or dfn.__class__
88
+ a = unp.uarray(dfn, dfs)
89
+ if isinstance(cls, np.ndarray):
90
+ return a
91
+ kws = dict(columns=dfn.columns) if isinstance(dfn, pd.DataFrame) else dict(name=dfn.name)
92
+ return cls(a, index=dfn.index, **kws)
93
+
94
+
95
+ def is_sep_array(v1):
96
+ return isinstance(v1, tuple) and isinstance(v1[0], np.ndarray)
97
+
98
+
99
+ def split_unc_df(df: pd.DataFrame):
100
+ recreate_table = lambda x: df.__class__._from_arrays(x, index=df.index, columns=df.columns)
101
+ return tuple(map(recreate_table, zip(*(
102
+ (sr.nominal_value, sr.std_dev) if is_unc_series(sr) else (sr, sr * 0)
103
+ for _, sr in df.iteritems()
104
+ ))))
105
+
106
+
107
+ def split_unc(v: UV):
108
+ return v if isinstance(v, tuple) else (
109
+ (unp.nominal_values(v), unp.std_devs(v)) if is_unc_array(v) else
110
+ (v.nominal_value, v.std_dev) if is_unc_series(v) else
111
+ split_unc_df(v) if isinstance(v, pd.DataFrame) else (v, 0)
112
+ )
113
+
114
+
115
+ def add(v1, v2, *, axis=0, sep=None):
116
+ oper = (lambda x, y: np.add(x, y)) if is_sep_array(v1) else (
117
+ lambda x, y: x.add(y, axis=axis))
118
+ err = lambda n1, s1, _, s2: (s1**2 + s2**2) ** 0.5
119
+ return bin_operation(v1, v2, oper, err=err, sep=sep)
120
+
121
+
122
+ def multiply(v1, v2, axis=0, *, sep=None):
123
+ oper = (lambda x, y: np.multiply(x, y)) if is_sep_array(v1)\
124
+ else (lambda x, y: x.multiply(y, axis=axis))
125
+ err = lambda n1, s1, n2, s2: (oper(s1**2, n2**2) + oper(s2**2, n1**2)) ** 0.5
126
+ return bin_operation(v1, v2, oper, err=err, sep=sep)
127
+
128
+
129
+ def divide(v1: UV, v2: UV, axis=0, *, eps=0, sep=None):
130
+ oper = (lambda x, y: np.true_divide(x+eps, y+eps)) if is_sep_array(v1)\
131
+ else (lambda x, y: (x+eps).divide(y+eps, axis=axis))
132
+ rel_err = lambda n1, s1, n2, s2: (oper(s1, n1) ** 2 + oper(s2, n2) ** 2) ** 0.5
133
+ return bin_operation(v1, v2, oper, rel_err=rel_err, sep=sep)
134
+
135
+
136
+ def pow(v1: UV, p: float, *, sep=None):
137
+ oper = lambda x, y: x**y
138
+ err = lambda n1, s1, n2, _: abs(n2 * n1**(n2-1)) * s1
139
+ return bin_operation(v1, (p, 0), oper, err=err, sep=sep)
140
+
141
+
142
+ def conv(v1: UV, v2: UV, axis=0, *, unc=True, sep=False):
143
+ """
144
+ Calculate multiple 1D convolutions with uncertainty along selected axis
145
+ between two sets of vectors provided as series, arrays or dataframes
146
+ each optionally containing the uncertainty component.
147
+
148
+ Uncertainty calculation and inclusion in the result may be disabled.
149
+ Type of the result is DataTable or array (if both inputs are arrays)
150
+
151
+ Shape of the result is D1 x D2, where D* are lengths of non-convolved
152
+ dimensions in first and second inputs.
153
+
154
+ Inputs must have same alignment of the convolution axis, same
155
+ length and same index (if its a series or a dataframe)
156
+
157
+ :param v1: first set of vectors
158
+ :param v2: first set of vectors
159
+ :param axis: axis to sum along - must match actual dimension!
160
+ :param unc: if False disables uncertainty calculations
161
+ :param sep: if True return as a UncT tuple (n, s)
162
+ :return: D1 x D2 DataTable or array
163
+ """
164
+ assert axis in (0, 1)
165
+ assert v1.shape[axis] == v2.shape[axis], f"inputs must have size along {axis} dimension"
166
+
167
+ array_inputs = isinstance(v1, np.ndarray) + 2*isinstance(v2, np.ndarray)
168
+ if not array_inputs: # series and frames, index must match!
169
+ v1, v2 = map(lambda x: x.to_frame() if isinstance(x, pd.Series) else x, (v1, v2))
170
+ v2 = v2.loc[:, v1.columns] if axis else v2.loc[v1.index, :]
171
+ if array_inputs in (1, 2): # convert to DataTable unless ALL the inputs are arrays
172
+ v1, v2 = map(lambda x: DataTable(x) if isinstance(x, np.ndarray) else x, (v1, v2))
173
+
174
+ # convert to numpy arrays
175
+ n1, s1 = split_unc(v1)
176
+ n2, s2 = split_unc(v2)
177
+ n1, n2, s1, s2 = map(lambda x: x.to_numpy(), (n1, n2, s1, s2))
178
+
179
+ if axis == 0: # transpose for matrix multiplication
180
+ n1, s1 = n1.T, s1.T
181
+ else:
182
+ n2, s2 = n2.T, s2.T
183
+
184
+ a = n = n1 @ n2
185
+ if unc:
186
+ s = ((s1**2)@(n2**2) + (n1**2)@(s2**2)) ** 0.5
187
+ if not sep:
188
+ with warnings.catch_warnings():
189
+ warnings.filterwarnings('ignore', r'invalid value')
190
+ a = unp.uarray(n, s)
191
+
192
+ if array_inputs == 3:
193
+ return (UncT(n, s) if unc else n) if sep else a
194
+
195
+ iax = 1 - axis # the other axis
196
+ return (UncT(DataTable(n, index=v1.axes[iax], columns=v2.axes[iax]),
197
+ DataTable(s, index=v1.axes[iax], columns=v2.axes[iax])
198
+ ) if unc else
199
+ DataTable(n, index=v1.axes[iax], columns=v2.axes[iax])
200
+ ) if sep else DataTable(a, index=v1.axes[iax], columns=v2.axes[iax])
201
+
202
+
203
+ def sum(v: UV, axis=0, **kws):
204
+ n, s = split_unc(v)
205
+ return join_unc(n.sum(axis=axis, **kws), (s**2).sum(axis=axis, **kws)**0.5)
206
+
207
+
208
+ UncT.add = add
209
+ UncT.divide = divide
210
+ UncT.multiply = multiply
211
+ UncT.conv = conv
212
+ UncT.pow = pow
213
+
214
+
215
+ def bin_operation(v1: UV, v2: UV, func, *, err=None, rel_err=None, sep=None):
216
+ assert err is None or rel_err is None
217
+ n1, s1 = split_unc(v1)
218
+ n2, s2 = split_unc(v2)
219
+
220
+ n = func(n1, n2)
221
+ s = err(n1, s1, n2, s2) if err else rel_err(n1, s1, n2, s2) * abs(n)
222
+
223
+ if sep is None:
224
+ sep = isinstance(v1, tuple) and (isinstance(v2, tuple) or
225
+ isinstance(v2, Number) or
226
+ not is_unc_cont(v2))
227
+ if sep:
228
+ return UncT(n, s)
229
+
230
+ if isinstance(n, Number):
231
+ return uncert.core.ufloat(n, s)
232
+
233
+ with warnings.catch_warnings():
234
+ warnings.filterwarnings('ignore', r'invalid value')
235
+ res = unp.uarray(n, s)
236
+
237
+ if isinstance(n, pd.Series):
238
+ return n.__class__(res, index=n.index, name=n.name)
239
+
240
+ if isinstance(n, pd.DataFrame):
241
+ return n.__class__(res, index=n.index, columns=n.columns)
242
+
243
+ if isinstance(n, np.ndarray):
244
+ return res
245
+
246
+ raise TypeError(f"Unsupported type: {type(n)}")
247
+
248
+
249
+ def strip_unc(v: UV):
250
+ if is_unc_series(v, tuple):
251
+ return v[0]
252
+ if is_unc_array(v):
253
+ return unp.nominal_values(v)
254
+ if isinstance(v, np.ndarray):
255
+ return v
256
+ return v.nominal_value # series or frame
257
+
258
+
259
+ def unc_func(f):
260
+ @wraps(f)
261
+ def uf(x, *args, **kws):
262
+ if is_unc_series(x):
263
+ return x.__class__(f(x.values, *args, unc=True, **kws), index=x.index, name=x.name)
264
+ if isinstance(x, pd.DataFrame):
265
+ return x.apply(lambda s: f(s.values, *args, unc=is_unc_series(s), **kws))
266
+ if isinstance(x, uncert.UFloat) or is_unc_array(x):
267
+ return f(x, *args, unc=True, **kws)
268
+ return f(x, *args, **kws)
269
+
270
+ return uf
iad/core/units.py ADDED
@@ -0,0 +1,58 @@
1
+ import warnings
2
+ from typing import Union
3
+
4
+ import numpy as np
5
+ import pint
6
+
7
+ un = pint.UnitRegistry(auto_reduce_dimensions=True)
8
+ # print(f'--- init units reg {id(un)}!')
9
+ Q_ = Quantity = un.Quantity
10
+
11
+
12
+ def isQ(x):
13
+ return isinstance(x, pint.Quantity)
14
+
15
+
16
+ def is_array(x):
17
+ """ Check if its any kind of array """
18
+ return isinstance(x, pint.Quantity) and isinstance(x.magnitude, np.ndarray) \
19
+ or isinstance(x, np.ndarray)
20
+
21
+
22
+ def magnitude(x):
23
+ """Safely return magnitude even if not a Quantity"""
24
+ return x.m if isinstance(x, pint.Quantity) else x
25
+
26
+
27
+ def __format__(self, spec):
28
+ if isinstance(self.magnitude, np.ndarray) and self.magnitude.size > 32:
29
+ units = '{:~P}'.format(self.units)
30
+ a = self.magnitude
31
+ nans_num = np.isnan(a).sum()
32
+ metrics = "" if a.size == nans_num else \
33
+ "\u2208 [{:{fmt}}, {:{fmt}}] <{:{fmt}}> \u03c3={:{fmt}} ".format(
34
+ np.nanmin(a), np.nanmax(a), np.nanmean(a), np.nanstd(a),
35
+ fmt=".4" if a.dtype.kind == 'f' else '')
36
+ metrics += f"({nans_num / a.size:.1%} nans)" * int(nans_num > 0)
37
+ return f"[{a.shape[0]}x{a.shape[1]}]{units} ({a.dtype}) {metrics}"
38
+ return pint.Quantity.__format__(self, spec)
39
+
40
+
41
+ Quantity.__format__ = __format__
42
+ with warnings.catch_warnings():
43
+ warnings.simplefilter("ignore")
44
+ Quantity([])
45
+
46
+
47
+ def assign_units(q, u: Union[float, str, pint.Quantity]) -> pint.Quantity:
48
+ """Assign units to the value """
49
+ if u != 1:
50
+ if not hasattr(q, 'units'):
51
+ if isinstance(u, str):
52
+ u = un(u)
53
+ elif not hasattr(u, 'units'):
54
+ raise TypeError('Invalid type of units arg. Expected Pint')
55
+ q = q * u
56
+ elif u.units != q.units:
57
+ raise ValueError(f"Can't apply units {u.units} on quantity with {q}")
58
+ return q