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.
@@ -1,6 +1,6 @@
1
1
  BSD 3-Clause License
2
2
 
3
- Copyright (c) 2023, Andrés Megías Toledano
3
+ Copyright (c) 2025, Andrés Megías Toledano
4
4
  All rights reserved.
5
5
 
6
6
  Redistribution and use in source and binary forms, with or without
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: richvalues
3
- Version: 4.2.0
3
+ Version: 4.2.2
4
4
  Summary: Python library for working with uncertainties and upper/lower limits
5
5
  Home-page: https://github.com/andresmegias/richvalues/
6
6
  Author: Andrés Megías Toledano
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "richvalues"
7
- version = "4.2.0"
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) 2024 - Andrés Megías Toledano
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.0'
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, np.inf, max_dec, extra_sf_lim)
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
- dy_ = round_sf(float(dy)*10**d, n, min_exp=np.inf, extra_sf_lim=0.)
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 'e' in y1 and 'e' not in y2 or 'e' in y2 and 'e' not in y1:
358
- min_exp = 0
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
- diff = num_dec_1 - num_dec_2
369
- off1, off2 = 0, 0
370
- if num_dec_1 == 0 == num_dec_2:
371
- base_dy1 = '{:e}'.format(dx1).split('e')[0]
372
- base_dy2 = '{:e}'.format(dx2).split('e')[0]
373
- b1 = float(base_dy1) if np.isfinite(dx1) else 10.
374
- b2 = float(base_dy2) if np.isfinite(dx2) else 10.
375
- if dx2 > dx1 and b1 <= extra_sf_lim and b2 > extra_sf_lim:
376
- off2 = 1
377
- if dx1 > dx2 and b2 <= extra_sf_lim and b1 > extra_sf_lim:
378
- off1 = 1
379
- y1, dy1 = round_sf_unc(x, dx1, n+off1, min_exp, max_dec, extra_sf_lim)
380
- y2, dy2 = round_sf_unc(x, dx2, n+diff+off2, min_exp, max_dec, extra_sf_lim)
381
- y = y1 if dx2 > dx1 else y2
382
- if dy1 != dy2 and (')' in dy1 or ')' in dy2):
383
- dy1 = dy1.replace('(', '(-')
384
- dy2 = dy2.replace('(', '(+')
385
- if ')' in dy1 and ')' not in dy2 or ')' in dy2 and '.' in dy2:
386
- _, dy2 = round_sf_unc(x, dx[1], n, min_exp, max_dec-1, extra_sf_lim)
387
- dy2 = '(' + dy2[1:-1] + '0' + ')'
388
- elif ')' in dy2 and ')' not in dy1 or ')' in dy1 and '.' in dy1:
389
- _, dy1 = round_sf_unc(x, dx[0], n, min_exp, max_dec-1, extra_sf_lim)
390
- dy1 = '(' + dy1[1:-1] + '0' + ')'
391
- if ')' in dy1 or ')' in dy2:
392
- if not dy1.startswith('(-'):
393
- dy1 = '(-' + dy1[1:]
394
- if not dy2.startswith('(+'):
395
- dy2 = '(+' + dy2[1:]
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
- """Minimum of the signals-to-noise and the relative amplitudes."""
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) is int))
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) is int))
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) is int))
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) is int
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 type(x) in (int, float):
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) is int
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
- dx1 = '{:f}'.format(float(dx1)*10**(-d))
3318
- dx2 = '{:f}'.format(float(dx2)*10**(-d))
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 type(x) in (int, float):
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 type(x) in (int, float):
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 and all([arg.is_centr for arg in args]):
4375
- consider_intervs = False
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 type(lims_factor) in (float, int):
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: richvalues
3
- Version: 4.2.0
3
+ Version: 4.2.2
4
4
  Summary: Python library for working with uncertainties and upper/lower limits
5
5
  Home-page: https://github.com/andresmegias/richvalues/
6
6
  Author: Andrés Megías Toledano
@@ -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.0',
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