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.
- iad/core/__init__.py +9 -0
- iad/core/array.py +1961 -0
- iad/core/binary.py +377 -0
- iad/core/cache.py +903 -0
- iad/core/codetools.py +203 -0
- iad/core/datatools.py +671 -0
- iad/core/docs/locators.ipynb +754 -0
- iad/core/dotstyle.py +99 -0
- iad/core/env.py +271 -0
- iad/core/events.py +650 -0
- iad/core/filesproc.py +1046 -0
- iad/core/fnctools.py +390 -0
- iad/core/label.py +240 -0
- iad/core/logs.py +182 -0
- iad/core/nptools.py +449 -0
- iad/core/one_dark.puml +881 -0
- iad/core/param/__init__.py +17 -0
- iad/core/param/confargparse.py +55 -0
- iad/core/param/paramaze.py +339 -0
- iad/core/param/tbox.py +277 -0
- iad/core/paths.py +563 -0
- iad/core/pdtools.py +2570 -0
- iad/core/pydantools/__init__.py +5 -0
- iad/core/pydantools/fixed_pydantic_yaml/__init__.py +32 -0
- iad/core/pydantools/fixed_pydantic_yaml/compat/__init__.py +0 -0
- iad/core/pydantools/fixed_pydantic_yaml/compat/hacks.py +76 -0
- iad/core/pydantools/fixed_pydantic_yaml/compat/old_enums.py +37 -0
- iad/core/pydantools/fixed_pydantic_yaml/compat/representers.py +92 -0
- iad/core/pydantools/fixed_pydantic_yaml/compat/types.py +122 -0
- iad/core/pydantools/fixed_pydantic_yaml/compat/yaml_lib.py +104 -0
- iad/core/pydantools/fixed_pydantic_yaml/ext/__init__.py +1 -0
- iad/core/pydantools/fixed_pydantic_yaml/ext/semver.py +152 -0
- iad/core/pydantools/fixed_pydantic_yaml/ext/versioned_model.py +113 -0
- iad/core/pydantools/fixed_pydantic_yaml/main.py +30 -0
- iad/core/pydantools/fixed_pydantic_yaml/mixin.py +281 -0
- iad/core/pydantools/fixed_pydantic_yaml/model.py +20 -0
- iad/core/pydantools/fixed_pydantic_yaml/py.typed +1 -0
- iad/core/pydantools/fixed_pydantic_yaml/version.py +1 -0
- iad/core/pydantools/models.py +560 -0
- iad/core/regexp.py +348 -0
- iad/core/short.py +308 -0
- iad/core/strings.py +635 -0
- iad/core/unc_panda.py +270 -0
- iad/core/units.py +58 -0
- iad/core/wrap.py +420 -0
- ialdev_core-0.1.0.dist-info/METADATA +73 -0
- ialdev_core-0.1.0.dist-info/RECORD +48 -0
- 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
|