FluctuationAnalysisTools 1.6.1__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.
Files changed (30) hide show
  1. fluctuationanalysistools-1.6.1/FluctuationAnalysisTools.egg-info/PKG-INFO +36 -0
  2. fluctuationanalysistools-1.6.1/FluctuationAnalysisTools.egg-info/SOURCES.txt +28 -0
  3. fluctuationanalysistools-1.6.1/FluctuationAnalysisTools.egg-info/dependency_links.txt +1 -0
  4. fluctuationanalysistools-1.6.1/FluctuationAnalysisTools.egg-info/top_level.txt +2 -0
  5. fluctuationanalysistools-1.6.1/LICENSE.txt +7 -0
  6. fluctuationanalysistools-1.6.1/MANIFEST.in +1 -0
  7. fluctuationanalysistools-1.6.1/PKG-INFO +36 -0
  8. fluctuationanalysistools-1.6.1/README.md +27 -0
  9. fluctuationanalysistools-1.6.1/StatTools/Gamma.py +145 -0
  10. fluctuationanalysistools-1.6.1/StatTools/__init__.py +0 -0
  11. fluctuationanalysistools-1.6.1/StatTools/analysis/__init__.py +2 -0
  12. fluctuationanalysistools-1.6.1/StatTools/analysis/dfa.py +235 -0
  13. fluctuationanalysistools-1.6.1/StatTools/analysis/dpcca.py +250 -0
  14. fluctuationanalysistools-1.6.1/StatTools/analysis/dpcca_as_class.py +128 -0
  15. fluctuationanalysistools-1.6.1/StatTools/analysis/fa.py +87 -0
  16. fluctuationanalysistools-1.6.1/StatTools/analysis/movmean.py +25 -0
  17. fluctuationanalysistools-1.6.1/StatTools/analysis/qss.py +204 -0
  18. fluctuationanalysistools-1.6.1/StatTools/auxiliary.py +340 -0
  19. fluctuationanalysistools-1.6.1/StatTools/generators/__init__.py +2 -0
  20. fluctuationanalysistools-1.6.1/StatTools/generators/base_filter.py +248 -0
  21. fluctuationanalysistools-1.6.1/StatTools/generators/cholesky_transform.py +118 -0
  22. fluctuationanalysistools-1.6.1/StatTools/generators/fbm.py +117 -0
  23. fluctuationanalysistools-1.6.1/StatTools/generators/field_generator.py +402 -0
  24. fluctuationanalysistools-1.6.1/StatTools_C_API.cpp +374 -0
  25. fluctuationanalysistools-1.6.1/pyproject.toml +21 -0
  26. fluctuationanalysistools-1.6.1/requirements.txt +7 -0
  27. fluctuationanalysistools-1.6.1/setup.cfg +4 -0
  28. fluctuationanalysistools-1.6.1/setup.py +19 -0
  29. fluctuationanalysistools-1.6.1/tests/test_dpcca.py +126 -0
  30. fluctuationanalysistools-1.6.1/tests/test_fa.py +87 -0
