richvalues 4.2.0__tar.gz → 4.2.2__tar.gz
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.
- {richvalues-4.2.0 → richvalues-4.2.2}/LICENSE +1 -1
- {richvalues-4.2.0 → richvalues-4.2.2}/PKG-INFO +1 -1
- {richvalues-4.2.0 → richvalues-4.2.2}/pyproject.toml +1 -1
- {richvalues-4.2.0 → richvalues-4.2.2}/richvalues/__init__.py +164 -100
- {richvalues-4.2.0 → richvalues-4.2.2}/richvalues.egg-info/PKG-INFO +1 -1
- {richvalues-4.2.0 → richvalues-4.2.2}/setup.py +1 -1
- {richvalues-4.2.0 → richvalues-4.2.2}/README.md +0 -0
- {richvalues-4.2.0 → richvalues-4.2.2}/richvalues.egg-info/SOURCES.txt +0 -0
- {richvalues-4.2.0 → richvalues-4.2.2}/richvalues.egg-info/dependency_links.txt +0 -0
- {richvalues-4.2.0 → richvalues-4.2.2}/richvalues.egg-info/requires.txt +0 -0
- {richvalues-4.2.0 → richvalues-4.2.2}/richvalues.egg-info/top_level.txt +0 -0
- {richvalues-4.2.0 → richvalues-4.2.2}/setup.cfg +0 -0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "richvalues"
|
7
|
-
version = "4.2.
|
7
|
+
version = "4.2.2"
|
8
8
|
description = "Python library for working with uncertainties and upper/lower limits"
|
9
9
|
license = {file="LICENSE"}
|
10
10
|
authors = [{name="Andrés Megías Toledano"}]
|
@@ -6,19 +6,19 @@ Rich Values Library
|
|
6
6
|
-------------------
|
7
7
|
Version 4.2
|
8
8
|
|
9
|
-
Copyright (C)
|
9
|
+
Copyright (C) 2025 - Andrés Megías Toledano
|
10
10
|
|
11
11
|
Redistribution and use in source and binary forms, with or without
|
12
12
|
modification, are permitted provided that the following conditions are
|
13
13
|
met:
|
14
14
|
|
15
15
|
(1) Redistributions of source code must retain the above copyright
|
16
|
-
notice, this list of conditions and the following disclaimer.
|
16
|
+
notice, this list of conditions and the following disclaimer.
|
17
17
|
|
18
18
|
(2) Redistributions in binary form must reproduce the above copyright
|
19
19
|
notice, this list of conditions and the following disclaimer in
|
20
20
|
the documentation and/or other materials provided with the
|
21
|
-
distribution.
|
21
|
+
distribution.
|
22
22
|
|
23
23
|
(3) The name of the author may not be used to endorse or promote
|
24
24
|
products derived from this software without specific prior written
|
@@ -37,7 +37,7 @@ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
37
37
|
POSSIBILITY OF SUCH DAMAGE.
|
38
38
|
"""
|
39
39
|
|
40
|
-
__version__ = '4.2.
|
40
|
+
__version__ = '4.2.2'
|
41
41
|
__author__ = 'Andrés Megías Toledano'
|
42
42
|
|
43
43
|
import copy
|
@@ -275,7 +275,8 @@ def round_sf_unc(x, dx, n=None, min_exp=None, max_dec=None, extra_sf_lim=None):
|
|
275
275
|
y = '{}e{}'.format(base_y, exp_dy)
|
276
276
|
else:
|
277
277
|
f = 10**(-int(exp_y))
|
278
|
-
base_y, base_dy = round_sf_unc(x*f, dx*f, n,
|
278
|
+
base_y, base_dy = round_sf_unc(x*f, dx*f, n,
|
279
|
+
np.inf, max_dec, extra_sf_lim)
|
279
280
|
y = '{}e{}'.format(base_y, exp_y)
|
280
281
|
dy = '{}e{}'.format(base_dy, exp_y)
|
281
282
|
if len(dy) > len(y)+1:
|
@@ -311,7 +312,8 @@ def round_sf_unc(x, dx, n=None, min_exp=None, max_dec=None, extra_sf_lim=None):
|
|
311
312
|
else:
|
312
313
|
exp = None
|
313
314
|
d = len(y.split('.')[-1])
|
314
|
-
|
315
|
+
d_ = len(dy.split('.')[-1])
|
316
|
+
dy_ = round_sf(float(dy)*10**(d-d_), n, 0, extra_sf_lim)
|
315
317
|
dy = '(' + dy_.split('e')[0] + ')'
|
316
318
|
if exp is not None:
|
317
319
|
y = '{}e{}'.format(y, exp)
|
@@ -354,45 +356,48 @@ def round_sf_uncs(x, dx, n=None, min_exp=None, max_dec=None, extra_sf_lim=None):
|
|
354
356
|
dx1, dx2 = dx
|
355
357
|
y1, dy1 = round_sf_unc(x, dx1, n, min_exp, max_dec, extra_sf_lim)
|
356
358
|
y2, dy2 = round_sf_unc(x, dx2, n, min_exp, max_dec, extra_sf_lim)
|
357
|
-
if
|
358
|
-
|
359
|
-
y1, dy1 = round_sf_unc(x, dx1, n, min_exp, max_dec, extra_sf_lim)
|
360
|
-
y2, dy2 = round_sf_unc(x, dx2, n, min_exp, max_dec, extra_sf_lim)
|
361
|
-
num_dec_1 = len(y1.split('e')[0].split('.')[1]) if '.' in y1 else 0
|
362
|
-
num_dec_2 = len(y2.split('e')[0].split('.')[1]) if '.' in y2 else 0
|
363
|
-
if num_dec_2 > num_dec_1:
|
364
|
-
diff = num_dec_2 - num_dec_1
|
365
|
-
y1, dy1 = round_sf_unc(x, dx1, n+diff, min_exp, max_dec, extra_sf_lim)
|
366
|
-
y2, dy2 = round_sf_unc(x, dx2, n, min_exp, max_dec, extra_sf_lim)
|
359
|
+
if y1 == y2 and dy1 == dy2:
|
360
|
+
y = y1
|
367
361
|
else:
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
if
|
393
|
-
|
394
|
-
|
395
|
-
dy2 = '(
|
362
|
+
if 'e' in y1 and 'e' not in y2 or 'e' in y2 and 'e' not in y1:
|
363
|
+
min_exp = 0
|
364
|
+
y1, dy1 = round_sf_unc(x, dx1, n, min_exp, max_dec, extra_sf_lim)
|
365
|
+
y2, dy2 = round_sf_unc(x, dx2, n, min_exp, max_dec, extra_sf_lim)
|
366
|
+
num_dec_1 = len(y1.split('e')[0].split('.')[1]) if '.' in y1 else 0
|
367
|
+
num_dec_2 = len(y2.split('e')[0].split('.')[1]) if '.' in y2 else 0
|
368
|
+
if num_dec_2 > num_dec_1:
|
369
|
+
diff = num_dec_2 - num_dec_1
|
370
|
+
y1, dy1 = round_sf_unc(x, dx1, n+diff, min_exp, max_dec, extra_sf_lim)
|
371
|
+
y2, dy2 = round_sf_unc(x, dx2, n, min_exp, max_dec, extra_sf_lim)
|
372
|
+
else:
|
373
|
+
diff = num_dec_1 - num_dec_2
|
374
|
+
off1, off2 = 0, 0
|
375
|
+
if num_dec_1 == 0 == num_dec_2:
|
376
|
+
base_dy1 = '{:e}'.format(dx1).split('e')[0]
|
377
|
+
base_dy2 = '{:e}'.format(dx2).split('e')[0]
|
378
|
+
b1 = float(base_dy1) if np.isfinite(dx1) else 10.
|
379
|
+
b2 = float(base_dy2) if np.isfinite(dx2) else 10.
|
380
|
+
if dx2 > dx1 and b1 <= extra_sf_lim and b2 > extra_sf_lim:
|
381
|
+
off2 = 1
|
382
|
+
if dx1 > dx2 and b2 <= extra_sf_lim and b1 > extra_sf_lim:
|
383
|
+
off1 = 1
|
384
|
+
y1, dy1 = round_sf_unc(x, dx1, n+off1, min_exp, max_dec, extra_sf_lim)
|
385
|
+
y2, dy2 = round_sf_unc(x, dx2, n+diff+off2, min_exp, max_dec, extra_sf_lim)
|
386
|
+
y = y1 if dx2 > dx1 else y2
|
387
|
+
if dy1 != dy2 and (')' in dy1 or ')' in dy2):
|
388
|
+
dy1 = dy1.replace('(', '(-')
|
389
|
+
dy2 = dy2.replace('(', '(+')
|
390
|
+
if ')' in dy1 and ')' not in dy2 or ')' in dy2 and '.' in dy2:
|
391
|
+
_, dy2 = round_sf_unc(x, dx[1], n, min_exp, max_dec-1, extra_sf_lim)
|
392
|
+
dy2 = '(' + dy2[1:-1] + '0' + ')'
|
393
|
+
elif ')' in dy2 and ')' not in dy1 or ')' in dy1 and '.' in dy1:
|
394
|
+
_, dy1 = round_sf_unc(x, dx[0], n, min_exp, max_dec-1, extra_sf_lim)
|
395
|
+
dy1 = '(' + dy1[1:-1] + '0' + ')'
|
396
|
+
if ')' in dy1 or ')' in dy2:
|
397
|
+
if not dy1.startswith('(-'):
|
398
|
+
dy1 = '(-' + dy1[1:]
|
399
|
+
if not dy2.startswith('(+'):
|
400
|
+
dy2 = '(+' + dy2[1:]
|
396
401
|
dy = [dy1, dy2]
|
397
402
|
return y, dy
|
398
403
|
|
@@ -592,6 +597,15 @@ class RichValue():
|
|
592
597
|
x = [x, x]
|
593
598
|
x = list(x)
|
594
599
|
self._unc = x
|
600
|
+
global variable_count
|
601
|
+
variable_count += 1
|
602
|
+
variable = 'x{}'.format(variable_count)
|
603
|
+
variables = [variable]
|
604
|
+
expression = variable
|
605
|
+
self.variables = variables
|
606
|
+
self.expression = expression
|
607
|
+
global variable_dict
|
608
|
+
variable_dict[expression] = self
|
595
609
|
|
596
610
|
@property
|
597
611
|
def is_lim(self):
|
@@ -618,11 +632,11 @@ class RichValue():
|
|
618
632
|
"""Constant value."""
|
619
633
|
isconst = self.is_exact and self.domain[0] == self.domain[1]
|
620
634
|
return isconst
|
621
|
-
@property
|
635
|
+
@property
|
622
636
|
def center(self):
|
623
637
|
"""Central value."""
|
624
638
|
cent = self.main if self.is_centr else np.nan
|
625
|
-
return cent
|
639
|
+
return cent
|
626
640
|
@property
|
627
641
|
def unc_eb(self):
|
628
642
|
"""Uncertainties with shape (2,1)."""
|
@@ -649,7 +663,7 @@ class RichValue():
|
|
649
663
|
else:
|
650
664
|
s_n = [np.nan]*2
|
651
665
|
return s_n
|
652
|
-
@property
|
666
|
+
@property
|
653
667
|
def ampl(self):
|
654
668
|
"""Amplitudes."""
|
655
669
|
m, b = self.main, self.domain
|
@@ -675,14 +689,23 @@ class RichValue():
|
|
675
689
|
s_a = [np.nan]*2
|
676
690
|
return s_a
|
677
691
|
@property
|
692
|
+
def unc_asymmetry(self):
|
693
|
+
"""Asymmetry of the uncertainties, as its maximum ratio."""
|
694
|
+
if self.is_centr:
|
695
|
+
s1, s2 = np.abs(self.unc)
|
696
|
+
f = max(s1/s2, s2/s1)
|
697
|
+
return f
|
698
|
+
@property
|
678
699
|
def prop_score(self):
|
679
|
-
"""
|
700
|
+
"""Propagation score, to determine the non-normal behaviour."""
|
680
701
|
if self.is_exact:
|
681
702
|
ps = np.inf
|
682
703
|
elif self.is_centr:
|
683
704
|
s_n = self.signal_noise
|
684
705
|
a_s = self.rel_ampl
|
685
706
|
ps = np.min([s_n, a_s])
|
707
|
+
f = self.unc_asymmetry
|
708
|
+
ps /= (1. + 8.*(f-1.))
|
686
709
|
else:
|
687
710
|
ps = 0.
|
688
711
|
return ps
|
@@ -761,7 +784,7 @@ class RichValue():
|
|
761
784
|
m = np.nanmedian(distr)
|
762
785
|
else:
|
763
786
|
m = np.nan
|
764
|
-
return m
|
787
|
+
return m
|
765
788
|
|
766
789
|
def mean(self, num_points=int(1e4), sigmas=8.):
|
767
790
|
"""Mean of the PDF of the rich value."""
|
@@ -817,7 +840,7 @@ class RichValue():
|
|
817
840
|
y = self.pdf(x)
|
818
841
|
c = np.trapz(y*x, x) if central or standarized else 0.
|
819
842
|
s = np.sqrt(np.trapz(y*(x-c)**2)) if standarized else 1.
|
820
|
-
moment = np.trapz((y*(x-c)**n)) / s**n
|
843
|
+
moment = np.trapz((y*(x-c)**n)) / s**n
|
821
844
|
else:
|
822
845
|
moment = np.nan
|
823
846
|
return moment
|
@@ -1071,7 +1094,7 @@ class RichValue():
|
|
1071
1094
|
else:
|
1072
1095
|
if is_lolim:
|
1073
1096
|
symbol = '>'
|
1074
|
-
y = int(np.floor(x)) if is_int else x
|
1097
|
+
y = int(np.floor(x)) if is_int else x
|
1075
1098
|
elif is_uplim:
|
1076
1099
|
symbol = '<'
|
1077
1100
|
y = int(np.ceil(x)) if is_int else x
|
@@ -1121,10 +1144,10 @@ class RichValue():
|
|
1121
1144
|
else:
|
1122
1145
|
if is_lolim:
|
1123
1146
|
symbol = '>'
|
1124
|
-
y = int(np.floor(x)) if is_int else x
|
1147
|
+
y = int(np.floor(x)) if is_int else x
|
1125
1148
|
elif is_uplim:
|
1126
1149
|
symbol = '<'
|
1127
|
-
y = int(np.ceil(x)) if is_int else x
|
1150
|
+
y = int(np.ceil(x)) if is_int else x
|
1128
1151
|
y = round_sf(y, n, min_exp, extra_sf_lim)
|
1129
1152
|
if 'e' in y:
|
1130
1153
|
y, a = y.split('e')
|
@@ -1388,27 +1411,27 @@ class RichValue():
|
|
1388
1411
|
|
1389
1412
|
def __floordiv__(self, other):
|
1390
1413
|
type_other = str(type(other))
|
1391
|
-
other_ = (RichValue(other, is_int=(type(other)
|
1414
|
+
other_ = (RichValue(other, is_int=('int' in str(type(other))))
|
1392
1415
|
if 'int' in type_other or 'float' in type_other else other)
|
1393
1416
|
rvalue = function_with_rich_values('{}//{}', [self, other_])
|
1394
1417
|
return rvalue
|
1395
1418
|
|
1396
1419
|
def __rfloordiv__(self, other):
|
1397
1420
|
type_other = str(type(other))
|
1398
|
-
other_ = (RichValue(other, is_int=(type(other)
|
1421
|
+
other_ = (RichValue(other, is_int=('int' in str(type(other))))
|
1399
1422
|
if 'int' in type_other or 'float' in type_other else other)
|
1400
1423
|
other_ = RichValue(other) if type(other) is not RichValue else other
|
1401
1424
|
return other_ // self
|
1402
1425
|
|
1403
1426
|
def __mod__(self, other):
|
1404
1427
|
type_other = str(type(other))
|
1405
|
-
other_ = (RichValue(other, is_int=(type(other)
|
1428
|
+
other_ = (RichValue(other, is_int=('int' in str(type(other))))
|
1406
1429
|
if 'int' in type_other or 'float' in type_other else other)
|
1407
1430
|
domain = other_.interval(6.)
|
1408
1431
|
if domain[0] > 0 and other_.sign() != -1:
|
1409
1432
|
domain[0] = 0
|
1410
1433
|
if domain[1] < 0 and other_.sign() != 1:
|
1411
|
-
domain[1] = 0
|
1434
|
+
domain[1] = 0
|
1412
1435
|
rvalue = function_with_rich_values('{}%{}', [self, other_],
|
1413
1436
|
domain=domain, is_domain_cyclic=True)
|
1414
1437
|
return rvalue
|
@@ -1452,7 +1475,7 @@ class RichValue():
|
|
1452
1475
|
x = self.main ** other
|
1453
1476
|
dx = (np.abs(x * other * np.array(self.unc) / self.main)
|
1454
1477
|
if (x*other) != 0. else 0.)
|
1455
|
-
is_int = self.is_int and type(other)
|
1478
|
+
is_int = self.is_int and 'int' in str(type(other))
|
1456
1479
|
if domain != [-np.inf, np.inf]:
|
1457
1480
|
if domain[0] != 0 or (domain[0] == 0 and other>0):
|
1458
1481
|
x1 = domain[0] ** other
|
@@ -1519,11 +1542,11 @@ class RichValue():
|
|
1519
1542
|
main = self.main
|
1520
1543
|
unc = self.unc
|
1521
1544
|
domain = copy.copy(self.domain)
|
1522
|
-
if
|
1545
|
+
if not hasattr(x, '__iter__'):
|
1523
1546
|
x = [x]
|
1524
1547
|
x = np.array(x)
|
1525
1548
|
y = np.zeros(len(x))
|
1526
|
-
if self.is_exact:
|
1549
|
+
if self.is_exact:
|
1527
1550
|
ind = np.argmin(abs(x - main))
|
1528
1551
|
if hasattr(ind, '__iter__'):
|
1529
1552
|
ind = ind[0]
|
@@ -1584,7 +1607,7 @@ class RichValue():
|
|
1584
1607
|
if not self.is_lim:
|
1585
1608
|
distr = general_distribution(main, unc, domain, N)
|
1586
1609
|
else:
|
1587
|
-
x1, x2 = self.interval()
|
1610
|
+
x1, x2 = self.interval()
|
1588
1611
|
distr = loguniform_distribution(x1, x2, N)
|
1589
1612
|
elif not is_finite_interv and all(np.isinf(unc)):
|
1590
1613
|
distr = loguniform_distribution(-np.inf, np.inf, N)
|
@@ -1694,7 +1717,7 @@ class RichArray(np.ndarray):
|
|
1694
1717
|
|
1695
1718
|
def __new__(cls, mains=None, uncs=None, are_lolims=None, are_uplims=None,
|
1696
1719
|
are_ranges=None, domains=None, are_ints=None,
|
1697
|
-
variables=None, expressions=None, **kwargs):
|
1720
|
+
variables=None, expressions=None, pdf_infos=None, **kwargs):
|
1698
1721
|
"""
|
1699
1722
|
Parameters
|
1700
1723
|
----------
|
@@ -1823,6 +1846,8 @@ class RichArray(np.ndarray):
|
|
1823
1846
|
if variables is not None and expressions is not None:
|
1824
1847
|
array[i].variables = variables[i]
|
1825
1848
|
array[i].expression = expressions[i]
|
1849
|
+
if pdf_infos is not None:
|
1850
|
+
array[i].pdf_info = pdf_infos[i]
|
1826
1851
|
array = array.reshape(mains.shape)
|
1827
1852
|
array = array.view(cls)
|
1828
1853
|
return array
|
@@ -1832,17 +1857,17 @@ class RichArray(np.ndarray):
|
|
1832
1857
|
return np.array([x.main for x in self.flat]).reshape(self.shape)
|
1833
1858
|
@property
|
1834
1859
|
def uncs(self):
|
1835
|
-
return np.array([x.unc for x in self.flat]).reshape([*self.shape,2])
|
1860
|
+
return np.array([x.unc for x in self.flat]).reshape([*self.shape,2])
|
1836
1861
|
@property
|
1837
1862
|
def are_lolims(self):
|
1838
1863
|
return np.array([x.is_lolim for x in self.flat]).reshape(self.shape)
|
1839
1864
|
@property
|
1840
1865
|
def are_uplims(self):
|
1841
|
-
return np.array([x.is_uplim for x in self.flat]).reshape(self.shape)
|
1866
|
+
return np.array([x.is_uplim for x in self.flat]).reshape(self.shape)
|
1842
1867
|
@property
|
1843
1868
|
def are_ranges(self):
|
1844
1869
|
return np.array([x.is_range for x in self.flat]).reshape(self.shape)
|
1845
|
-
@property
|
1870
|
+
@property
|
1846
1871
|
def domains(self):
|
1847
1872
|
return np.array([x.domain for x in self.flat]).reshape([*self.shape,2])
|
1848
1873
|
@property
|
@@ -1883,7 +1908,7 @@ class RichArray(np.ndarray):
|
|
1883
1908
|
return np.array([x.is_inf for x in self.flat]).reshape(self.shape)
|
1884
1909
|
@property
|
1885
1910
|
def centers(self):
|
1886
|
-
return np.array([x.center for x in self.flat]).reshape(self.shape)
|
1911
|
+
return np.array([x.center for x in self.flat]).reshape(self.shape)
|
1887
1912
|
@property
|
1888
1913
|
def rel_uncs(self):
|
1889
1914
|
return (np.array([x.rel_unc for x in self.flat])
|
@@ -1957,27 +1982,27 @@ class RichArray(np.ndarray):
|
|
1957
1982
|
|
1958
1983
|
def medians(self, num_points=None):
|
1959
1984
|
return np.array([x.median(num_points)
|
1960
|
-
for x in self.flat]).reshape(self.shape)
|
1985
|
+
for x in self.flat]).reshape(self.shape)
|
1961
1986
|
|
1962
1987
|
def means(self, num_points=int(1e4), sigmas=8.):
|
1963
1988
|
return np.array([x.mean(num_points, sigmas)
|
1964
|
-
for x in self.flat]).reshape(self.shape)
|
1989
|
+
for x in self.flat]).reshape(self.shape)
|
1965
1990
|
|
1966
1991
|
def modes(self, num_points=int(1e4), sigmas=8.):
|
1967
1992
|
return np.array([x.mode(num_points, sigmas)
|
1968
|
-
for x in self.flat]).reshape(self.shape)
|
1993
|
+
for x in self.flat]).reshape(self.shape)
|
1969
1994
|
|
1970
1995
|
def variances(self, num_points=int(1e4), sigmas=8.):
|
1971
1996
|
return np.array([x.var(num_points, sigmas)
|
1972
|
-
for x in self.flat]).reshape(self.shape)
|
1997
|
+
for x in self.flat]).reshape(self.shape)
|
1973
1998
|
|
1974
1999
|
def stds(self, num_points=int(1e4), sigmas=8.):
|
1975
2000
|
return np.array([x.std(num_points, sigmas)
|
1976
|
-
for x in self.flat]).reshape(self.shape)
|
2001
|
+
for x in self.flat]).reshape(self.shape)
|
1977
2002
|
|
1978
2003
|
def moments(self, n, central=True, standarized=False):
|
1979
2004
|
return np.array([x.moments(n, central, standarized)
|
1980
|
-
for x in self.flat]).reshape(self.shape)
|
2005
|
+
for x in self.flat]).reshape(self.shape)
|
1981
2006
|
|
1982
2007
|
def set_params(self, params):
|
1983
2008
|
"""Set the rich value parameters of each entry of the rich array."""
|
@@ -1986,7 +2011,7 @@ class RichArray(np.ndarray):
|
|
1986
2011
|
'minimum exponent for scientific notation': 'min_exp',
|
1987
2012
|
'maximum number of decimals': 'max_dec',
|
1988
2013
|
'limit for extra significant figure': 'extra_sf_lim'}
|
1989
|
-
attributes = ['domain'] + list(abbreviations.values())
|
2014
|
+
attributes = ['domain'] + list(abbreviations.values())
|
1990
2015
|
for entry in abbreviations:
|
1991
2016
|
name = abbreviations[entry]
|
1992
2017
|
if entry in params:
|
@@ -2138,7 +2163,7 @@ class RichDataFrame(pd.DataFrame):
|
|
2138
2163
|
exec(code, {**{'self': self}, **globals()}, output)
|
2139
2164
|
return output['df']
|
2140
2165
|
|
2141
|
-
@property
|
2166
|
+
@property
|
2142
2167
|
def mains(self): return self._property('mains')
|
2143
2168
|
@property
|
2144
2169
|
def uncs(self): return self._property2('uncs')
|
@@ -2570,7 +2595,7 @@ class ComplexRichValue():
|
|
2570
2595
|
Parameters
|
2571
2596
|
----------
|
2572
2597
|
real : rich value
|
2573
|
-
Real part of the complex rich value.
|
2598
|
+
Real part of the complex rich value.
|
2574
2599
|
imag : rich value
|
2575
2600
|
Imaginary part of the complex rich value
|
2576
2601
|
"""
|
@@ -2651,14 +2676,14 @@ class ComplexRichValue():
|
|
2651
2676
|
self.imag.num_sf = x
|
2652
2677
|
|
2653
2678
|
@property
|
2654
|
-
def min_exp(self): return round(np.mean([self.real.min_exp, self.imag.min_exp]))
|
2679
|
+
def min_exp(self): return round(np.mean([self.real.min_exp, self.imag.min_exp]))
|
2655
2680
|
@min_exp.setter
|
2656
2681
|
def min_exp(self, x):
|
2657
2682
|
self.real.min_exp = x
|
2658
2683
|
self.imag.min_exp = x
|
2659
2684
|
|
2660
2685
|
@property
|
2661
|
-
def max_dec(self): return min(self.real.max_dec, self.imag.max_dec)
|
2686
|
+
def max_dec(self): return min(self.real.max_dec, self.imag.max_dec)
|
2662
2687
|
@max_dec.setter
|
2663
2688
|
def max_dec(self, x):
|
2664
2689
|
self.real.max_dec = x
|
@@ -2698,7 +2723,7 @@ class ComplexRichValue():
|
|
2698
2723
|
def main(self):
|
2699
2724
|
"""Main value."""
|
2700
2725
|
x = self.real.main + 1j*self.imag.main
|
2701
|
-
return x
|
2726
|
+
return x
|
2702
2727
|
|
2703
2728
|
@property
|
2704
2729
|
def unc(self):
|
@@ -2898,7 +2923,7 @@ class ComplexRichValue():
|
|
2898
2923
|
is_other_real = (type(other) not in (RichValue, ComplexRichValue)
|
2899
2924
|
and 'complex' not in str(type(other)))
|
2900
2925
|
if is_other_real:
|
2901
|
-
is_int = type(other)
|
2926
|
+
is_int = 'int' in str(type(other))
|
2902
2927
|
other_ = RichValue(other, is_int=is_int)
|
2903
2928
|
other_.variables = []
|
2904
2929
|
other_.expression = str(other)
|
@@ -2918,7 +2943,7 @@ class ComplexRichValue():
|
|
2918
2943
|
"""Apply a function to the rich value"""
|
2919
2944
|
return function_with_rich_values(function, self, **kwargs)
|
2920
2945
|
|
2921
|
-
# Instance variable acronyms.
|
2946
|
+
# Instance variable acronyms.
|
2922
2947
|
|
2923
2948
|
@property
|
2924
2949
|
def real_part(self): return self.real
|
@@ -3262,7 +3287,7 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
3262
3287
|
domain = read_domain(text)
|
3263
3288
|
if domain is not None:
|
3264
3289
|
text = text.split('[')[0][:-1]
|
3265
|
-
if not '--' in text:
|
3290
|
+
if not '--' in text:
|
3266
3291
|
if text.startswith('+'):
|
3267
3292
|
text = text[1:]
|
3268
3293
|
if 'e' in text:
|
@@ -3314,8 +3339,10 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
3314
3339
|
dx1 = dx1[1:]
|
3315
3340
|
dx2 = dx2[1:]
|
3316
3341
|
d = len(x.split('.')[1]) if '.' in x else 0
|
3317
|
-
|
3318
|
-
|
3342
|
+
d1 = len(dx1.split('.')[1]) if '.' in dx1 else 0
|
3343
|
+
d2 = len(dx1.split('.')[1]) if '.' in dx2 else 0
|
3344
|
+
dx1 = '{:f}'.format(float(dx1)*10**(-(d-d1)))
|
3345
|
+
dx2 = '{:f}'.format(float(dx2)*10**(-(d-d2)))
|
3319
3346
|
elif '+/-' in text:
|
3320
3347
|
x, dx = x_dx.split('+/-')
|
3321
3348
|
text = '{}-{}+{} {}'.format(x, dx, dx, e)
|
@@ -3370,11 +3397,11 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
3370
3397
|
if eval(dx1) == eval(dx2) == 0:
|
3371
3398
|
extra_sf_lim = 1 - 1e-8
|
3372
3399
|
else:
|
3373
|
-
extra_sf_lim = default_extra_sf_lim
|
3400
|
+
extra_sf_lim = default_extra_sf_lim
|
3374
3401
|
base = float('{:e}'.format(eval(val)).split('e')[0])
|
3375
3402
|
if base <= default_extra_sf_lim:
|
3376
3403
|
if num_sf < default_num_sf + 1:
|
3377
|
-
extra_sf_lim = base - 1e-8
|
3404
|
+
extra_sf_lim = base - 1e-8
|
3378
3405
|
else:
|
3379
3406
|
extra_sf_lim = default_extra_sf_lim
|
3380
3407
|
x = x.replace('e0','')
|
@@ -3382,7 +3409,7 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
3382
3409
|
unc = [eval(dx1), eval(dx2)]
|
3383
3410
|
is_range = False
|
3384
3411
|
if domain is None and np.isfinite(main) and unc[0] == 0. == unc[1]:
|
3385
|
-
domain = [main]*2
|
3412
|
+
domain = [main]*2
|
3386
3413
|
else:
|
3387
3414
|
text = text.replace(' --','--').replace('-- ','--')
|
3388
3415
|
text1, text2 = text.split('--')
|
@@ -3429,7 +3456,7 @@ def rich_value(text=None, domain=None, is_int=None, pdf=None,
|
|
3429
3456
|
imag = rich_value(text_imag, *args)
|
3430
3457
|
else:
|
3431
3458
|
text = text.replace(' + ', '+').replace(' - ', '-')
|
3432
|
-
val = complex(text)
|
3459
|
+
val = complex(text)
|
3433
3460
|
real = val.real
|
3434
3461
|
imag = val.imag
|
3435
3462
|
rvalue = ComplexRichValue(real, imag, domain, is_int)
|
@@ -3489,15 +3516,18 @@ def rich_array(array, domain=None, is_int=None,
|
|
3489
3516
|
shape = array.shape
|
3490
3517
|
mains, uncs, are_lolims, are_uplims, are_ranges, domains, are_ints = \
|
3491
3518
|
[], [], [], [], [], [], []
|
3492
|
-
min_exps, extra_sf_lims, variables, expressions
|
3519
|
+
min_exps, extra_sf_lims, variables, expressions, pdf_infos = \
|
3520
|
+
[], [], [], [], []
|
3493
3521
|
for entry in array.flat:
|
3494
3522
|
if type(entry) in (RichValue, ComplexRichValue):
|
3495
3523
|
if domain is not None:
|
3496
3524
|
entry.domain = domain
|
3497
3525
|
if is_int is not None:
|
3498
3526
|
entry.is_int = is_int
|
3527
|
+
pdf_info = entry.pdf_info
|
3499
3528
|
else:
|
3500
3529
|
entry = rich_value(entry, domain, is_int, use_default_extra_sf_lim)
|
3530
|
+
pdf_info = 'default'
|
3501
3531
|
mains += [entry.main]
|
3502
3532
|
uncs += [entry.unc]
|
3503
3533
|
are_lolims += [entry.is_lolim]
|
@@ -3509,6 +3539,7 @@ def rich_array(array, domain=None, is_int=None,
|
|
3509
3539
|
extra_sf_lims += [entry.extra_sf_lim]
|
3510
3540
|
variables += [entry.variables]
|
3511
3541
|
expressions += [entry.expression]
|
3542
|
+
pdf_infos += [pdf_info]
|
3512
3543
|
mains = np.array(mains).reshape(shape)
|
3513
3544
|
uncs = np.array(uncs)
|
3514
3545
|
uncs = (np.array([uncs[:,0].reshape(shape).tolist(),
|
@@ -3523,7 +3554,7 @@ def rich_array(array, domain=None, is_int=None,
|
|
3523
3554
|
.transpose().reshape((*shape, 2)))
|
3524
3555
|
are_ints = np.array(are_ints).reshape(shape)
|
3525
3556
|
rarray = RichArray(mains, uncs, are_lolims, are_uplims, are_ranges,
|
3526
|
-
domains, are_ints, variables, expressions)
|
3557
|
+
domains, are_ints, variables, expressions, pdf_infos)
|
3527
3558
|
min_exp = round(np.mean(min_exps))
|
3528
3559
|
extra_sf_lim = max(extra_sf_lims)
|
3529
3560
|
rarray.set_params({'min_exp': min_exp, 'extra_sf_lim': extra_sf_lim})
|
@@ -3608,6 +3639,28 @@ def rich_dataframe(df, domains=None, are_ints=None, ignore_columns=[],
|
|
3608
3639
|
rdf = RichDataFrame(df)
|
3609
3640
|
return rdf
|
3610
3641
|
|
3642
|
+
def gaussian(x, m=0., s=1.):
|
3643
|
+
"""
|
3644
|
+
Parameters
|
3645
|
+
----------
|
3646
|
+
x : array (float)
|
3647
|
+
Independent variable.
|
3648
|
+
m : float, optional
|
3649
|
+
Mean of the curve. The default is 0.
|
3650
|
+
s : float, optional
|
3651
|
+
Standard deviation of the curve.
|
3652
|
+
The default is 1.
|
3653
|
+
|
3654
|
+
Returns
|
3655
|
+
-------
|
3656
|
+
y : array (float)
|
3657
|
+
Resulting array.
|
3658
|
+
"""
|
3659
|
+
sqrt_tau = 2.50662827
|
3660
|
+
y = np.exp(-0.5 * ((x-m) / s)**2)
|
3661
|
+
y /= s * sqrt_tau
|
3662
|
+
return y
|
3663
|
+
|
3611
3664
|
def bounded_gaussian(x, m=0., s=1., a=np.inf):
|
3612
3665
|
"""
|
3613
3666
|
Bounded gaussian function.
|
@@ -3724,7 +3777,7 @@ def qsplitgaussian(x, m=0., s1=1., s2=1., num_points=1200, sigmas=8.,
|
|
3724
3777
|
Resulting array.
|
3725
3778
|
"""
|
3726
3779
|
alpha = 0.15865
|
3727
|
-
if
|
3780
|
+
if not hasattr(x, '__iter__'):
|
3728
3781
|
x = [x]
|
3729
3782
|
x = np.array(x)
|
3730
3783
|
x_ = np.linspace(m - sigmas*s1, m + sigmas*s2, num_points)
|
@@ -3772,7 +3825,7 @@ def qgenextreme(x, m=0., s1=1., s2=1., num_points=800, sigmas=12.,
|
|
3772
3825
|
Resulting array.
|
3773
3826
|
"""
|
3774
3827
|
alpha = 0.15865
|
3775
|
-
if
|
3828
|
+
if not hasattr(x, '__iter__'):
|
3776
3829
|
x = [x]
|
3777
3830
|
x = np.array(x)
|
3778
3831
|
x_ = np.linspace(m - s1*sigmas, m + s2*sigmas, num_points)
|
@@ -4120,7 +4173,7 @@ def loguniform_distribution(low=-1, high=1, size=1,
|
|
4120
4173
|
log_x2 = _log10(abs(x2))
|
4121
4174
|
if log_x1 < zero_log:
|
4122
4175
|
log_x1 = zero_log
|
4123
|
-
if log_x2 > inf_log:
|
4176
|
+
if log_x2 > inf_log:
|
4124
4177
|
log_x2 = inf_log
|
4125
4178
|
if x1 < 0:
|
4126
4179
|
if x2 <= 0:
|
@@ -4146,6 +4199,8 @@ def distr_with_rich_values(function, args, len_samples=None,
|
|
4146
4199
|
"""
|
4147
4200
|
Same as function_with_rich_values, but just returns the final distribution.
|
4148
4201
|
"""
|
4202
|
+
len_samples = (int(len_samples) if len_samples is not None else
|
4203
|
+
int(len(args)**0.5 * defaultparams['size of samples']))
|
4149
4204
|
if type(args) not in (tuple, list):
|
4150
4205
|
args = [args]
|
4151
4206
|
args = [rich_value(arg) if type(arg) not in (RichValue, ComplexRichValue)
|
@@ -4260,7 +4315,7 @@ def add_zero_infs(interval, zero_log, inf_log):
|
|
4260
4315
|
elif x2 > 0 and x2 > 10**inf_log:
|
4261
4316
|
x2 = np.inf
|
4262
4317
|
new_interval = [x1, x2]
|
4263
|
-
return new_interval
|
4318
|
+
return new_interval
|
4264
4319
|
def remove_zero_infs(interval, zero_log, inf_log):
|
4265
4320
|
"""Replace 0 and infinity for the given values in the input interval."""
|
4266
4321
|
x1, x2 = interval
|
@@ -4371,8 +4426,16 @@ def evaluate_distr(distr, domain=None, function=None, args=None,
|
|
4371
4426
|
(RichValue, ComplexRichValue) else arg for arg in args]
|
4372
4427
|
if consider_intervs is None:
|
4373
4428
|
consider_intervs = True
|
4374
|
-
if args is not None
|
4375
|
-
|
4429
|
+
if args is not None:
|
4430
|
+
if type(args[0]) is RichValue:
|
4431
|
+
all_args = [arg for arg in args]
|
4432
|
+
elif type(args[0]) is RichArray:
|
4433
|
+
all_args = []
|
4434
|
+
for arg in args:
|
4435
|
+
for xi in arg:
|
4436
|
+
all_args += [xi]
|
4437
|
+
if all([arg.is_centr for arg in all_args]):
|
4438
|
+
consider_intervs = False
|
4376
4439
|
|
4377
4440
|
distr = np.array(distr)
|
4378
4441
|
|
@@ -5042,6 +5105,7 @@ def distr_with_rich_arrays(function, args, elementwise=False, **kwargs):
|
|
5042
5105
|
alt_args = []
|
5043
5106
|
for arg in args:
|
5044
5107
|
alt_args += list(arg.flat)
|
5108
|
+
distr = []
|
5045
5109
|
output = distr_with_rich_values(alt_function, alt_args, **kwargs)
|
5046
5110
|
return output
|
5047
5111
|
|
@@ -5156,7 +5220,7 @@ def errorbar(x, y, lims_factor=None, **kwargs):
|
|
5156
5220
|
xa, ya = rich_array(x), rich_array(y)
|
5157
5221
|
xc = rich_array([x]) if len(xa.shape) == 0 else xa
|
5158
5222
|
yc = rich_array([y]) if len(ya.shape) == 0 else ya
|
5159
|
-
if
|
5223
|
+
if not hasattr(lims_factor, '__iter__'):
|
5160
5224
|
lims_factor_x, lims_factor_y = [lims_factor]*2
|
5161
5225
|
elif type(lims_factor) in (list, tuple):
|
5162
5226
|
lims_factor_x, lims_factor_y = lims_factor
|
@@ -5363,7 +5427,7 @@ def curve_fit(x, y, function, guess, num_samples=3000,
|
|
5363
5427
|
lim1, lim2 = 0.2, 1.2
|
5364
5428
|
if disp_coef <= lim1:
|
5365
5429
|
frac1 = 1.
|
5366
|
-
elif disp_coef < lim2:
|
5430
|
+
elif disp_coef < lim2:
|
5367
5431
|
frac1 = 1. - disp_coef / (lim2 - lim1)
|
5368
5432
|
else:
|
5369
5433
|
frac1 = 0.
|
@@ -5376,7 +5440,7 @@ def curve_fit(x, y, function, guess, num_samples=3000,
|
|
5376
5440
|
result = {'parameters': params_fit, 'dispersion': dispersion, 'loss': loss,
|
5377
5441
|
'parameters samples': samples, 'dispersion sample': dispersions,
|
5378
5442
|
'loss sample': losses, 'number of fails': num_fails}
|
5379
|
-
return result
|
5443
|
+
return result
|
5380
5444
|
|
5381
5445
|
def point_fit(y, function, guess, num_samples=3000,
|
5382
5446
|
loss=lambda a,b: (a-b)**2, lim_loss_factor=4.,
|
@@ -5453,7 +5517,7 @@ def point_fit(y, function, guess, num_samples=3000,
|
|
5453
5517
|
lim1, lim2 = 0.2, 1.2
|
5454
5518
|
if disp_coef <= lim1:
|
5455
5519
|
frac1 = 1.
|
5456
|
-
elif disp_coef < lim2:
|
5520
|
+
elif disp_coef < lim2:
|
5457
5521
|
frac1 = 1. - disp_coef / (lim2 - lim1)
|
5458
5522
|
else:
|
5459
5523
|
frac1 = 0.
|
@@ -5696,4 +5760,4 @@ evaluate_distribution = evaluate_distr
|
|
5696
5760
|
center_and_uncertainties = center_and_uncs
|
5697
5761
|
is_not_a_number = is_nan = isnan
|
5698
5762
|
is_infinite = is_inf = isinf
|
5699
|
-
is_finite = is_finite = isfinite
|
5763
|
+
is_finite = is_finite = isfinite
|
@@ -5,7 +5,7 @@ with open('README.md', 'r') as file:
|
|
5
5
|
|
6
6
|
setuptools.setup(
|
7
7
|
name = 'richvalues',
|
8
|
-
version = '4.2.
|
8
|
+
version = '4.2.2',
|
9
9
|
license = 'BSD-3-Clause',
|
10
10
|
author = 'Andrés Megías Toledano',
|
11
11
|
description = 'Python library for working with uncertainties and upper/lower limits',
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|