pyrolite 0.0.14__zip

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 (119) hide show
  1. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__init__.py +10 -0
  2. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/__init__.cpython-36.pyc +0 -0
  3. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/_version.cpython-36.pyc +0 -0
  4. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/alteration.cpython-36.pyc +0 -0
  5. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/classification.cpython-36.pyc +0 -0
  6. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/compositions.cpython-36.pyc +0 -0
  7. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/geochem.cpython-36.pyc +0 -0
  8. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/melts.cpython-36.pyc +0 -0
  9. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/norm.cpython-36.pyc +0 -0
  10. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/normalisation.cpython-36.pyc +0 -0
  11. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/__pycache__/plot.cpython-36.pyc +0 -0
  12. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/_version.py +21 -0
  13. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/alteration.py +66 -0
  14. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/classification.py +222 -0
  15. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__init__.py +9 -0
  16. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/__init__.cpython-36.pyc +0 -0
  17. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/aggregate.cpython-36.pyc +0 -0
  18. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/codata.cpython-36.pyc +0 -0
  19. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/impute.cpython-36.pyc +0 -0
  20. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/__pycache__/renorm.cpython-36.pyc +0 -0
  21. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/aggregate.py +391 -0
  22. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/codata.py +266 -0
  23. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/impute.py +82 -0
  24. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/comp/renorm.py +40 -0
  25. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/compositions.py +524 -0
  26. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_CFB_Dataset_List.csv +42 -0
  27. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_Convergent_Dataset_List.csv +42 -0
  28. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_OBFB_Dataset_List.csv +5 -0
  29. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_OIB_Dataset_List.csv +49 -0
  30. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/GEOROC_OceanicPlateau_Dataset_List.csv +18 -0
  31. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/georoc/contents.json +1 -0
  32. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/melts/__pycache__/env.cpython-35.pyc +0 -0
  33. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/melts/__pycache__/env.cpython-36.pyc +0 -0
  34. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/melts/env.py +1063 -0
  35. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Ba.modelfield +0 -0
  36. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Bs.modelfield +0 -0
  37. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.F.modelfield +0 -0
  38. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.O1.modelfield +0 -0
  39. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.O2.modelfield +0 -0
  40. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.O3.modelfield +0 -0
  41. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Pc.modelfield +0 -0
  42. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.Ph.modelfield +0 -0
  43. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.R.modelfield +0 -0
  44. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.S1.modelfield +0 -0
  45. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.S2.modelfield +0 -0
  46. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.S3.modelfield +0 -0
  47. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.T1.modelfield +0 -0
  48. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.T2.modelfield +0 -0
  49. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.U1.modelfield +0 -0
  50. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.U2.modelfield +0 -0
  51. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.U3.modelfield +0 -0
  52. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.modelfields +0 -0
  53. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.nan.modelfield +0 -0
  54. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS/TAS.none.modelfield +0 -0
  55. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/TAS.clsf.gz +0 -0
  56. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/aphanitic.clsf.gz +0 -0
  57. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/gabbroic.clsf.gz +0 -0
  58. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/peralkalinity.clsf.gz +0 -0
  59. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/phaneritic.clsf.gz +0 -0
  60. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/models/ultramafic.clsf.gz +0 -0
  61. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/CH_PalmeONeill2014.csv +95 -0
  62. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/DDMM_WorkmanHart2005.csv +105 -0
  63. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/DMM_WorkmanHart2005.csv +105 -0
  64. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/DM_SaltersStrake2004.csv +95 -0
  65. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/EDMM_WorkmanHart2005.csv +105 -0
  66. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/refcomp/PM_PalmeONeill2014.csv +95 -0
  67. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/data/timescale/geotimescale_spans.csv +180 -0
  68. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/geochem.py +821 -0
  69. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/melts.py +92 -0
  70. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__init__.py +10 -0
  71. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/__init__.cpython-36.pyc +0 -0
  72. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/db.cpython-36.pyc +0 -0
  73. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/ions.cpython-36.pyc +0 -0
  74. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/mineral.cpython-36.pyc +0 -0
  75. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/__pycache__/sites.cpython-36.pyc +0 -0
  76. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/db.py +88 -0
  77. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/ions.py +78 -0
  78. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/mineral.py +587 -0
  79. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/mineral/sites.py +134 -0
  80. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/norm.py +224 -0
  81. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/normalisation.py +204 -0
  82. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/plot.py +514 -0
  83. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__init__.py +13 -0
  84. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/__init__.cpython-36.pyc +0 -0
  85. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/database.cpython-36.pyc +0 -0
  86. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/env.cpython-36.pyc +0 -0
  87. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/general.cpython-36.pyc +0 -0
  88. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/georoc.cpython-36.pyc +0 -0
  89. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/math.cpython-36.pyc +0 -0
  90. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/melts.cpython-36.pyc +0 -0
  91. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/multip.cpython-36.pyc +0 -0
  92. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/multiprocessing.cpython-36.pyc +0 -0
  93. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/pd.cpython-36.pyc +0 -0
  94. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/plot.cpython-36.pyc +0 -0
  95. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/skl.cpython-36.pyc +0 -0
  96. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/spatial.cpython-36.pyc +0 -0
  97. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/text.cpython-36.pyc +0 -0
  98. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/time.cpython-36.pyc +0 -0
  99. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/__pycache__/wfs.cpython-36.pyc +0 -0
  100. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/database.py +88 -0
  101. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/env.py +81 -0
  102. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/general.py +266 -0
  103. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/georoc.py +444 -0
  104. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/math.py +371 -0
  105. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/melts.py +397 -0
  106. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/multip.py +29 -0
  107. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/multiprocessing.py +29 -0
  108. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/pd.py +214 -0
  109. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/plot.py +345 -0
  110. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/skl.py +847 -0
  111. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/spatial.py +91 -0
  112. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/text.py +207 -0
  113. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/time.py +224 -0
  114. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite/util/wfs.py +10 -0
  115. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/PKG-INFO +61 -0
  116. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/SOURCES.txt +83 -0
  117. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/dependency_links.txt +1 -0
  118. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/requires.txt +47 -0
  119. ProgramData/Anaconda3_64/Lib/site-packages/pyrolite-0.0.14-py3.6.egg-info/top_level.txt +1 -0