@@ -0,0 +1,36 @@
1
+ Metadata-Version: 2.2
2
+ Name: FluctuationAnalysisTools
3
+ Version: 1.6.1
4
+ Summary: This library allows to create and process long-term dependent datasets.
5
+ Author-email: Aleksandr Sinitca <amsinitca@etu.ru>, Alexandr Kuzmenko <alexander.k.spb@gmail.com>, Asya Lyanova <ailianova@etu.ru>
6
+ Maintainer-email: Aleksandr Sinitca <amsinitca@etu.ru>
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE.txt
9
+
10
+ # StatTools
11
+ This library allows to create and process long-term dependent datasets.
12
+
13
+ ## Installation:
14
+
15
+ python setup.py install
16
+
17
+ ## Basis usage
18
+
19
+ 1. To create a simple dataset with given Hurst parameter:
20
+
21
+ ```python
22
+ from StatTools.filters import FilteredArray
23
+
24
+ h = 0.8 # choose Hurst parameter
25
+ total_vectors = 1000 # total number of vectors in output
26
+ vectors_length = 1440 # each vector's length
27
+ t = 8 # threads in use during computation
28
+
29
+ correlated_vectors = Filter(h, vectors_length).generate(n_vectors=total_vectors,
30
+ threads=t, progress_bar=True)
31
+ ```
32
+
33
+ ## Contributors
34
+
35
+ * [Alexandr Kuzmenko](https://github.com/alexandr-1k)
36
+ * [Aleksandr Sinitca](https://github.com/Sinitca-Aleksandr)
@@ -0,0 +1,28 @@
1
+ LICENSE.txt
2
+ MANIFEST.in
3
+ README.md
4
+ StatTools_C_API.cpp
5
+ pyproject.toml
6
+ requirements.txt
7
+ setup.py
8
+ FluctuationAnalysisTools.egg-info/PKG-INFO
9
+ FluctuationAnalysisTools.egg-info/SOURCES.txt
10
+ FluctuationAnalysisTools.egg-info/dependency_links.txt
11
+ FluctuationAnalysisTools.egg-info/top_level.txt
12
+ StatTools/Gamma.py
13
+ StatTools/__init__.py
14
+ StatTools/auxiliary.py
15
+ StatTools/analysis/__init__.py
16
+ StatTools/analysis/dfa.py
17
+ StatTools/analysis/dpcca.py
18
+ StatTools/analysis/dpcca_as_class.py
19
+ StatTools/analysis/fa.py
20
+ StatTools/analysis/movmean.py
21
+ StatTools/analysis/qss.py
22
+ StatTools/generators/__init__.py
23
+ StatTools/generators/base_filter.py
24
+ StatTools/generators/cholesky_transform.py
25
+ StatTools/generators/fbm.py
26
+ StatTools/generators/field_generator.py
27
+ tests/test_dpcca.py
28
+ tests/test_fa.py
@@ -0,0 +1,7 @@
1
+ Copyright 2021 Alexandr Kuzmenko
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1 @@
1
+ include requirements.txt
@@ -0,0 +1,36 @@
1
+ Metadata-Version: 2.2
2
+ Name: FluctuationAnalysisTools
3
+ Version: 1.6.1
4
+ Summary: This library allows to create and process long-term dependent datasets.
5
+ Author-email: Aleksandr Sinitca <amsinitca@etu.ru>, Alexandr Kuzmenko <alexander.k.spb@gmail.com>, Asya Lyanova <ailianova@etu.ru>
6
+ Maintainer-email: Aleksandr Sinitca <amsinitca@etu.ru>
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE.txt
9
+
10
+ # StatTools
11
+ This library allows to create and process long-term dependent datasets.
12
+
13
+ ## Installation:
14
+
15
+ python setup.py install
16
+
17
+ ## Basis usage
18
+
19
+ 1. To create a simple dataset with given Hurst parameter:
20
+
21
+ ```python
22
+ from StatTools.filters import FilteredArray
23
+
24
+ h = 0.8 # choose Hurst parameter
25
+ total_vectors = 1000 # total number of vectors in output
26
+ vectors_length = 1440 # each vector's length
27
+ t = 8 # threads in use during computation
28
+
29
+ correlated_vectors = Filter(h, vectors_length).generate(n_vectors=total_vectors,
30
+ threads=t, progress_bar=True)
31
+ ```
32
+
33
+ ## Contributors
34
+
35
+ * [Alexandr Kuzmenko](https://github.com/alexandr-1k)
36
+ * [Aleksandr Sinitca](https://github.com/Sinitca-Aleksandr)
@@ -0,0 +1,27 @@
1
+ # StatTools
2
+ This library allows to create and process long-term dependent datasets.
3
+
4
+ ## Installation:
5
+
6
+ python setup.py install
7
+
8
+ ## Basis usage
9
+
10
+ 1. To create a simple dataset with given Hurst parameter:
11
+
12
+ ```python
13
+ from StatTools.filters import FilteredArray
14
+
15
+ h = 0.8 # choose Hurst parameter
16
+ total_vectors = 1000 # total number of vectors in output
17
+ vectors_length = 1440 # each vector's length
18
+ t = 8 # threads in use during computation
19
+
20
+ correlated_vectors = Filter(h, vectors_length).generate(n_vectors=total_vectors,
21
+ threads=t, progress_bar=True)
22
+ ```
23
+
24
+ ## Contributors
25
+
26
+ * [Alexandr Kuzmenko](https://github.com/alexandr-1k)
27
+ * [Aleksandr Sinitca](https://github.com/Sinitca-Aleksandr)
@@ -0,0 +1,145 @@
1
+ import numpy
2
+ from tqdm import tqdm
3
+ from multiprocessing import Pool, Value, Array, Lock
4
+ from ctypes import c_double
5
+ from contextlib import closing
6
+ from threading import Thread
7
+ from StatTools.analysis.dfa import bar_manager
8
+ from functools import partial
9
+
10
+
11
+ class GammaReplacement():
12
+
13
+ def __init__(self, dataset, set_mean=20, set_std=6):
14
+
15
+ if set_mean < 0:
16
+ error_str = "\tGammaReplacement Error: Mean value is not supposed to be negative!"
17
+ raise NameError(error_str)
18
+
19
+ if set_std ==0 or set_mean == 0:
20
+ error_str = "\tGammaReplacement Error: Zero mean or std!"
21
+ raise NameError(error_str)
22
+
23
+ if not isinstance(dataset, type(numpy.array([]))):
24
+ self.dataset = numpy.array(dataset)
25
+
26
+ else:
27
+ self.dataset = dataset
28
+
29
+ self.set_std = set_std
30
+ self.set_mean = set_mean
31
+
32
+ @staticmethod
33
+ def rank_replacement_with_gamma(initial_vector):
34
+ sorted_x1 = numpy.sort(initial_vector)
35
+
36
+ var_normal = numpy.var(initial_vector, ddof=1)
37
+ mean_normal = numpy.mean(initial_vector)
38
+
39
+ theta = var_normal / mean_normal
40
+ k = mean_normal / (var_normal / mean_normal)
41
+ validation_vector = numpy.random.mtrand.gamma(k, theta, len(initial_vector))
42
+
43
+ sorted_x2 = numpy.sort(validation_vector)
44
+
45
+ # @njit(cache=True)
46
+ def rank_replacement_core(x1, sorted_x1, sorted_x2):
47
+ for i in range(len(x1)):
48
+ get_index_in_sorted_x1 = numpy.where(sorted_x1 == x1[i])[0][0]
49
+ x1[i] = sorted_x2[get_index_in_sorted_x1]
50
+ return x1
51
+
52
+ x1 = rank_replacement_core(initial_vector, sorted_x1, sorted_x2)
53
+
54
+ return x1
55
+
56
+ def perform(self, threads=1, progress_bar=False):
57
+
58
+ if threads == 1:
59
+
60
+ if self.dataset.size > pow(10, 6):
61
+ print("\tGamaReplacement Warning: Given the size of input dataset it'd be faster to use more threads . . .")
62
+
63
+ if progress_bar:
64
+ bar = tqdm(desc="GammaReplacment", total=len(self.dataset), leave=False, position=0)
65
+
66
+ one_dim = False
67
+
68
+ if self.dataset.ndim == 1:
69
+
70
+ self.dataset = [self.dataset]
71
+ one_dim = True
72
+
73
+ for v, vector in enumerate(self.dataset):
74
+ self.dataset[v] = self.dataset[v] * (self.set_std / numpy.std(self.dataset[v], ddof=1))
75
+ self.dataset[v] = self.dataset[v] + (-numpy.mean(self.dataset[v]) + self.set_mean)
76
+ self.dataset[v] = self.rank_replacement_with_gamma(self.dataset[v])
77
+ self.dataset[v] = self.dataset[v] * (self.set_std / numpy.std(self.dataset[v], ddof=1))
78
+ self.dataset[v] = self.dataset[v] + (-numpy.mean(self.dataset[v]) + self.set_mean)
79
+ a = numpy.std(self.dataset[v], ddof=1)
80
+ if progress_bar:
81
+ bar.update(1)
82
+
83
+ if one_dim:
84
+ return self.dataset[0]
85
+
86
+ return self.dataset
87
+
88
+ else:
89
+
90
+ vectors_indices = numpy.linspace(0, len(self.dataset) - 1, len(self.dataset), dtype=int)
91
+ vectors_by_threads = numpy.array_split(vectors_indices, threads)
92
+
93
+ shared_initial_dataset = Array(c_double, self.dataset.size)
94
+ vectors_num = len(self.dataset)
95
+ vectors_length = len(self.dataset[0])
96
+
97
+ numpy.copyto(numpy.frombuffer(shared_initial_dataset.get_obj()).reshape((vectors_num, vectors_length)),
98
+ self.dataset)
99
+
100
+ bar_value = Value('i', 0)
101
+ stop_bit = Value('i', 0)
102
+ lock = Lock()
103
+
104
+ if progress_bar:
105
+ bar = Thread(target=bar_manager, args=('GammaReplacement', vectors_num, bar_value, lock, 'total', stop_bit))
106
+ bar.start()
107
+
108
+ with closing(Pool(processes=threads, initializer=self.global_initializer, initargs=(shared_initial_dataset,
109
+ bar_value, lock))) as pool:
110
+ pool.map(partial(self.processing_vectors, set_mean=self.set_mean, set_std=self.set_std, vectors_num=vectors_num,
111
+ vectors_length=vectors_length, function=self.rank_replacement_with_gamma), vectors_by_threads)
112
+
113
+ stop_bit.value += 1
114
+
115
+ output_array = numpy.frombuffer(shared_initial_dataset.get_obj()).reshape((vectors_num, vectors_length))
116
+
117
+ return output_array
118
+
119
+ @staticmethod
120
+ def global_initializer(shared_init_data, b_val, b_lk):
121
+ global SHARED_VECTORS
122
+ global BAR_VALUE
123
+ global BAR_LOCK
124
+ SHARED_VECTORS = shared_init_data
125
+ BAR_VALUE = b_val
126
+ BAR_LOCK = b_lk
127
+
128
+
129
+ @staticmethod
130
+ def processing_vectors(indices, set_mean, set_std, vectors_num, vectors_length, function):
131
+
132
+ def get_pointer():
133
+ return numpy.frombuffer(SHARED_VECTORS.get_obj(), dtype=c_double).reshape((vectors_num, vectors_length))
134
+
135
+ for v in indices:
136
+ vector = get_pointer()[v]
137
+ vector = vector * (set_std / numpy.std(vector, ddof=1))
138
+ vector = vector + numpy.abs(numpy.mean(vector) - set_mean)
139
+ vector = function(vector)
140
+ vector = vector * (set_std / numpy.std(vector, ddof=1))
141
+ vector = vector + numpy.abs(numpy.mean(vector) - set_mean)
142
+ get_pointer()[v] = vector
143
+
144
+ with BAR_LOCK:
145
+ BAR_VALUE.value += 1
File without changes
@@ -0,0 +1,2 @@
1
+ from .fa import fa
2
+ from .dpcca import dpcca
@@ -0,0 +1,235 @@
1
+ import numpy
2
+ from math import floor, exp, ceil
3
+ from multiprocessing import Pool, Array, Value, Lock, cpu_count
4
+ from ctypes import c_double
5
+ from contextlib import closing
6
+ from threading import Thread
7
+ from functools import partial
8
+ from tqdm import tqdm, TqdmWarning
9
+ import time
10
+
11
+
12
+ def bar_manager(description, total, counter, lock, mode="total", stop_bit=None):
13
+ max_val = total
14
+ if mode == "percent":
15
+ max_val = 100
16
+ with closing(tqdm(desc=description, total=max_val, leave=False, position=0)) as bar:
17
+
18
+ try:
19
+ last_val = counter.value
20
+ while True:
21
+ if stop_bit is not None:
22
+ if stop_bit.value > 0:
23
+ break
24
+
25
+ time.sleep(0.25)
26
+ with lock:
27
+ if counter.value > last_val:
28
+ if mode == "percent":
29
+ bar.update(round(((counter.value - last_val) * 100 / total), 2))
30
+ else:
31
+ bar.update(counter.value - last_val)
32
+ last_val = counter.value
33
+
34
+ if counter.value == total:
35
+ bar.close()
36
+ break
37
+ except TqdmWarning:
38
+ return None
39
+
40
+ class DFA:
41
+
42
+ def __init__(self, dataset, degree=2, root=False, ignore_input_control=False):
43
+ if ignore_input_control:
44
+ s_return_1d, F_s_return_1d = self.dfa_core_cycle(dataset, degree, root)
45
+ self.s = s_return_1d
46
+ self.F_s = F_s_return_1d
47
+ else:
48
+ if isinstance(dataset, type("string")):
49
+ try:
50
+ dataset = numpy.loadtxt(dataset)
51
+ except OSError:
52
+ error_str = "\n The file either doesn't exit or you use wrong path!"
53
+ raise NameError(error_str)
54
+
55
+ if numpy.size(dataset) == 0:
56
+ error_str = "\n Input file is empty!"
57
+ raise NameError(error_str)
58
+
59
+ if not isinstance(dataset, type(numpy.array([]))):
60
+ try: # in case of list
61
+ dataset = numpy.array(dataset, dtype=float)
62
+ except ValueError:
63
+ error_str = "\n Input dataset is supposed to be numpy array, list or directory!"
64
+ raise NameError(error_str)
65
+
66
+ dataset = numpy.array(dataset)
67
+
68
+ if dataset.ndim > 2 or dataset.ndim == 0:
69
+ error_str = "\n You can not use such input array! Only 1- or 2-dimensional arrays are allowed!"
70
+ raise NameError(error_str)
71
+
72
+ self.dataset = dataset
73
+ self.degree = degree
74
+ self.root = root
75
+
76
+ if self.dataset.ndim == 1:
77
+ s_max = int(len(dataset) / 4)
78
+ try:
79
+ log_s_max = numpy.arange(1.6, numpy.log(s_max), 0.5)
80
+ except ValueError:
81
+ error_str = "\n Wrong input array ! (It's probably too short)"
82
+ raise NameError(error_str)
83
+ if numpy.size(log_s_max) < 1:
84
+ error_str = "\n Input array is too small! (It usually requires 20 or more samples!)"
85
+ raise NameError(error_str)
86
+
87
+ if self.dataset.ndim == 2:
88
+
89
+ s_max = int(len(dataset[0]) / 4)
90
+ try:
91
+ log_s_max = numpy.arange(1.6, numpy.log(s_max), 0.5)
92
+ except ValueError:
93
+ error_str = "\n Wrong input vectors in input matrix! (They are probably too short)"
94
+ raise NameError(error_str)
95
+ if numpy.size(log_s_max) < 1:
96
+ error_str = "\n Vectors in your input array are too short! Use longer vectors " \
97
+ "(it usually requires 20 or more samples) or transpose!"
98
+ raise NameError(error_str)
99
+
100
+ @staticmethod
101
+ def initializer_for_parallel_mod(shared_array, h_est, shared_c, shared_l):
102
+ global datasets_array
103
+ global estimations
104
+ global shared_counter
105
+ global shared_lock
106
+ datasets_array = shared_array
107
+ estimations = h_est
108
+ shared_counter = shared_c
109
+ shared_lock = shared_l
110
+
111
+ @staticmethod
112
+ def dfa_core_cycle(dataset, degree, root):
113
+ data_mean = numpy.mean(dataset)
114
+ data = dataset - data_mean
115
+ Y_cumsum = numpy.cumsum(data)
116
+
117
+ s_max = int(len(data) / 4)
118
+
119
+ log_s_max = numpy.arange(1.6, numpy.log(s_max), 0.5)
120
+
121
+ x_Axis = []
122
+ y_Axis = []
123
+
124
+ for step in log_s_max:
125
+ s = numpy.linspace(1, floor(exp(step)), floor(exp(step)), dtype=int)
126
+ cycles_amount = floor(len(data) / len(s))
127
+
128
+ F_q_s_sum = 0
129
+ for i in range(1, cycles_amount):
130
+ indices = numpy.array((s - (i + 0.5) * len(s)), dtype=int)
131
+ Y_cumsum_s = numpy.take(Y_cumsum, s)
132
+
133
+ coef = numpy.polyfit(indices, Y_cumsum_s, deg=degree)
134
+ current_trend = numpy.polyval(coef, indices)
135
+ F_2 = sum(pow((Y_cumsum_s - current_trend), 2)) / len(s)
136
+ F_q_s_sum += pow(F_2, (degree / 2))
137
+ s += floor(exp(step))
138
+
139
+ F1 = pow(((1 / cycles_amount) * F_q_s_sum), 1 / degree)
140
+ x_Axis.append(numpy.log(floor(exp(step))))
141
+ if root:
142
+ y_Axis.append(numpy.log(F1 / numpy.sqrt(len(s))))
143
+ else:
144
+ y_Axis.append(numpy.log(F1))
145
+
146
+ return numpy.array(x_Axis), numpy.array(y_Axis)
147
+
148
+ def find_h(self, simple_mode=True):
149
+ if self.dataset.ndim == 1:
150
+ self.s, self.F_s = self.dfa_core_cycle(self.dataset, self.degree, self.root)
151
+ else:
152
+ self.s = numpy.array([])
153
+ self.F_s = numpy.array([])
154
+ for vector in self.dataset:
155
+ s, F_s = self.dfa_core_cycle(vector, self.degree, self.root)
156
+ if numpy.size(self.s) < 1:
157
+ self.s = s
158
+ self.F_s = F_s
159
+ else:
160
+ self.s = numpy.vstack((self.s, s))
161
+ self.F_s = numpy.vstack((self.F_s, F_s))
162
+
163
+ if simple_mode:
164
+
165
+ if self.s.ndim == 1:
166
+ return numpy.polyfit(self.s, self.F_s, deg=1)[0]
167
+ else:
168
+ h_estimation = []
169
+ for s, F_s in zip(self.s, self.F_s):
170
+ h_estimation.append(numpy.polyfit(s, F_s, deg=1)[0])
171
+ return numpy.array(h_estimation)
172
+ else:
173
+ error_str = "\n Non-linear approximation is non supported yet!"
174
+ raise NameError(error_str)
175
+
176
+ def parallel_2d(self, threads=cpu_count(), progress_bar=False, h_control=False, h_target=float(), h_limit=float()):
177
+ if threads == 1 or self.dataset.ndim == 1:
178
+ return self.find_h()
179
+
180
+ if len(self.dataset) / threads < 1:
181
+ error_str = "\n DFA Warning: Input array is too small for using it in parallel mode!" \
182
+ f"\n You better use either less threads ({len(self.dataset)}) or don't use " \
183
+ f"parallel mode at all!"
184
+ print(error_str)
185
+ h_est = self.find_h()
186
+ return h_est
187
+
188
+ if len(self.dataset) / threads < 10:
189
+ error_str = "\n DFA Warning: It may be not so effective when using parallel mode with such small array!" \
190
+ "\n Spawning processes creates its own overhead!"
191
+ print(error_str)
192
+
193
+ vectors_indices_by_threads = numpy.array_split(numpy.linspace(0, len(self.dataset) - 1, len(self.dataset),
194
+ dtype=int), threads)
195
+
196
+ dataset_to_memory = Array(c_double, len(self.dataset) * len(self.dataset[0]))
197
+ h_estimation_in_memory = Array(c_double, len(self.dataset))
198
+ numpy.copyto(numpy.frombuffer(dataset_to_memory.get_obj()).reshape((len(self.dataset), len(self.dataset[0]))),
199
+ self.dataset)
200
+
201
+ shared_counter = Value('i', 0)
202
+ shared_lock = Lock()
203
+
204
+ if progress_bar:
205
+ bar_thread = Thread(target=bar_manager, args=(f"DFA", len(self.dataset), shared_counter, shared_lock))
206
+ bar_thread.start()
207
+
208
+ with closing(Pool(processes=threads, initializer=self.initializer_for_parallel_mod, initargs=
209
+ (dataset_to_memory, h_estimation_in_memory, shared_counter, shared_lock))) as pool:
210
+ invalid_i = pool.map(partial(self.parallel_core, quantity=len(self.dataset), length=len(self.dataset[0]),
211
+ h_control=h_control, h_target=h_target, h_limit=h_limit),
212
+ vectors_indices_by_threads)
213
+
214
+ if h_control:
215
+ invalid_i = numpy.concatenate(invalid_i)
216
+ return numpy.frombuffer(h_estimation_in_memory.get_obj()), invalid_i
217
+ else:
218
+ return numpy.frombuffer(h_estimation_in_memory.get_obj())
219
+
220
+ def parallel_core(self, indices, quantity, length, h_control, h_target, h_limit):
221
+
222
+ invalid_i = []
223
+ for i in indices:
224
+ vector = numpy.frombuffer(datasets_array.get_obj()).reshape((quantity, length))[i]
225
+ x_ax, y_ax = self.dfa_core_cycle(vector, self.degree, self.root)
226
+ lin_reg = numpy.polyfit(x_ax, y_ax, deg=1)[0]
227
+ numpy.frombuffer(estimations.get_obj())[i] = lin_reg
228
+ with shared_lock:
229
+ shared_counter.value += 1
230
+
231
+ if h_control:
232
+ if abs(lin_reg - h_target) > h_limit:
233
+ invalid_i.append(i)
234
+
235
+ return numpy.array(invalid_i)