maxsmooth 1.2.4__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.
maxsmooth/DCF.py ADDED
@@ -0,0 +1,854 @@
1
+
2
+ """
3
+ *smooth*, as demonstrated in the examples section,
4
+ is used to call the fitting routine. There are a number
5
+ of :math:`{^{**}}` kwargs that can be assigned to the function which change how
6
+ the fit is performed, the model that is fit and various other attributes.
7
+ These are detailed below.
8
+
9
+ """
10
+
11
+ from maxsmooth.qp import qp_class, precompute_matrices
12
+ from maxsmooth.Models import Models_class
13
+ from maxsmooth.derivatives import derivative_class
14
+ from maxsmooth.Data_save import save, save_optimum
15
+ from itertools import product
16
+ import warnings
17
+ import numpy as np
18
+ import time
19
+ import os
20
+ import shutil
21
+
22
+
23
+ class smooth(object):
24
+
25
+ r"""
26
+
27
+ **Parameters:**
28
+
29
+ x: **numpy.array**
30
+ | The x data points for the set being fitted.
31
+
32
+ y: **numpy.array**
33
+ | The y data points for fitting.
34
+
35
+ N: **int**
36
+ | The number of terms in the DCF.
37
+
38
+ **Kwargs:**
39
+
40
+ fit_type: **Default = 'qp-sign_flipping'**
41
+ | This kwarg allows the user to
42
+ switch between sampling the available discrete sign spaces
43
+ (default) or testing all sign combinations on the derivatives
44
+ which can be accessed by setting to 'qp'.
45
+
46
+ model_type: **Default = 'difference_polynomial'**
47
+ | Allows the user to
48
+ access default Derivative Constrained Functions built into the
49
+ software. Available options include the default, 'polynomial',
50
+ 'normalised_polynomial', 'legendre', 'log_polynomial',
51
+ 'loglog_polynomial' and 'exponential'. For more details on the
52
+ functional form of the built in basis see the ``maxsmooth``
53
+ paper.
54
+
55
+ **pivot_point: Default = len(x)//2 otherwise an integer between**
56
+ **-len(x) and len(x)**
57
+ | Some of the built in
58
+ models rely on pivot points in the data sets which by defualt
59
+ is set as the middle index. This can be altered via
60
+ this kwarg which can occasionally lead to a better quality fit.
61
+
62
+ base_dir: **Default = 'Fitted_Output/'**
63
+ | The location of the outputted
64
+ data from ``maxsmooth``. This must be a string and end in '/'.
65
+ If the file does not exist then ``maxsmooth`` will create it.
66
+ By default the only outputted data is a summary of the best
67
+ fit but additional data can be recorded by setting the keyword
68
+ argument 'data_save = True'.
69
+
70
+ data_save: **Default = False**
71
+ | By setting this to True the algorithm
72
+ will save every tested set of parameters, signs and objective
73
+ function evaluations into files in base_dir. Theses files will
74
+ be over written on repeated runs but they are needed to run the
75
+ 'chidist_plotter'.
76
+
77
+ print_output: **Default = 1**
78
+ | The parameter can take a value of 0, 1, 2.
79
+ If set to 2 this outputs to the
80
+ terminal every fit performed by the algorithm. By default the
81
+ parameter has a value of 1 and the
82
+ only output is the optimal solution once the code is finished.
83
+ Setting this to 0 will prevent any output to the terminal. This
84
+ is useful when running the code inside a nested sampling loop
85
+ for example.
86
+
87
+ cvxopt_maxiter: **Default = 10000 else integer**
88
+ | This shouldn't need
89
+ changing for most problems however if ``CVXOPT`` fails with a
90
+ 'maxiters reached' error message this can be increased.
91
+ Doing so arbitrarily will however increase the run time of
92
+ ``maxsmooth``.
93
+
94
+ initial_params: **Default = None else list of length N**
95
+ | Allows the user
96
+ to overwrite the default initial parameters used by ``CVXOPT``.
97
+
98
+ **constraints: Default = 2 else an integer less than or equal**
99
+ **to N - 1**
100
+ | The minimum constrained derivative order which is set by default
101
+ to 2 for a Maximally Smooth Function.
102
+
103
+ zero_crossings: **Default = None else list of integers**
104
+ | Allows you to
105
+ specify if the conditions should be relaxed on any
106
+ of the derivatives between constraints and the highest order
107
+ derivative. e.g. a 6th order fit with just a constrained 2nd
108
+ and 3rd order derivative would have zero_crossings = [4, 5].
109
+
110
+ cap: **Default = (len(available_signs)//N) + N else an integer**
111
+ | Determines the maximum number of signs explored either side of
112
+ the minimum :math:`{\chi^2}` value found after the decent
113
+ algorithm has terminated.
114
+
115
+ chi_squared_limit: **Default = 2 else float or int**
116
+ | The prefactor on the maximum allowed increase in :math:`{\chi^2}`
117
+ during the directional exploration which is defaulted at 2.
118
+ If this value multiplied by the minimum :math:`{\chi^2}`
119
+ value found after the descent algorithm is exceeded then the
120
+ exploration in one direction is stopped and started in the
121
+ other. For more details on this and 'cap' see the ``maxsmooth``
122
+ paper.
123
+
124
+ The following Kwargs can be used by the user to define their own basis
125
+ function and will overwrite the 'model_type' kwarg.
126
+
127
+ **basis_function: Default = None else function with parameters**
128
+ **(x, y, pivot_point, N)**
129
+ | This is a function of basis functions
130
+ for the quadratic programming. The variable pivot_point is the
131
+ index at the middle of the datasets x and y by default but can
132
+ be adjusted.
133
+
134
+ **model: Default = None else function with parameters**
135
+ **(x, y, pivot_point, N, params)**
136
+ | This is
137
+ a user defined function describing the model to be fitted to
138
+ the data.
139
+
140
+ **der_pres: Default = None else function with parameters**
141
+ **(m, x, y, N, pivot_point)**
142
+ | This function describes the prefactors on the
143
+ mth order derivative used in defining the constraint.
144
+
145
+ **derivatives: Default = None else function with parameters**
146
+ **(m, x, y, N, pivot_point, params)**
147
+ | User defined function describing the mth
148
+ order derivative used to check that conditions are being met.
149
+
150
+ **args: Default = None else list**
151
+ | Extra arguments for `smooth`
152
+ to pass to the functions detailed above.
153
+
154
+ **Output**
155
+
156
+ .y_fit: **numpy.array**
157
+ | The fitted array of y data from smooth().
158
+
159
+ .optimum_chi: **float**
160
+ | The optimum :math:`{\chi^2}` value for the fit calculated by,
161
+
162
+ .. math::
163
+
164
+ {X^2=\sum(y-y_{fit})^2}.
165
+
166
+ .optimum_params: **numpy.array**
167
+ | The set of parameters corresponding to the optimum fit.
168
+
169
+ .rms: **float**
170
+ | The rms value of the residuals :math:`{y_{res}=y-y_{fit}}`
171
+ calculated by,
172
+
173
+ .. math::
174
+
175
+ {rms=\sqrt{\frac{\sum(y-y_{fit})^2}{n}}}
176
+
177
+ where :math:`n` is the number of data points.
178
+
179
+ .derivatives: **numpy.array**
180
+ | The :math:`m^{th}` order derivatives.
181
+
182
+ .optimum_signs: **numpy.array**
183
+ | The sign combinations corresponding to the
184
+ optimal result. The nature of the constraint means that a
185
+ negative ``maxsmooth`` sign implies a positive :math:`{m^{th}}`
186
+ order derivative and visa versa.
187
+
188
+ """
189
+
190
+ def __init__(self, x, y, N, **kwargs):
191
+ self.x = x
192
+ self.y = y
193
+
194
+ self.N = N
195
+ if self.N % 1 != 0:
196
+ raise ValueError('N must be an integer or whole number float.')
197
+
198
+ for keys, values in kwargs.items():
199
+ if keys not in set(
200
+ ['fit_type', 'model_type', 'base_dir',
201
+ 'print_output', 'cvxopt_maxiter', 'zero_crossings',
202
+ 'data_save',
203
+ 'constraints', 'chi_squared_limit', 'cap',
204
+ 'initial_params', 'basis_functions',
205
+ 'der_pres', 'model',
206
+ 'derivatives', 'args', 'pivot_point']):
207
+ raise KeyError("Unexpected keyword argument in smooth().")
208
+
209
+ self.fit_type = kwargs.pop('fit_type', 'qp-sign_flipping')
210
+ if self.fit_type not in set(['qp', 'qp-sign_flipping']):
211
+ raise KeyError(
212
+ "Invalid 'fit_type'. Valid entries include 'qp'\n" +
213
+ "'qp-sign_flipping'")
214
+
215
+ self.pivot_point = kwargs.pop('pivot_point', len(self.x)//2)
216
+ if type(self.pivot_point) is not int:
217
+ raise TypeError('Pivot point is not an integer index.')
218
+ elif self.pivot_point >= len(self.x) or \
219
+ self.pivot_point < -len(self.x):
220
+ raise ValueError(
221
+ 'Pivot point must be in the range -len(x) - len(x).')
222
+
223
+ self.base_dir = kwargs.pop('base_dir', 'Fitted_Output/')
224
+ if type(self.base_dir) is not str:
225
+ raise KeyError("'base_dir' must be a string ending in '/'.")
226
+ elif self.base_dir.endswith('/') is False:
227
+ raise KeyError("'base_dir' must end in '/'.")
228
+
229
+ self.model_type = kwargs.pop('model_type', 'difference_polynomial')
230
+ if self.model_type not in set(
231
+ ['normalised_polynomial', 'polynomial',
232
+ 'log_polynomial', 'loglog_polynomial',
233
+ 'difference_polynomial',
234
+ 'exponential', 'legendre']):
235
+ raise KeyError(
236
+ "Invalid 'model_type'. See documentation for built" +
237
+ "in models.")
238
+
239
+ self.cvxopt_maxiter = kwargs.pop('cvxopt_maxiter', 10000)
240
+ if type(self.cvxopt_maxiter) is not int:
241
+ raise ValueError("'cvxopt_maxiter' is not integer.")
242
+
243
+ self.print_output = kwargs.pop('print_output', 1)
244
+ if self.print_output not in [0, 1, 2]:
245
+ raise ValueError("'print_output' must have a value in the set" +
246
+ " [0, 1, 2]. See documentation for details.")
247
+
248
+ self.data_save = kwargs.pop('data_save', False)
249
+ if type(self.data_save) is not bool:
250
+ raise TypeError(
251
+ "Boolean keyword argument with value 'data_save'" +
252
+ " is not True or False.")
253
+
254
+ self.constraints = kwargs.pop('constraints', 2)
255
+ if type(self.constraints) is not int:
256
+ raise TypeError("'constraints' is not an integer")
257
+ if self.constraints > self.N-1:
258
+ raise ValueError(
259
+ "'constraints' exceeds the number of derivatives.")
260
+
261
+ self.zero_crossings = kwargs.pop('zero_crossings', None)
262
+ if self.zero_crossings is not None:
263
+ for i in range(len(self.zero_crossings)):
264
+ if type(self.zero_crossings[i]) is not int:
265
+ raise TypeError(
266
+ "Entries in 'zero_crossings'" +
267
+ " are not integer.")
268
+ if self.zero_crossings[i] < self.constraints:
269
+ raise ValueError(
270
+ 'One or more specified derivatives for' +
271
+ ' zero crossings is less than the minimum' +
272
+ ' constrained' +
273
+ ' derivative.\n zero_crossings = ' +
274
+ str(self.zero_crossings)
275
+ + '\n' + ' Minimum Constrained Derivative = '
276
+ + str(self.constraints))
277
+
278
+ self.chi_squared_limit = kwargs.pop('chi_squared_limit', None)
279
+ self.cap = kwargs.pop('cap', None)
280
+ if self.chi_squared_limit is not None:
281
+ if isinstance(self.chi_squared_limit, int) or \
282
+ isinstance(self.chi_squared_limit, float):
283
+ pass
284
+ else:
285
+ raise TypeError(
286
+ "Limit on maximum allowed increase in chi squared" +
287
+ ", 'chi_squared_limit', is not an integer or float.")
288
+ if self.cap is not None:
289
+ if type(self.cap) is not int:
290
+ raise TypeError(
291
+ "The cap on directional exploration" +
292
+ ", 'cap', is not an integer.")
293
+
294
+ self.initial_params = kwargs.pop('initial_params', None)
295
+ if self.initial_params is not None and len(self.initial_params) \
296
+ != self.N:
297
+ raise ValueError(
298
+ "Initial Parameters is not equal to the number" +
299
+ "of terms in the polynomial, N.")
300
+ if self.initial_params is not None and len(self.initial_params) \
301
+ == self.N:
302
+ for i in range(len(self.initial_params)):
303
+ if type(self.initial_params[i]) is not int:
304
+ if type(self.initial_params[i]) is not float:
305
+ raise ValueError(
306
+ 'One or more initial' +
307
+ 'parameters is not numeric.')
308
+
309
+ self.basis_functions = kwargs.pop('basis_functions', None)
310
+ self.der_pres = kwargs.pop('der_pres', None)
311
+ self.model = kwargs.pop('model', None)
312
+ self.derivatives_function = kwargs.pop('derivatives', None)
313
+ self.args = kwargs.pop('args', None)
314
+
315
+ self.new_basis = {
316
+ 'basis_function':
317
+ self.basis_functions, 'der_pres': self.der_pres,
318
+ 'derivatives_function': self.derivatives_function,
319
+ 'model': self.model, 'args': self.args}
320
+ if np.all([value is None for value in self.new_basis.values()]):
321
+ pass
322
+ else:
323
+ count = 0
324
+ for key, value in self.new_basis.items():
325
+ if value is None and key != 'args':
326
+ raise KeyError(
327
+ 'Attempt to change basis functions failed.' +
328
+ ' One or more functions not defined.' +
329
+ ' Please consult documentation.')
330
+ if value is None and key == 'args':
331
+ warnings.warn(
332
+ 'Warning: No additional arguments passed to' +
333
+ ' new basis functions')
334
+ count += 1
335
+ if count == len(self.new_basis):
336
+ self.model_type = 'user_defined'
337
+
338
+ self.y_fit, self.optimum_signs, self.optimum_params, \
339
+ self.derivatives,\
340
+ self.optimum_chi, self.rms, self.optimum_zc_dict \
341
+ = self.fitting()
342
+
343
+ def fitting(self):
344
+
345
+ def signs_array(nums):
346
+ return np.array(list(product(*((x, -x) for x in nums))))
347
+
348
+ if not os.path.exists(self.base_dir):
349
+ os.mkdir(self.base_dir)
350
+
351
+ if os.path.isdir(self.base_dir+'Output_Parameters/'):
352
+ shutil.rmtree(self.base_dir+'Output_Parameters/')
353
+ if os.path.isdir(self.base_dir+'Output_Signs/'):
354
+ shutil.rmtree(self.base_dir+'Output_Signs/')
355
+ if os.path.isdir(self.base_dir+'Output_Evaluation/'):
356
+ shutil.rmtree(self.base_dir+'Output_Evaluation/')
357
+
358
+ def qp(x, y, pivot_point): # Testing all signs
359
+
360
+ start = time.time()
361
+
362
+ if self.zero_crossings is not None:
363
+ signs = signs_array([1]*(
364
+ self.N-self.constraints-len(self.zero_crossings)))
365
+ else:
366
+ signs = signs_array([1]*(self.N-self.constraints))
367
+
368
+ params, chi_squared, zc_dict, passed_signs = [], [], [], []
369
+ append_params, append_chi, append_zc_dict, append_passed_signs = \
370
+ params.append, chi_squared.append, zc_dict.append, \
371
+ passed_signs.append
372
+ precomputed = precompute_matrices(
373
+ x, y, self.N, pivot_point, self.model_type,
374
+ self.zero_crossings, self.constraints, self.new_basis)
375
+ for j in range(signs.shape[0]):
376
+ fit = qp_class(
377
+ x, y, self.N, signs[j, :], pivot_point,
378
+ self.model_type, self.cvxopt_maxiter,
379
+ self.zero_crossings,
380
+ self.initial_params, self.constraints, self.new_basis,
381
+ precomputed=precomputed)
382
+
383
+ if self.print_output == 2:
384
+ print('-'*50)
385
+ print('Polynomial Order:', self.N)
386
+ if self.zero_crossings is not None:
387
+ print(
388
+ 'Number of Constrained Derivatives:',
389
+ self.N-self.constraints-len(self.zero_crossings))
390
+ else:
391
+ print(
392
+ 'Number of Constrained Derivatives:',
393
+ self.N-self.constraints)
394
+ print('Signs :', signs[j, :])
395
+ print('Objective Function Value:', fit.chi_squared)
396
+ print('Parameters:', (fit.parameters).T)
397
+ print('Method:', self.fit_type)
398
+ print('Model:', self.model_type)
399
+ print('Constraints: m >=', self.constraints)
400
+ if self.zero_crossings is None:
401
+ print(
402
+ 'Zero Crossings Used?' +
403
+ ' (0 signifies Yes\n in derivative order "i"):',
404
+ fit.zc_dict)
405
+ if self.zero_crossings is not None:
406
+ print(
407
+ 'Zero Crossing Derivatives:', self.zero_crossings)
408
+ print(
409
+ 'Zero Crossings Used?' +
410
+ ' (0 signifies Yes\n in derivative order "i"):',
411
+ fit.zc_dict)
412
+ print('-'*50)
413
+
414
+ append_params(fit.parameters)
415
+ append_chi(fit.chi_squared)
416
+ append_zc_dict(fit.zc_dict)
417
+ append_passed_signs(signs[j, :])
418
+ if self.data_save is True:
419
+ save(
420
+ self.base_dir, fit.parameters, fit.chi_squared,
421
+ signs[j, :], self.N, self.fit_type)
422
+
423
+ params, chi_squared, zc_dict, passed_signs = np.array(params), \
424
+ np.array(chi_squared), np.array(zc_dict), \
425
+ np.array(passed_signs)
426
+
427
+ Optimum_chi_squared = chi_squared.min()
428
+ for f in range(len(chi_squared)):
429
+ if chi_squared[f] == chi_squared.min():
430
+ Optimum_params = params[f, :]
431
+ Optimum_sign_combination = passed_signs[f, :]
432
+
433
+ y_fit = Models_class(
434
+ Optimum_params, x, y, self.N, pivot_point,
435
+ self.model_type, self.new_basis).y_sum
436
+ der = derivative_class(
437
+ x, y, Optimum_params, self.N,
438
+ pivot_point, self.model_type, self.zero_crossings,
439
+ self.constraints, self.new_basis)
440
+ derivatives, Optimum_zc_dict = der.derivatives, der.zc_dict
441
+
442
+ end = time.time()
443
+
444
+ if self.print_output in [1, 2]:
445
+ print('#'*50)
446
+ print('-'*20 + 'OPTIMUM RESULT' + '-'*20)
447
+ print('Time:', end-start)
448
+ print('Polynomial Order:', self.N)
449
+ if self.zero_crossings is not None:
450
+ print(
451
+ 'Number of Constrained Derivatives:',
452
+ self.N-self.constraints-len(self.zero_crossings))
453
+ else:
454
+ print(
455
+ 'Number of Constrained Derivatives:',
456
+ self.N-self.constraints)
457
+ print('Signs :', Optimum_sign_combination)
458
+ print('Objective Function Value:', Optimum_chi_squared)
459
+ print('Parameters:', Optimum_params.T)
460
+ print('Method:', self.fit_type)
461
+ print('Model:', self.model_type)
462
+ print('Constraints: m >=', self.constraints)
463
+ if self.zero_crossings is None:
464
+ print(
465
+ 'Zero Crossings Used?' +
466
+ ' (0 signifies Yes\n in derivative order "i"):',
467
+ Optimum_zc_dict)
468
+ if self.zero_crossings is not None:
469
+ print('Zero Crossing Derivatives:', self.zero_crossings)
470
+ print(
471
+ 'Zero Crossings Used?' +
472
+ ' (0 signifies Yes\n in derivative order "i"):',
473
+ Optimum_zc_dict)
474
+ print('-'*50)
475
+ print('#'*50)
476
+
477
+ save_optimum(
478
+ self.base_dir, end-start, self.N,
479
+ Optimum_sign_combination, Optimum_chi_squared,
480
+ Optimum_params, self.fit_type, self.model_type,
481
+ self.zero_crossings, Optimum_zc_dict, self.constraints)
482
+
483
+ return y_fit, derivatives, Optimum_chi_squared, Optimum_params, \
484
+ Optimum_sign_combination, Optimum_zc_dict
485
+
486
+ def qp_sign_flipping(x, y, pivot_point): # Sign Sampling
487
+
488
+ start = time.time()
489
+
490
+ if self.zero_crossings is not None:
491
+ array_signs = signs_array([1]*(
492
+ self.N-self.constraints-len(self.zero_crossings)))
493
+ else:
494
+ array_signs = signs_array([1]*(self.N-self.constraints))
495
+
496
+ r = np.random.randint(0, len(array_signs), 1)
497
+ signs = array_signs[r][0]
498
+
499
+ tested_indices = []
500
+ chi_squared = []
501
+ parameters = []
502
+ tested_signs = []
503
+ for i in range(len(array_signs)):
504
+ if i == r:
505
+ tested_indices.append(i)
506
+ precomputed = precompute_matrices(
507
+ x, y, self.N, pivot_point, self.model_type,
508
+ self.zero_crossings, self.constraints, self.new_basis)
509
+ fit = qp_class(
510
+ x, y, self.N, signs, pivot_point,
511
+ self.model_type, self.cvxopt_maxiter,
512
+ self.zero_crossings,
513
+ self.initial_params, self.constraints, self.new_basis,
514
+ precomputed=precomputed)
515
+ chi_squared.append(fit.chi_squared)
516
+ tested_signs.append(signs)
517
+ parameters.append(fit.parameters)
518
+ chi_squared_old = fit.chi_squared
519
+ previous_signs = signs
520
+
521
+ if self.print_output == 2:
522
+ print('-'*50)
523
+ print('Polynomial Order:', self.N)
524
+ if self.zero_crossings is not None:
525
+ print(
526
+ 'Number of Constrained Derivatives:',
527
+ self.N-self.constraints-len(self.zero_crossings))
528
+ else:
529
+ print(
530
+ 'Number of Constrained Derivatives:',
531
+ self.N-self.constraints)
532
+ print('Signs :', signs)
533
+ print('Objective Function Value:', chi_squared_old)
534
+ print('Parameters:', (fit.parameters).T)
535
+ print('Method:', self.fit_type)
536
+ print('Model:', self.model_type)
537
+ print('Constraints: m >=', self.constraints)
538
+ if self.zero_crossings is None:
539
+ print(
540
+ 'Zero Crossings Used?' +
541
+ ' (0 signifies Yes\n in derivative order "i"):',
542
+ fit.zc_dict)
543
+ if self.zero_crossings is not None:
544
+ print(
545
+ 'Zero Crossing Derivatives:',
546
+ self.zero_crossings)
547
+ print(
548
+ 'Zero Crossings Used? (0 signifies' +
549
+ 'Yes\n in derivative order "i"):', fit.zc_dict)
550
+ print('-'*50)
551
+ if self.data_save is True:
552
+ save(
553
+ self.base_dir, fit.parameters, fit.chi_squared,
554
+ signs, self.N, self.fit_type)
555
+
556
+ # Transforms or 'steps' of sign combination
557
+ sign_transform = []
558
+ for i in range(len(signs)):
559
+ base = np.array([1]*len(signs))
560
+ base[i] = -1
561
+ sign_transform.append(base)
562
+ sign_transform = np.array(sign_transform)
563
+ chi_squared_new = 0
564
+
565
+ while chi_squared_new < chi_squared_old:
566
+ if chi_squared_new != 0:
567
+ chi_squared_old = chi_squared_new
568
+ for h in range(sign_transform.shape[0]):
569
+ signs = previous_signs * sign_transform[h]
570
+ for i in range(len(array_signs)):
571
+ if np.all(signs == array_signs[i]):
572
+ ind = i
573
+ if ind in set(tested_indices):
574
+ pass
575
+ else:
576
+ tested_indices.append(ind)
577
+ fit = qp_class(
578
+ x, y, self.N, signs, pivot_point,
579
+ self.model_type, self.cvxopt_maxiter,
580
+ self.zero_crossings, self.initial_params,
581
+ self.constraints, self.new_basis,
582
+ precomputed=precomputed)
583
+ if fit.chi_squared < chi_squared_old:
584
+ chi_squared_new = fit.chi_squared
585
+ previous_signs = signs
586
+ chi_squared.append(fit.chi_squared)
587
+ tested_signs.append(signs)
588
+ parameters.append(fit.parameters)
589
+
590
+ if self.print_output == 2:
591
+ print('-'*50)
592
+ print('Polynomial Order:', self.N)
593
+ if self.zero_crossings is not None:
594
+ print(
595
+ 'Number of Constrained Derivatives:',
596
+ self.N - self.constraints -
597
+ len(self.zero_crossings))
598
+ else:
599
+ print(
600
+ 'Number of Constrained Derivatives:',
601
+ self.N-self.constraints)
602
+ print('Signs :', signs)
603
+ print(
604
+ 'Objective Function Value:',
605
+ fit.chi_squared)
606
+ print('Parameters:', fit.parameters.T)
607
+ print('Method:', self.fit_type)
608
+ print('Model:', self.model_type)
609
+ print('Constraints: m >=', self.constraints)
610
+ if self.zero_crossings is None:
611
+ print(
612
+ 'Zero Crossings Used?' +
613
+ ' (0 signifies Yes\n in derivative' +
614
+ ' order "i"):',
615
+ fit.zc_dict)
616
+ if self.zero_crossings is not None:
617
+ print(
618
+ 'Zero Crossing Derivatives:',
619
+ self.zero_crossings)
620
+ print(
621
+ 'Zero Crossings Used?' +
622
+ ' (0 signifies' +
623
+ 'Yes\n in derivative order "i"):',
624
+ fit.zc_dict)
625
+ print('-'*50)
626
+ if self.data_save is True:
627
+ save(
628
+ self.base_dir, fit.parameters,
629
+ fit.chi_squared,
630
+ signs, self.N, self.fit_type)
631
+
632
+ break
633
+ if h == sign_transform.shape[0] - 1:
634
+ chi_squared_new = chi_squared_old
635
+ break
636
+
637
+ if self.data_save is True:
638
+ np.save(
639
+ self.base_dir + str(self.N) +
640
+ '_'+self.fit_type+'_minimum_chi_post_descent.npy',
641
+ min(chi_squared))
642
+
643
+ if self.chi_squared_limit is not None:
644
+ lim = self.chi_squared_limit*min(chi_squared)
645
+ else:
646
+ lim = 2*min(chi_squared)
647
+
648
+ if self.cap is not None:
649
+ cap = self.cap
650
+ else:
651
+ cap = (len(array_signs)//self.N) + self.N
652
+
653
+ for i in range(len(array_signs)):
654
+ if np.all(previous_signs == array_signs[i]):
655
+ index = i
656
+
657
+ down_int = 1
658
+ while down_int < cap:
659
+ if index-down_int < 0:
660
+ break
661
+ elif (index-down_int) in set(tested_indices):
662
+ chi_down = 0
663
+ pass
664
+ else:
665
+ signs = array_signs[index-down_int]
666
+ tested_indices.append(index - down_int)
667
+ fit = qp_class(
668
+ x, y, self.N, signs, pivot_point,
669
+ self.model_type, self.cvxopt_maxiter,
670
+ self.zero_crossings, self.initial_params,
671
+ self.constraints, self.new_basis,
672
+ precomputed=precomputed)
673
+ chi_down = fit.chi_squared
674
+ chi_squared.append(fit.chi_squared)
675
+ tested_signs.append(signs)
676
+ parameters.append(fit.parameters)
677
+
678
+ if self.print_output == 2:
679
+ print('-'*50)
680
+ print('Polynomial Order:', self.N)
681
+ if self.zero_crossings is not None:
682
+ print(
683
+ 'Number of Constrained Derivatives:',
684
+ self.N-self.constraints -
685
+ len(self.zero_crossings))
686
+ else:
687
+ print(
688
+ 'Number of Constrained Derivatives:',
689
+ self.N-self.constraints)
690
+ print('Signs :', signs)
691
+ print('Objective Function Value:', fit.chi_squared)
692
+ print('Parameters:', fit.parameters.T)
693
+ print('Method:', self.fit_type)
694
+ print('Model:', self.model_type)
695
+ print('Constraints: m >=', self.constraints)
696
+ if self.zero_crossings is None:
697
+ print(
698
+ 'Zero Crossings Used?' +
699
+ ' (0 signifies Yes\n in derivative' +
700
+ ' order "i"):',
701
+ fit.zc_dict)
702
+ if self.zero_crossings is not None:
703
+ print(
704
+ 'Zero Crossing Derivatives:',
705
+ self.zero_crossings)
706
+ print(
707
+ 'Zero Crossings Used? (0 signifies' +
708
+ 'Yes\n in derivative order "i"):',
709
+ fit.zc_dict)
710
+ print('-'*50)
711
+ if self.data_save is True:
712
+ save(
713
+ self.base_dir, fit.parameters, fit.chi_squared,
714
+ signs, self.N, self.fit_type)
715
+
716
+ if chi_down > lim:
717
+ break
718
+ down_int += 1
719
+
720
+ up_int = 1
721
+ while up_int < cap:
722
+ if index+up_int >= len(array_signs):
723
+ break
724
+ elif (index + up_int) in set(tested_indices):
725
+ chi_up = 0
726
+ pass
727
+ else:
728
+ signs = array_signs[index+up_int]
729
+ tested_indices.append(index + up_int)
730
+ fit = qp_class(
731
+ x, y, self.N, signs, pivot_point,
732
+ self.model_type, self.cvxopt_maxiter,
733
+ self.zero_crossings, self.initial_params,
734
+ self.constraints, self.new_basis,
735
+ precomputed=precomputed)
736
+ chi_up = fit.chi_squared
737
+ chi_squared.append(fit.chi_squared)
738
+ tested_signs.append(signs)
739
+ parameters.append(fit.parameters)
740
+
741
+ if self.print_output == 2:
742
+ print('-'*50)
743
+ print('Polynomial Order:', self.N)
744
+ if self.zero_crossings is not None:
745
+ print(
746
+ 'Number of Constrained Derivatives:',
747
+ self.N-self.constraints -
748
+ len(self.zero_crossings))
749
+ else:
750
+ print(
751
+ 'Number of Constrained Derivatives:',
752
+ self.N-self.constraints)
753
+ print('Signs :', signs)
754
+ print('Objective Function Value:', fit.chi_squared)
755
+ print('Parameters:', fit.parameters.T)
756
+ print('Method:', self.fit_type)
757
+ print('Model:', self.model_type)
758
+ print('Constraints: m >=', self.constraints)
759
+ if self.zero_crossings is None:
760
+ print(
761
+ 'Zero Crossings Used?' +
762
+ ' (0 signifies Yes\n in derivative' +
763
+ ' order "i"):',
764
+ fit.zc_dict)
765
+ if self.zero_crossings is not None:
766
+ print(
767
+ 'Zero Crossing Derivatives:',
768
+ self.zero_crossings)
769
+ print(
770
+ 'Zero Crossings Used? (0 signifies' +
771
+ 'Yes\n in derivative order "i"):',
772
+ fit.zc_dict)
773
+ print('-'*50)
774
+ if self.data_save is True:
775
+ save(
776
+ self.base_dir, fit.parameters, fit.chi_squared,
777
+ signs, self.N, self.fit_type)
778
+
779
+ if chi_up > lim:
780
+ break
781
+ up_int += 1
782
+
783
+ for i in range(len(chi_squared)):
784
+ if chi_squared[i] == min(chi_squared):
785
+ Optimum_params = parameters[i]
786
+ Optimum_sign_combination = tested_signs[i]
787
+ Optimum_chi_squared = chi_squared[i]
788
+
789
+ y_fit = Models_class(
790
+ Optimum_params, x, y, self.N, pivot_point,
791
+ self.model_type, self.new_basis).y_sum
792
+ der = derivative_class(
793
+ x, y, Optimum_params, self.N,
794
+ pivot_point, self.model_type, self.zero_crossings,
795
+ self.constraints, self.new_basis)
796
+ derivatives, Optimum_zc_dict = der.derivatives, der.zc_dict
797
+
798
+ end = time.time()
799
+
800
+ if self.print_output in [1, 2]:
801
+ print('#'*50)
802
+ print('-'*20 + 'OPTIMUM RESULT' + '-'*20)
803
+ print('Time:', end-start)
804
+ print('Polynomial Order:', self.N)
805
+ if self.zero_crossings is not None:
806
+ print(
807
+ 'Number of Constrained Derivatives:',
808
+ self.N-self.constraints-len(self.zero_crossings))
809
+ else:
810
+ print(
811
+ 'Number of Constrained Derivatives:',
812
+ self.N-self.constraints)
813
+ print('Signs :', Optimum_sign_combination)
814
+ print('Objective Function Value:', Optimum_chi_squared)
815
+ print('Parameters:', Optimum_params.T)
816
+ print('Method:', self.fit_type)
817
+ print('Model:', self.model_type)
818
+ print('Constraints: m >=', self.constraints)
819
+ if self.zero_crossings is None:
820
+ print(
821
+ 'Zero Crossings Used?' +
822
+ ' (0 signifies Yes\n in derivative order "i"):',
823
+ Optimum_zc_dict)
824
+ if self.zero_crossings is not None:
825
+ print('Zero Crossing Derivatives:', self.zero_crossings)
826
+ print(
827
+ 'Zero Crossings Used?' +
828
+ ' (0 signifies Yes\n in derivative order "i"):',
829
+ Optimum_zc_dict)
830
+ print('-'*50)
831
+ print('#'*50)
832
+
833
+ save_optimum(
834
+ self.base_dir, end-start, self.N,
835
+ Optimum_sign_combination, Optimum_chi_squared,
836
+ Optimum_params, self.fit_type, self.model_type,
837
+ self.zero_crossings, Optimum_zc_dict, self.constraints)
838
+
839
+ return y_fit, derivatives, Optimum_chi_squared, Optimum_params, \
840
+ Optimum_sign_combination, Optimum_zc_dict
841
+
842
+ if self.fit_type == 'qp':
843
+ y_fit, derivatives, Optimum_chi_squared, Optimum_params, \
844
+ Optimum_sign_combination, Optimum_zc_dict = \
845
+ qp(self.x, self.y, self.pivot_point)
846
+ if self.fit_type == 'qp-sign_flipping':
847
+ y_fit, derivatives, Optimum_chi_squared, Optimum_params, \
848
+ Optimum_sign_combination, Optimum_zc_dict = \
849
+ qp_sign_flipping(self.x, self.y, self.pivot_point)
850
+
851
+ rms = (np.sqrt(np.sum((self.y-y_fit)**2)/len(self.y)))
852
+
853
+ return y_fit, Optimum_sign_combination, Optimum_params, derivatives, \
854
+ Optimum_chi_squared, rms, Optimum_zc_dict