@@ -0,0 +1,371 @@
1
+ import numpy as np
2
+ from sympy.solvers.solvers import nsolve
3
+ from sympy import symbols, var
4
+ from functools import partial
5
+ import scipy
6
+ import logging
7
+ from copy import copy
8
+
9
+
10
+ logging.getLogger(__name__).addHandler(logging.NullHandler())
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ def is_numeric(obj):
15
+ attrs = ["__add__", "__sub__", "__mul__", "__truediv__", "__pow__"]
16
+ return all(hasattr(obj, attr) for attr in attrs)
17
+
18
+
19
+ @np.vectorize
20
+ def round_sig(x, sig=2):
21
+ """Round a number to a certain number of significant figures."""
22
+ where_nan = ~np.isfinite(x)
23
+ x = copy(x)
24
+ if hasattr(x, "__len__"):
25
+ x[where_nan] = np.finfo(np.float).eps
26
+ vals = np.round(x, sig - np.int(np.floor(np.log10(np.abs(x)))) - 1)
27
+ vals[where_nan] = np.nan
28
+ return vals
29
+ else:
30
+ try:
31
+ return np.round(x, sig - np.int(np.floor(np.log10(np.abs(x)))) - 1)
32
+ except (ValueError, OverflowError): # nan or inf is passed
33
+ return x
34
+
35
+
36
+ def significant_figures(n, unc=None, max_sf=20, rtol=1e-20):
37
+ """Get number of significant digits for a number, given an uncertainty."""
38
+ if not hasattr(n, "__len__"):
39
+ if np.isfinite(n):
40
+ if unc is not None:
41
+ mag_n = np.floor(np.log10(np.abs(n)))
42
+ mag_u = np.floor(np.log10(unc))
43
+ if not np.isfinite(mag_u) or not np.isfinite(mag_n):
44
+ return np.nan
45
+ sf = int(max(0, int(1.0 + mag_n - mag_u)))
46
+ else:
47
+ sf = min(
48
+ [
49
+ ix
50
+ for ix in range(max_sf)
51
+ if np.isclose(round_sig(n, ix), n, rtol=rtol)
52
+ ]
53
+ )
54
+ return sf
55
+ else:
56
+ return 0
57
+ else: # this isn't working
58
+ n = np.array(n)
59
+ _n = n.copy()
60
+ mask = np.isclose(n, 0.0) # can't process zeros
61
+ _n[mask] = np.nan
62
+ if unc is not None:
63
+ mag_n = np.floor(np.log10(np.abs(_n)))
64
+ mag_u = np.floor(np.log10(unc))
65
+ sfs = np.nanmax(
66
+ np.vstack(
67
+ [np.zeros(mag_n.shape), (1.0 + mag_n - mag_u).astype(np.int)]
68
+ ),
69
+ axis=0,
70
+ ).astype(np.int)
71
+ else:
72
+ rounded = np.vstack([_n] * max_sf).reshape(max_sf, *_n.shape)
73
+ indx = np.indices(rounded.shape)[0] # get the row indexes for no. sig figs
74
+ rounded = round_sig(rounded, indx)
75
+ sfs = np.nanargmax(np.isclose(rounded, _n, rtol=rtol), axis=0)
76
+ sfs[np.isnan(sfs)] = 0
77
+ return sfs
78
+
79
+
80
+ def most_precise(arr):
81
+ """Get the most precise element from an array."""
82
+ arr = np.array(arr)
83
+ if np.isfinite(arr).any().any():
84
+ precision = significant_figures(arr)
85
+ if arr.ndim > 1:
86
+ return arr[range(arr.shape[0]), np.nanargmax(precision, axis=-1)]
87
+ else:
88
+ return arr[np.nanargmax(precision, axis=-1)]
89
+ else:
90
+ return np.nan
91
+
92
+
93
+ def equal_within_significance(arr, equal_nan=False, rtol=1e-15):
94
+ """
95
+ Test whether elements within an array are equal to the precision of the
96
+ least precise.
97
+ """
98
+ arr = np.array(arr)
99
+
100
+ if arr.ndim == 1:
101
+ if not np.isfinite(arr).all():
102
+ return equal_nan
103
+ else:
104
+ precision = significant_figures(arr)
105
+ min_precision = np.nanmin(precision)
106
+ rounded = round_sig(arr, min_precision * np.ones(arr.shape, dtype=int))
107
+ return np.isclose(rounded[0], rounded, rtol=rtol).all()
108
+ else: # ndmim =2
109
+ equal = equal_nan * np.ones(
110
+ arr.shape[0], dtype=bool
111
+ ) # mean for rows containing nan
112
+ if np.isfinite(arr).all(axis=1).any():
113
+ non_nan_rows = np.isfinite(arr).all(axis=1)
114
+
115
+ precision = significant_figures(arr[non_nan_rows, :])
116
+ min_precision = np.nanmin(precision, axis=1)
117
+ precs = np.repeat(min_precision, arr.shape[1]).reshape(
118
+ arr[non_nan_rows, :].shape
119
+ )
120
+ rounded = round_sig(arr[non_nan_rows, :], precs)
121
+ equal[non_nan_rows] = np.apply_along_axis(
122
+ lambda x: (x == x[0]).all(), 1, rounded
123
+ )
124
+
125
+ return equal
126
+
127
+
128
+ def signify_digit(n, unc=None, leeway=0, low_filter=True):
129
+ """
130
+ Reformats numbers to contain only significant_digits. Uncertainty can be provided to
131
+ digits with relevant precision.
132
+
133
+ Note: Will not pad 0s at the end or before floats.
134
+ """
135
+
136
+ if np.isfinite(n):
137
+ if np.isclose(n, 0.0):
138
+ return n
139
+ else:
140
+ mag_n = np.floor(np.log10(np.abs(n)))
141
+ sf = significant_figures(n, unc=unc) + int(leeway)
142
+ if unc is not None:
143
+ mag_u = np.floor(np.log10(unc))
144
+ else:
145
+ mag_u = 0
146
+ round_to = sf - int(mag_n) - 1 + leeway
147
+ if round_to <= 0:
148
+ fmt = int
149
+ else:
150
+ fmt = lambda x: x
151
+ sig_n = round(n, round_to)
152
+ if low_filter and sig_n == 0.0:
153
+ return np.nan
154
+ else:
155
+ return fmt(sig_n)
156
+ else:
157
+ return np.nan
158
+
159
+
160
+ def orthagonal_basis(X: np.ndarray):
161
+ """
162
+ Generate a set of orthagonal basis vectors.
163
+
164
+ Parameters
165
+ ---------------
166
+ X : np.ndarray
167
+ Array from which the size of the set is derived.
168
+ """
169
+ D = X.shape[1]
170
+ # D-1, D Helmert matrix, exact representation of ψ as in Egozogue's book
171
+ H = scipy.linalg.helmert(D, full=False)
172
+ return H[::-1]
173
+
174
+
175
+ def on_finite(X, f):
176
+ """
177
+ Calls a function on an array ignoring np.nan and +/- np.inf. Note that the
178
+ shape of the output may be different to that of the input.
179
+
180
+ Parameters
181
+ ---------------
182
+ X : np.ndarray
183
+ Array on which to perform the function.
184
+ """
185
+ ma = np.isfinite(X)
186
+ return f(X[ma])
187
+
188
+
189
+ def nancov(X, method="replace"):
190
+ """
191
+ Generates a covariance matrix excluding nan-components. Done on a
192
+ column-column/pairwise basis. The result Y may not be a positive definite matrix.
193
+
194
+ Parameters
195
+ ---------------
196
+ X: np.ndarray
197
+ Input array for which to derive a covariance matrix.
198
+ method: str, 'row_exclude' | 'replace'
199
+ Method for calculating covariance matrix.
200
+ 'row_exclude' removes all rows which contain np.nan before calculating
201
+ the covariance matrix. 'replace' instead replaces the np.nan values with
202
+ the mean before calculating the covariance.
203
+
204
+ """
205
+ if method == "rowexclude":
206
+ Xnanfree = X[np.all(np.isfinite(X), axis=1), :].T
207
+ # assert Xnanfree.shape[1] > Xnanfree.shape[0]
208
+ # (1/m)X^T*X
209
+ return np.cov(Xnanfree)
210
+ else:
211
+ X = np.array(X, ndmin=2, dtype=float)
212
+ X -= np.nanmean(X, axis=0) # [:, np.newaxis]
213
+ cov = np.empty((X.shape[1], X.shape[1]))
214
+ cols = range(X.shape[1])
215
+ for n in cols:
216
+ for m in [i for i in cols if i >= n]:
217
+ fn = np.isfinite(X[:, n])
218
+ fm = np.isfinite(X[:, m])
219
+ if method == "replace":
220
+ X[~fn, n] = 0
221
+ X[~fm, m] = 0
222
+ fact = fn.shape[0] - 1
223
+ c = np.dot(X[:, n], X[:, m]) / fact
224
+ else:
225
+ f = fn & fm
226
+ fact = f.shape[0] - 1
227
+ c = np.dot(X[f, n], X[f, m]) / fact
228
+ cov[n, m] = c
229
+ cov[m, n] = c
230
+ return cov
231
+
232
+
233
+ def OP_constants(xs, degree=3, tol=10 ** -14):
234
+ """
235
+ For constructing orthagonal polynomial functions of the general form:
236
+ y(x) = a_0 + a_1 * (x - β) + a_2 * (x - γ_0) * (x - γ_1) +
237
+ a_3 * (x - δ_0) * (x - δ_1) * (x - δ_2)
238
+ Finds the parameters (β_0), (γ_0, γ_1), (δ_0, δ_1, δ_2).
239
+
240
+ These parameters are functions only of the independent variable x.
241
+ """
242
+ xs = np.array(xs)
243
+ x = var("x")
244
+ params = []
245
+ for d in range(degree):
246
+ ps = symbols("{}0:{}".format(chr(945 + d), d))
247
+ logger.debug("Generating {} DIM {} equations for {}.".format(d, d, ps))
248
+ if d:
249
+ eqs = []
250
+ for _deg in range(d):
251
+ q = 1
252
+ if _deg:
253
+ q = x ** _deg
254
+ for p in ps:
255
+ q *= x - p
256
+ eqs.append(q)
257
+
258
+ sums = []
259
+ for q in eqs:
260
+ sumq = 0.0
261
+ for xi in xs:
262
+ sumq += q.subs(dict(x=xi))
263
+ sums.append(sumq)
264
+
265
+ guess = np.linspace(np.nanmin(xs), np.nanmax(xs), d + 2)[1:-1]
266
+ result = nsolve(sums, ps, list(guess), tol=tol)
267
+ params.append(tuple(result))
268
+ else:
269
+ params.append(()) # first parameter
270
+ return params
271
+
272
+
273
+ def lambda_poly(x, ps):
274
+ """
275
+ Polynomial lambda_n(x) given parameters ps with len(ps) = n.
276
+
277
+ Parameters
278
+ -----------
279
+ x: np.ndarray
280
+ X values to calculate the function at.
281
+ ps: tuple
282
+ Parameter set tuple. E.g. parameters (a, b) from f(x) = (x-a)(x-b).
283
+ """
284
+ if not isinstance(x, np.ndarray):
285
+ x = np.array(x)
286
+ result = np.ones(len(x))
287
+ for p in ps:
288
+ result = result * (x - p)
289
+ return result.astype(np.float)
290
+
291
+
292
+ def lambda_min_func(ls, ys, arrs, power=2.0):
293
+ cost = np.abs(np.dot(ls, arrs) - ys) ** power
294
+ cost[np.isnan(cost)] = 0.0 # can't change nans - don't penalise them
295
+ return cost
296
+
297
+
298
+ def lambdas(
299
+ arr: np.ndarray,
300
+ xs=np.array([]),
301
+ params=None,
302
+ guess=None,
303
+ degree=5,
304
+ costf_power=2.0,
305
+ residuals=False,
306
+ min_func=lambda_min_func,
307
+ ):
308
+ """
309
+ Parameterises values based on linear combination of orthagonal polynomials
310
+ over a given set of x values.
311
+ """
312
+ if np.isnan(arr).any(): # With missing data, the method can't be used.
313
+ x = np.nan * np.ones(degree)
314
+ res = np.nan * np.ones(degree)
315
+ else:
316
+ guess = guess or np.exp(np.arange(degree) + 2)
317
+ params = params or OP_constants(xs, degree=degree)
318
+
319
+ fs = np.array([lambda_poly(xs, pset) for pset in params])
320
+
321
+ result = scipy.optimize.least_squares(
322
+ min_func, guess, args=(arr, fs, costf_power) # , method='Nelder-Mead'
323
+ )
324
+ x = result.x
325
+ res = result.fun
326
+ if residuals:
327
+ return x, res
328
+ else:
329
+ return x
330
+
331
+
332
+ def lambda_poly_func(lambdas: np.ndarray, params=None, pxs=None, degree=5):
333
+ """
334
+ Expansion of lambda parameters back to the original space. Returns a
335
+ function which evaluates the sum of the orthaogonal polynomials at given
336
+ x values.
337
+
338
+ Parameters
339
+ ------------
340
+ lambdas: np.ndarray
341
+ Lambda values to weight combination of polynomials.
342
+ params: list of tuples
343
+ Parameters for the orthagonal polynomial decomposition.
344
+ pxs: np.ndarray
345
+ x values used to construct the lambda values.*
346
+ degree: int
347
+ Degree of the orthagonal polynomial decomposition.*
348
+
349
+ * (only needed if parameters are not supplied)
350
+ """
351
+ if params is None and pxs is not None:
352
+ params = OP_constants(pxs, degree=degree)
353
+ elif params is None and pxs is None:
354
+ msg = """Must provide either x values to construct parameters,
355
+ or the parameters themselves."""
356
+ raise AssertionError(msg)
357
+
358
+ def lambda_poly_f(xarr):
359
+ """
360
+ Calculates the sum of decomposed polynomial components
361
+ at given x values.
362
+
363
+ Parameters
364
+ -----------
365
+ xarr: np.ndarray
366
+ X values at which to evaluate the function.
367
+ """
368
+ arrs = np.array([lambda_poly(xarr, pset) for pset in params])
369
+ return np.dot(lambdas, arrs)
370
+
371
+ return lambda_poly_f