SegmentSignalPy 0.1.2__cp312-cp312-win_amd64.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.
@@ -0,0 +1,167 @@
1
+ #include "SegmentSignal.h"
2
+ #include "NoiseVarianceEstimateMethod.h"
3
+ #include "SegmentSignalFunctions.h"
4
+ #include <vector>
5
+ #include <cmath>
6
+
7
+ using namespace std;
8
+
9
+ namespace Algorithms
10
+ {
11
+ SegmentationResults* SegmentSignal::Segment(double signal[], int signalLength, double threshold, int jumpSequenceWindowSize, int noiseVarianceWindowSize)
12
+ {
13
+ return Segment(signal, signalLength, threshold, jumpSequenceWindowSize, noiseVarianceWindowSize, NoiseVarianceEstimateMethod::Point, 300);
14
+ }
15
+
16
+ SegmentationResults* SegmentSignal::Segment(double signal[], int signalLength, double threshold, int jumpSequenceWindowSize, int noiseVarianceWindowSize, NoiseVarianceEstimateMethod noiseVarianceEstimateMethod)
17
+ {
18
+ return Segment(signal, signalLength, threshold, jumpSequenceWindowSize, noiseVarianceWindowSize, noiseVarianceEstimateMethod, 300);
19
+ }
20
+
21
+ SegmentationResults* SegmentSignal::Segment(double signal[], int signalLength, double threshold, int jumpSequenceWindowSize, int noiseVarianceWindowSize, NoiseVarianceEstimateMethod noiseVarianceEstimateMethod, int maxSMLRIterations)
22
+ {
23
+ // Scalars which are need for output from the call to the algorithm.
24
+ int numberOfBinaryEvents = 0;
25
+ double jumpSequenceVariance = 0;
26
+ double segmentDensity = 0;
27
+ int iterations = 0;
28
+ int error = 0;
29
+
30
+ // We seem to need to create the array in the function immediately prior to calling the unmanaged code, otherwise the garbage collector
31
+ // gets cute and moves things around, which the unmanaged code takes offense to.
32
+ //double* signalToPass = new double[signalLength];
33
+ //for (int i = 0; i < signalLength; i++)
34
+ //{
35
+ // signalToPass[i] = signal[i];
36
+ //}
37
+
38
+
39
+ // Create the output arrays. After being populated by the call to the algorithm they are grouped, stored, and returned in the SegmenationResults data structure.
40
+ int* Q = new int[signalLength]; // Binary event sequence.
41
+ double* FLTLOG = new double[signalLength]; // Filtered signal.
42
+ double* SEGLOG = new double[signalLength]; // Segmented log.
43
+ double* R = new double[signalLength]; // Noise variance.
44
+
45
+ // Function call to the C DLL.
46
+ ::SegmentSignal(signal, signalLength, threshold, jumpSequenceWindowSize, noiseVarianceWindowSize, (int)noiseVarianceEstimateMethod, maxSMLRIterations, Q, numberOfBinaryEvents, FLTLOG, SEGLOG, R, jumpSequenceVariance, segmentDensity, iterations, error);
47
+
48
+ return new SegmentationResults(signalLength, Q, numberOfBinaryEvents, FLTLOG, SEGLOG, R, jumpSequenceVariance, segmentDensity, iterations, error);
49
+ }
50
+
51
+ SegmentationResults* SegmentSignal::Segment(vector<double> signal, double threshold, int jumpSequenceWindowSize, int noiseVarianceWindowSize)
52
+ {
53
+ return Segment(signal, threshold, jumpSequenceWindowSize, noiseVarianceWindowSize, NoiseVarianceEstimateMethod::Point, 300);
54
+ }
55
+
56
+ SegmentationResults* SegmentSignal::Segment(vector<double> signal, double threshold, int jumpSequenceWindowSize, int noiseVarianceWindowSize, NoiseVarianceEstimateMethod noiseVarianceEstimateMethod)
57
+ {
58
+ return Segment(signal, threshold, jumpSequenceWindowSize, noiseVarianceWindowSize, noiseVarianceEstimateMethod, 300);
59
+ }
60
+
61
+ SegmentationResults* SegmentSignal::Segment(vector<double> signal, double threshold, int jumpSequenceWindowSize, int noiseVarianceWindowSize, NoiseVarianceEstimateMethod noiseVarianceEstimateMethod, int maxSMLRIterations)
62
+ {
63
+ // Scalars which are need for output from the call to the algorithm.
64
+ int numberOfBinaryEvents = 0;
65
+ double jumpSequenceVariance = 0;
66
+ double segmentDensity = 0;
67
+ int iterations = 0;
68
+ int error = 0;
69
+
70
+ int signalLength = (int)signal.size();
71
+ double* signalToPass = new double[signalLength];
72
+ for (int i = 0; i < signalLength; i++)
73
+ {
74
+ signalToPass[i] = signal[i];
75
+ }
76
+
77
+ // Create the output arrays. After being populated by the call to the algorithm they are grouped, stored, and returned in the SegmenationResults data structure.
78
+ int* Q = new int[signalLength]; // Binary event sequence.
79
+ double* FLTLOG = new double[signalLength]; // Filtered signal.
80
+ double* SEGLOG = new double[signalLength]; // Segmented log.
81
+ double* R = new double[signalLength]; // Noise variance.
82
+
83
+
84
+ int estimateMethod = (int)noiseVarianceEstimateMethod;
85
+
86
+ // Function call to the C DLL.
87
+ ::SegmentSignal(signalToPass, signalLength, threshold, jumpSequenceWindowSize, noiseVarianceWindowSize, estimateMethod, maxSMLRIterations, Q, numberOfBinaryEvents, FLTLOG, SEGLOG, R, jumpSequenceVariance, segmentDensity, iterations, error);
88
+
89
+ return new SegmentationResults(signalLength, Q, numberOfBinaryEvents, FLTLOG, SEGLOG, R, jumpSequenceVariance, segmentDensity, iterations, error);
90
+ }
91
+
92
+ vector<array<int, 2>>* SegmentSignal::FindSignificantZones(int binaryEvents[], double xData[], int signalLength, double threshold)
93
+ {
94
+ return FindSignificantZones(binaryEvents, xData, signalLength, threshold, false);
95
+ }
96
+
97
+ vector<array<int, 2>>* SegmentSignal::FindSignificantZones(int binaryEvents[], double xData[], int signalLength, double threshold, bool includeBoundaries)
98
+ {
99
+ vector<array<int, 2>>* significantZones = new vector<array<int, 2>>();
100
+
101
+ // Find the first "0" entry which will mark the beginning of a zone.
102
+ int zoneStart = FindNextZero(binaryEvents, signalLength, 0);
103
+
104
+ for (int currentIndex = zoneStart+1; currentIndex < signalLength; currentIndex++)
105
+ {
106
+ if (binaryEvents[currentIndex])
107
+ {
108
+ CheckIfValidZone(xData, threshold, includeBoundaries, significantZones, zoneStart, currentIndex-1);
109
+
110
+ // Scan for the start of the next potential section.
111
+ zoneStart = FindNextZero(binaryEvents, signalLength, currentIndex);
112
+ currentIndex = zoneStart;
113
+ }
114
+ }
115
+
116
+ // If the last entry of the binary events is zero, we need to handle the final section.
117
+ if (!binaryEvents[signalLength-1])
118
+ {
119
+ CheckIfValidZone(xData, threshold, includeBoundaries, significantZones, zoneStart, signalLength-1);
120
+ }
121
+
122
+ // When including the boundaries (includeBoundaries==true), it is possible to have added data points before the beginning of the array
123
+ // and after the end. We need to check for and, if they exist, correct them.
124
+ if (significantZones->size() > 0)
125
+ {
126
+ if ((*significantZones)[0][0] < 0)
127
+ {
128
+ (*significantZones)[0][0] = 0;
129
+ }
130
+
131
+ if ((*significantZones)[significantZones->size()-1][1] >= signalLength)
132
+ {
133
+ (*significantZones)[significantZones->size()-1][1] = signalLength-1;
134
+ }
135
+ }
136
+
137
+ return significantZones;
138
+ }
139
+
140
+ int SegmentSignal::FindNextZero(int binaryEvents[], int signalLength, int currentIndex)
141
+ {
142
+ // Find the first zero.
143
+ while (binaryEvents[currentIndex] && currentIndex < signalLength-1)
144
+ {
145
+ currentIndex++;
146
+ }
147
+ return currentIndex;
148
+ }
149
+
150
+ void SegmentSignal::CheckIfValidZone(double xData[], double threshold, bool includeBoundaries, vector<array<int, 2>>* significantZones, int startIndex, int endIndex)
151
+ {
152
+ // Check to see if the threshold is met. If it met, we will store the section
153
+ // as a significant zone. If the threshold is not met, then the zone is not long
154
+ // enough so it is ignored and we scan ahead.
155
+ if (abs(xData[endIndex] - xData[startIndex]) > threshold)
156
+ {
157
+ if (includeBoundaries)
158
+ {
159
+ significantZones->push_back({ {startIndex-1, endIndex+1} });
160
+ }
161
+ else
162
+ {
163
+ significantZones->push_back({{startIndex, endIndex}});
164
+ }
165
+ }
166
+ }
167
+ } // End namespace.
@@ -0,0 +1,797 @@
1
+ #include "SegmentSignalFunctions.h"
2
+ #include <stdlib.h>
3
+ #include <math.h>
4
+ #include <windows.h>
5
+ #include <malloc.h>
6
+ #include <stdexcept>
7
+
8
+ // Original function name: LOGSEG
9
+ void SegmentSignal(double LOG[], int NSAMPS, double F, int ORDER, int ORDER1, int RMODE, int NITER, int Q[], int& NQ, double FLTLOG[], double SEGLOG[], double R[], double& C, double& D, int& NACT, int& IER)
10
+ {
11
+ // Function:
12
+ // Maximum Likelihood Segmentation
13
+ //
14
+ // Input parameters:
15
+ // LOG: Input discretized well log.
16
+ //
17
+ // NSAMPS: Number of samples in array log.
18
+ //
19
+ // F: Segmentation threshold index.
20
+ //
21
+ // ORDER: Length of the moving average window used for smoothing the input well
22
+ // log to arrive at an initial estimate of jump sequence variance, C.
23
+ //
24
+ // ORDER1: Length of the moving average window used for smoothing the noise variances.
25
+ //
26
+ // RMODE: Noise variance estimate option.
27
+ // RMODE = 0 ==> Point estimate of noise variance.
28
+ // RMODE = 1 ==> Noise estimates smoothed within segments.
29
+ //
30
+ // NITER: Upper bound on the number of SingleMostLikelihoodReplacement iterations.
31
+ //
32
+ // Output parameters:
33
+ // Q: Binary event sequence.
34
+ //
35
+ // NQ: Number of binary events found (number of "1"s in Q).
36
+ //
37
+ // FLTLOG: Filtered estimate of the signal. Also used as intermediate work array.
38
+ //
39
+ // SEGLOG: FLTLOG averaged over each segment.
40
+ //
41
+ // R: Estimated noise variance.
42
+ //
43
+ // C: Estimated variance of the jump sequence.
44
+ //
45
+ // D: Estimated segment density.
46
+ //
47
+ // NACT: Actual SingleMostLikelihoodReplacement iteration count.
48
+ //
49
+ // IER: Error flag.
50
+ // IER = 0 ==> No error.
51
+ // IER < 0 ==> Invalid event density estimated after threshold. Reduce/increase F and rerun.
52
+ // IER > 0 ==> Logarithm argument became zero at sample number IER during the calculation of
53
+ // likelihood ratios in SingleMostLikelihoodReplacement. There may be more samples of this type which may give rise
54
+ // to this problem. Edit/rescale data values and rerun.
55
+
56
+ // Check input.
57
+ if (ORDER > NSAMPS || ORDER1 > NSAMPS)
58
+ {
59
+ throw std::runtime_error("SegmentSignal Error: The window sizes cannot exceed the signal length.");
60
+ }
61
+
62
+ // Intermediate work arrays.
63
+ double* WORK1 = (double*)malloc(NSAMPS * sizeof(double));
64
+ double* WORK2 = (double*)malloc(NSAMPS * sizeof(double));
65
+
66
+ int HORDER = ORDER / 2;
67
+ int NORDER = ORDER1 / 2;
68
+
69
+ // Ensure we did not round to 0.
70
+ if (HORDER < 1)
71
+ {
72
+ HORDER = 1;
73
+ }
74
+
75
+ if (NORDER < 1)
76
+ {
77
+ NORDER = 1;
78
+ }
79
+
80
+ int VMODE = 0;
81
+ bool CONV = false;
82
+ int ITER = 0;
83
+
84
+ double MEAN = 0.0;
85
+ double LBOUND = 0.1E-04;
86
+ double UBOUND = 0.98;
87
+
88
+ // Smooth input log using an HORDER point moving average (HORDER is number of points).
89
+ MovingAverage(LOG, NSAMPS, HORDER, SEGLOG);
90
+
91
+ // Initial estimate of c the variance of the jump sequence.
92
+ EstimateVarianceOfJumpSequence(SEGLOG, NSAMPS, WORK1, C);
93
+
94
+ // Estimate R, the variance of the noise.
95
+ for (int i = 0; i < NSAMPS; i++)
96
+ {
97
+ SEGLOG[i] = (LOG[i]-SEGLOG[i]) * (LOG[i]-SEGLOG[i]);
98
+ }
99
+
100
+ // Smooth the variance of the noise using an NORDER point moving average.
101
+ MovingAverage(SEGLOG, NSAMPS, NORDER, R);
102
+
103
+ // Bootstrap event sequence.
104
+ for (int i = 0; i < 2; i++)
105
+ {
106
+ // Initialize event sequence Q.
107
+ for (int j = 0; j < NSAMPS; j++)
108
+ {
109
+ Q[j] = 1;
110
+ }
111
+
112
+ // Invoke fixed interval optimal smoother to estimate the jump sequence, residual state, and its variance.
113
+ KalmanFilter(LOG, Q, C, R, NSAMPS, WORK2, WORK1, SEGLOG, FLTLOG);
114
+
115
+ FixedIntervalOptimalSmoother(Q, NSAMPS, C, SEGLOG, WORK1, WORK2);
116
+
117
+ // Re-estimate the variance of the jump sequence C.
118
+ CalculateMeanAndVariance(SEGLOG, NSAMPS, VMODE, MEAN, C);
119
+
120
+ // Invoke threshold detector and update the event sequence.
121
+ Threshold(SEGLOG, C, F, NSAMPS, Q, D);
122
+
123
+ // Deglitch the event sequence Q.
124
+ Deglitch(NSAMPS, Q);
125
+
126
+ // Update d, the event density.
127
+ EstimateEventDensity(Q, NSAMPS, D, NQ);
128
+ C = C / D;
129
+
130
+ // Deglitch and re-estimate R, the variance of noise.
131
+ DeglitchAndEstimateNoiseVariance(LOG, Q, NSAMPS, RMODE, SEGLOG, R);
132
+ }
133
+
134
+ // Trap event density if invalid.
135
+ if (D <= LBOUND || D >= UBOUND)
136
+ {
137
+ IER = -1;
138
+ }
139
+ else
140
+ {
141
+ // Start Single Most Likelihood Replacement iterations.
142
+ do
143
+ {
144
+ // Increment iteration counter.
145
+ ITER++;
146
+
147
+ // Invoke fixed interval optimal smoother to estimate jump sequence, residual state, and its variance.
148
+ KalmanFilter(LOG, Q, C, R, NSAMPS, WORK2, WORK1, SEGLOG, FLTLOG);
149
+
150
+ FixedIntervalOptimalSmoother(Q, NSAMPS, C, SEGLOG, WORK1, WORK2);
151
+
152
+ // Invoke Single Most Likelihood Replacement detector.
153
+ SingleMostLikelihoodReplacement(WORK2, WORK1, C, NSAMPS, D, Q, CONV, IER);
154
+
155
+ // Update event density d.
156
+ EstimateEventDensity(Q, NSAMPS, D, NQ);
157
+
158
+ }
159
+ // Check for SingleMostLikelihoodReplacement termination.
160
+ while (ITER < NITER && !CONV && IER == 0);
161
+
162
+ NACT = ITER;
163
+
164
+ // Re-run KalmanFilter filter to estimate the filtered log if SingleMostLikelihoodReplacement did not converge.
165
+ if (CONV != 1 && IER == 0)
166
+ {
167
+ KalmanFilter(LOG, Q, C, R, NSAMPS, WORK2, WORK1, SEGLOG, FLTLOG);
168
+ }
169
+ // Average filtered log over segments.
170
+ AverageArraySegments(FLTLOG, Q, NSAMPS, SEGLOG);
171
+ }
172
+
173
+ // Free memory.
174
+ free(WORK1);
175
+ free(WORK2);
176
+ }
177
+
178
+ // Original function name: SMLR
179
+ void SingleMostLikelihoodReplacement(double G[], double S[], double C, int NSAMPS, double D, int Q[], bool& CONV, int& IER)
180
+ {
181
+ // Function:
182
+ // Single most likelihood replacement detector for updating an event sequence Q(k).
183
+ //
184
+ // Input parameters:
185
+ // G: Residual state.
186
+ //
187
+ // S: Variance of the residual state.
188
+ //
189
+ // C: Variance of the jump sequence.
190
+ //
191
+ // NSAMPS: Length of the binary event sequence.
192
+ //
193
+ // D: Segment density.
194
+ //
195
+ // Input/output parameters:
196
+ // Q: Binary event sequence. This sequence is updated by SingleMostLikelihoodReplacement.
197
+ //
198
+ // Output parameters:
199
+ // CONV: Convergence flag.
200
+ // CONV = 0 => No convergence.
201
+ // CONV = 1 => SingleMostLikelihoodReplacement convergence.
202
+ //
203
+ // IER: Return error code.
204
+ // IER = 0 => No error.
205
+ // IER = 1 => logarithm argument became zero at sample number IER.
206
+
207
+ // Input initialization.
208
+ IER = 0;
209
+ CONV = 0;
210
+
211
+ // Local variable initialization.
212
+ double LNHOLD = log(D / (1.0-D));
213
+ int INDKNT = 0;
214
+ int INDSTR = 0;
215
+ double GLOBAL = 0;
216
+
217
+ // Calculate log-likelihood ratios.
218
+ for (int i = 0; i < NSAMPS; i++)
219
+ {
220
+ double DHOLD = 1.0 - 2.0 * Q[i];
221
+ double LOGARG = 1.0 + C * DHOLD * S[i];
222
+
223
+ if (LOGARG <= 0)
224
+ {
225
+ IER = i;
226
+ return;
227
+ }
228
+
229
+ double HOLD3 = -0.5 * log(LOGARG);
230
+ double HOLD1 = C * G[i] * G[i] * DHOLD / (2.0*LOGARG);
231
+ double STORE = HOLD1 + DHOLD * LNHOLD + HOLD3;
232
+ if (STORE > 0)
233
+ {
234
+ INDKNT++;
235
+ if (STORE > GLOBAL)
236
+ {
237
+ GLOBAL = STORE;
238
+ INDSTR = i;
239
+ }
240
+ }
241
+ }
242
+
243
+ if (INDKNT < 1)
244
+ {
245
+ // In case of convergence, return.
246
+ CONV = true;
247
+ }
248
+ else
249
+ {
250
+ // Reset event.
251
+ Q[INDSTR] = !Q[INDSTR];
252
+ }
253
+ }
254
+
255
+ // Original function name: THOLD
256
+ void Threshold(double JMPSEQ[], double C, double F, int NSAMPS, int Q[], double& D)
257
+ {
258
+ // Function:
259
+ // Threshold procedure to estimate an initial event sequence.
260
+ //
261
+ // Input parameters:
262
+ // JMPSEQ: Jump sequence estimate obtained with the event sequence Q set to unity for all values.
263
+ //
264
+ // C: Variance of the jump sequence.
265
+ //
266
+ // F: Segmentation threshold index.
267
+ //
268
+ // NSAMPS: Length of the array JMPSEQ.
269
+ //
270
+ // Output parameters:
271
+ // Q: Estimated binary event sequence.
272
+ //
273
+ // D: Estimated segment density.
274
+
275
+ D = 0.0;
276
+
277
+ for (int i = 0; i < NSAMPS; i++)
278
+ {
279
+ if (F*C <= JMPSEQ[i]*JMPSEQ[i])
280
+ {
281
+ Q[i] = 1;
282
+ D = D + 1.0;
283
+ }
284
+ else
285
+ {
286
+ Q[i] = 0;
287
+ }
288
+ }
289
+
290
+ D = D / (double)NSAMPS;
291
+ }
292
+
293
+ // Original function name: MOVAVG
294
+ void MovingAverage(double ARR1[], int NSAMPS, int ORDER, double ARR2[])
295
+ {
296
+ // Function:
297
+ // Centered moving average.
298
+ //
299
+ // Input parameters:
300
+ // ARR1: Input data array to be averaged.
301
+ //
302
+ // NSAMPS: Length of the input data array (ARR1).
303
+ //
304
+ // ORDER: One sided length of the moving average window.
305
+ //
306
+ // Output parameters:
307
+ // ARR2: Averaged data array.
308
+
309
+ if (ORDER >= NSAMPS)
310
+ {
311
+ // Auto correct.
312
+ ORDER = NSAMPS-2;
313
+ }
314
+
315
+ ARR2[0] = ARR1[0];
316
+ ARR2[NSAMPS-1] = ARR1[NSAMPS-1];
317
+
318
+ // Average build and drop (beginning and end of average array).
319
+ double SUM = ARR1[0];
320
+ double SUM1 = ARR1[NSAMPS-1];
321
+
322
+ int jfront = -1;
323
+ int jback = NSAMPS;
324
+
325
+ for (int i = 1; i < ORDER+1; i++)
326
+ {
327
+ // Building by 2 because this is a "central" moving average.
328
+ jfront = jfront + 2;
329
+ jback = jback - 2;
330
+ SUM = SUM + ARR1[jfront] + ARR1[jfront+1];
331
+ SUM1 = SUM1 + ARR1[jback] + ARR1[jback-1];
332
+ ARR2[i] = SUM / ((double)jfront + 2);
333
+ ARR2[NSAMPS-1-i] = SUM1 / ((double)jfront + 2);
334
+ }
335
+
336
+ // Average stable.
337
+ jfront = jfront + 2;
338
+ jback = 0;
339
+
340
+ for (int i = ORDER+1; i < NSAMPS-ORDER; i++)
341
+ {
342
+ SUM = SUM + ARR1[jfront] - ARR1[jback];
343
+ ARR2[i] = SUM / ((double)ORDER * 2 + 1);
344
+ jfront++;
345
+ jback++;
346
+ }
347
+ }
348
+
349
+ // Original function name: KALMAN
350
+ void KalmanFilter(double LOG[], int Q[], double C, double R[], int NSAMPS, double GAIN[], double ZTLT[], double ETA[], double STATE[])
351
+ {
352
+ // Function:
353
+ // One dimensional KalmanFilter filter.
354
+ //
355
+ // Input parameters:
356
+ // LOG: Input discretized well log.
357
+ //
358
+ // Q: Binary event sequence.
359
+ //
360
+ // C: Variance of the jump sequence.
361
+ //
362
+ // NSAMPS: Length of the input well log.
363
+ //
364
+ // Output parameters:
365
+ // GAIN: KalmanFilter gain array.
366
+ //
367
+ // ZTLT: Innovation sequence.
368
+ //
369
+ // ETA: Variance of the innovation sequence.
370
+ //
371
+ // STATE: Estimated state values (filtered log).
372
+
373
+ // Init state and its variance.
374
+ double VAR = 0.0;
375
+
376
+ if (Q[0])
377
+ {
378
+ VAR = C;
379
+ }
380
+
381
+ ZTLT[0] = 0.0;
382
+ ETA[0] = VAR + R[0];
383
+ GAIN[0] = VAR / ETA[0];
384
+ STATE[0] = LOG[0] + GAIN[0] * ZTLT[0];
385
+ VAR = (1.0 - GAIN[0]) * VAR;
386
+
387
+ // Estimate state and its variance (one dim KalmanFilter filter).
388
+ for (int i = 1; i < NSAMPS; i++)
389
+ {
390
+ if (Q[i])
391
+ {
392
+ VAR = VAR + C;
393
+ }
394
+
395
+ ZTLT[i] = LOG[i] - STATE[i-1];
396
+ ETA[i] = VAR + R[i];
397
+ GAIN[i] = VAR / ETA[i];
398
+ STATE[i] = STATE[i-1] + GAIN[i] * ZTLT[i];
399
+ VAR = (1.0 - GAIN[i]) * VAR;
400
+ }
401
+ }
402
+
403
+ // Original function name: FIOS
404
+ void FixedIntervalOptimalSmoother(int Q[], int NSAMPS, double C, double ARR1[], double ARR2[], double ARR3[])
405
+ {
406
+ // Function:
407
+ // Fixed interval optimal smoother to estimate the jump sequence, residual state and its variance.
408
+ //
409
+ // Input parameters:
410
+ // Q: Binary event sequence.
411
+ //
412
+ // NSAMPS: Length of the binary event sequence Q.
413
+ //
414
+ // C: Variance of the jump sequence.
415
+ //
416
+ // Input/output parameters:
417
+ // ARR1: Variance of the innovation sequence. On return it contains the product Q*R.
418
+ //
419
+ // ARR2: Innovation sequence. On return it contains S (variance of residual state).
420
+ //
421
+ // ARR3: KalmanFilter gain array. On return it contains G (residual state).
422
+
423
+ int lastindex = NSAMPS - 1;
424
+
425
+ ARR3[lastindex] = ARR2[lastindex] / ARR1[lastindex];
426
+ ARR2[lastindex] = 1.0 / ARR1[lastindex];
427
+ ARR1[lastindex] = C * Q[lastindex] * ARR3[lastindex];
428
+
429
+ for (int i = lastindex-1; i > -1; i--)
430
+ {
431
+ double TEMP = 1.0 - ARR3[i];
432
+ ARR3[i] = TEMP * ARR3[i+1] + ARR2[i] / ARR1[i];
433
+ ARR2[i] = TEMP * TEMP * ARR2[i+1] + 1.0 / ARR1[i];
434
+ ARR1[i] = C * Q[i] * ARR3[i];
435
+ }
436
+ }
437
+
438
+ // Original function name: DATAVG
439
+ void AverageArraySegments(double ARR[], int Q[], int NSAMPS, double AVGOUT[])
440
+ {
441
+ // Function:
442
+ // Data array to be averaged within segments implied by an event sequence Q.
443
+ //
444
+ // Input parameters:
445
+ // ARR: Input data array to be averaged.
446
+ //
447
+ // Q: Binary event sequence.
448
+ //
449
+ // NSAMPS: Length of the input data array (ARR).
450
+ //
451
+ // Output parameters:
452
+ // AVGOUT: Output data averaged within each segment implied by the event sequence Q.
453
+
454
+ bool endofarray = false;
455
+ int SEGSTR = 0;
456
+
457
+ while (!endofarray)
458
+ {
459
+ int SEGEND;
460
+ int SEGLEN;
461
+ double SEGAVG;
462
+
463
+ GetSegment(ARR, Q, NSAMPS, SEGSTR, SEGEND, SEGLEN, SEGAVG, endofarray);
464
+
465
+ for (int i = SEGSTR; i <= SEGEND; i++)
466
+ {
467
+ AVGOUT[i] = SEGAVG;
468
+ }
469
+
470
+ SEGSTR = SEGEND + 1;
471
+ }
472
+ }
473
+
474
+ // Original function name: UPDNSE
475
+ void DeglitchAndEstimateNoiseVariance(double LOG[], int Q[], int NSAMPS, int RMODE, double WORK1[], double R[])
476
+ {
477
+ // Function:
478
+ // Deglitch and re-estimate noise variance.
479
+ //
480
+ // Input parameters:
481
+ // LOG: Input discretized well log to be used for updating noise variance R.
482
+ //
483
+ // Q: Binary event sequence.
484
+ //
485
+ // NSAMPS: Length of the input well log.
486
+ //
487
+ // RMODE: Noise variance estimate option.
488
+ // RMODE = 0 ==> Point estimate of noise variance.
489
+ // RMODE = 1 ==> Noise estimates smoothed within segments.
490
+ //
491
+ // Output parameters:
492
+ // R: Estimated noise variance.
493
+
494
+ // Average the log within each segment implied by Q.
495
+ AverageArraySegments(LOG, Q, NSAMPS, WORK1);
496
+
497
+ // Calculate the noise variance R.
498
+ for (int i = 0; i < NSAMPS; i++)
499
+ {
500
+ WORK1[i] = (LOG[i] - WORK1[i]) * (LOG[i] - WORK1[i]);
501
+
502
+ if (WORK1[i] <= 0.0)
503
+ {
504
+ WORK1[i] = 1.0;
505
+ }
506
+ }
507
+
508
+ // Point estimate.
509
+ if (RMODE == 0)
510
+ {
511
+ for (int i = 0; i < NSAMPS; i++)
512
+ {
513
+ R[i] = WORK1[i];
514
+ }
515
+ }
516
+ else
517
+ {
518
+ // Smooth the noise variance R within each segment.
519
+ int SEGSTR = 0;
520
+ bool endofarray = false;
521
+
522
+ while (!endofarray)
523
+ {
524
+ // Outputs from call to "GetSegment".
525
+ int SEGEND;
526
+ int SEGLEN;
527
+ double SEGAVG;
528
+
529
+ GetSegment(LOG, Q, NSAMPS, SEGSTR, SEGEND, SEGLEN, SEGAVG, endofarray);
530
+
531
+ int IOR = SEGLEN/3;
532
+ if (IOR > 0)
533
+ {
534
+ MovingAverage(&(WORK1[SEGSTR]), SEGLEN, IOR, &(R[SEGSTR]));
535
+ }
536
+ else
537
+ {
538
+ for (int i = SEGSTR; i <= SEGEND; i++)
539
+ {
540
+ R[i] = WORK1[i];
541
+ }
542
+ }
543
+
544
+ SEGSTR = SEGEND + 1;
545
+ }
546
+ }
547
+ }
548
+
549
+ // Original function name: GETSEG
550
+ void GetSegment(double LOG[], int Q[], int NSAMPS, int SEGSTR, int& SEGEND, int& SEGLEN, double& SEGAVG, bool& endofarray)
551
+ {
552
+ // Function:
553
+ // Identifies a segment within a given event sequence.
554
+ // A segment is defined by the sequence 1,0,0,...,0,1.
555
+ //
556
+ // Input parameters:
557
+ // LOG: Data array for which the averages are to be computed.
558
+ //
559
+ // Q: Binary event sequence which identifies the segments in the input array log.
560
+ //
561
+ // NSAMPS: Length of the input array log.
562
+ //
563
+ // SEGSTR: Sample number where the segment boundary starts.
564
+ //
565
+ // Output parameters:
566
+ // SEGEND: Sample number where the segment boundary ends.
567
+ //
568
+ // SEGLEN: Length of the segment.
569
+ //
570
+ // SEGAVG: Average value of the input data array log over the segment.
571
+ //
572
+ // endofarray: End of data indicator.
573
+ // true: End of array reached.
574
+ // false: Not at end of the array.
575
+
576
+ endofarray = false;
577
+ SEGEND = SEGSTR;
578
+ SEGAVG = 0;
579
+
580
+ do
581
+ {
582
+ SEGAVG = SEGAVG + LOG[SEGEND];
583
+ SEGEND = SEGEND + 1;
584
+ }
585
+ while (!Q[SEGEND] && SEGEND < NSAMPS);
586
+
587
+ if (SEGEND == NSAMPS)
588
+ {
589
+ // We hit the end of the array without finding an event indicator (a "1" in the "Q" array).
590
+ endofarray = true;
591
+ }
592
+
593
+ // In the case were we found a "1" in the "Q" array the end of the segment is the previous
594
+ // index before the event ("1"). If we hit the end of the array first, SEGEND == NSAMPS which
595
+ // is past the end of the array so it needs to be de-incremented.
596
+ SEGEND--;
597
+
598
+ SEGLEN = SEGEND - SEGSTR + 1;
599
+ SEGAVG = SEGAVG / SEGLEN;
600
+ }
601
+
602
+ // Original function name: DEGLCH
603
+ void Deglitch(int NSAMPS, int Q[])
604
+ {
605
+ // Function:
606
+ // Deglitches all the spiky zones in the event sequence Q.
607
+ //
608
+ // Input parameters:
609
+ // NSAMPS: Length of the array Q.
610
+ //
611
+ // Input/output parameters:
612
+ // Q: Binary event sequence to be deglitched. On return this contains the updated event
613
+ // sequence. It is of length "NSAMPS."
614
+
615
+ int SEGSTR = 0;
616
+ bool endofarray = false;
617
+
618
+ do
619
+ {
620
+ int SEGEND;
621
+ GetSpikeyZone(Q, NSAMPS, SEGSTR, SEGEND, endofarray);
622
+
623
+ if (SEGSTR == SEGEND)
624
+ {
625
+ SEGSTR++;
626
+ }
627
+ else
628
+ {
629
+ if (SEGEND == SEGSTR+1)
630
+ {
631
+ Q[SEGSTR] = 0;
632
+ }
633
+ else
634
+ {
635
+ for (int i = SEGSTR+1; i < SEGEND; i++)
636
+ {
637
+ Q[i] = 0;
638
+ }
639
+ }
640
+ SEGSTR = SEGEND + 1;
641
+ }
642
+ }
643
+ while (!endofarray);
644
+ }
645
+
646
+ // Original function name: GETSPK
647
+ void GetSpikeyZone(int Q[], int NSAMPS, int SEGSTR, int& SEGEND, bool& endofarray)
648
+ {
649
+ // Function:
650
+ // Identifies a zone of spikes. A spiky zone is defined by 0,1,1,...,1,0.
651
+ //
652
+ // Input parameters:
653
+ // Q: Binary event sequence in which the zone is to be identified.
654
+ //
655
+ // NSAMPS: Length of the array Q.
656
+ //
657
+ // SEGSTR: Sample number where the spiky zone starts.
658
+ //
659
+ // Output parameters:
660
+ // SEGEND: Sample number where the zone ends.
661
+ //
662
+ // endofarray: End of data indicator.
663
+ // true: End of array reached.
664
+ // false: Not at end of the array.
665
+
666
+ SEGEND = SEGSTR;
667
+ if (!Q[SEGEND])
668
+ {
669
+ // Modified from original paper. The "if" statement below was not part of the original algorithm.
670
+ // It seems there can be a case where Q[i] < 0.5 for SEGEND = NSAMPS that causes us to miss flagging the end
671
+ // of the array. Do a check here to ensure we don't overrun the end of the array and over write memory we should
672
+ // not over write.
673
+ if (SEGEND >= NSAMPS)
674
+ {
675
+ endofarray = true;
676
+ SEGEND = NSAMPS - 1;
677
+ }
678
+
679
+ return;
680
+ }
681
+
682
+ do
683
+ {
684
+ SEGEND++;
685
+ }
686
+ while (Q[SEGEND] && (SEGEND < NSAMPS));
687
+
688
+ if (SEGEND >= NSAMPS)
689
+ {
690
+ endofarray = true;
691
+ }
692
+
693
+ SEGEND--;
694
+ }
695
+
696
+ // Original function name: UPDDEN
697
+ void EstimateEventDensity(int Q[], int NSAMPS, double& D, int& NQ)
698
+ {
699
+ // Function:
700
+ // Estimates the event density for a given event sequence.
701
+ //
702
+ // Input parameters:
703
+ // Q: Binary event sequence for which the event density is to be estimated.
704
+ //
705
+ // NSAMPS: Length of the array Q.
706
+ //
707
+ // Output parameters:
708
+ // D: Estimated segment density.
709
+ //
710
+ // NQ: Number of binary events found (number of "1"s in Q).
711
+
712
+ D = 0;
713
+ for (int i = 0; i < NSAMPS; i++)
714
+ {
715
+ D = D + Q[i];
716
+ }
717
+
718
+ // Store the number of events found, the calculate the event density.
719
+ NQ = (int)D;
720
+ D = D / (double)NSAMPS;
721
+ }
722
+
723
+ // Original function name: ESTSIG
724
+ void EstimateVarianceOfJumpSequence(double LOG[], int NSAMPS, double WORK1[], double& C)
725
+ {
726
+ // Function:
727
+ // Estimates initially C, the variance of the jump sequence as the variance of unit-step
728
+ // finite difference of input smoothed log.
729
+ //
730
+ // Input parameters:
731
+ // LOG: Smoothed well log.
732
+ //
733
+ // NSAMPS: Length of the array log.
734
+ //
735
+ // Output parameters:
736
+ // C: Estimated variance of the jump sequence.
737
+
738
+ // Estimate jump sequence as the unit-step finite difference of input log.
739
+ WORK1[0] = 0;
740
+ for (int i = 1; i < NSAMPS; i++)
741
+ {
742
+ WORK1[i] = LOG[i] - LOG[i-1];
743
+ }
744
+
745
+ // Calculate the variance of the differ log (consider non zero values).
746
+ double MEAN;
747
+ CalculateMeanAndVariance(WORK1, NSAMPS, 1, MEAN, C);
748
+ }
749
+
750
+ // Original function name: VARNCE
751
+ void CalculateMeanAndVariance(double ARRAY[], int NSAMPS, int MODE, double& MEAN, double& VAR)
752
+ {
753
+ // Function:
754
+ // Calculates mean and variance.
755
+ //
756
+ // Input parameters:
757
+ // ARRAY: Input data array for which the mean and variance is to be calculated.
758
+ //
759
+ // NSAMPS: Length of the input array.
760
+ //
761
+ // MODE: Option to include zero values for calculating mean and variance.
762
+ // MODE == 0 = Consider all values.
763
+ // MODE == 1 = Consider only non zero values.
764
+ //
765
+ // Output parameters:
766
+ // MEAN: Calculated mean of the given data.
767
+ //
768
+ // VAR: Calculated variance of the given data.
769
+
770
+ int NZEKNT = 0;
771
+ MEAN = 0;
772
+ VAR = 0;
773
+
774
+ // Calculate sum and sum of squares.
775
+ for (int i = 0; i < NSAMPS; i++)
776
+ {
777
+
778
+ if (ARRAY[i] != 0)
779
+ {
780
+ NZEKNT++;
781
+ MEAN = MEAN + ARRAY[i];
782
+ VAR = VAR + ARRAY[i]*ARRAY[i];
783
+ }
784
+ }
785
+
786
+ // Calculate mean and variance.
787
+ if (MODE == 0)
788
+ {
789
+ MEAN = MEAN / (double)NSAMPS;
790
+ VAR = VAR / (double)NSAMPS - MEAN*MEAN;
791
+ }
792
+ else
793
+ {
794
+ MEAN = MEAN / (double)NZEKNT;
795
+ VAR = VAR / (double)NZEKNT - MEAN*MEAN;
796
+ }
797
+ }
@@ -0,0 +1,82 @@
1
+ #include "SegmentationResults.h"
2
+
3
+ namespace Algorithms
4
+ {
5
+ SegmentationResults::SegmentationResults(int signalLength, int binaryEventSequence[], int numberOfBinaryEvents, double filteredSignal[], double segmentedLog[], double noiseVariance[], double jumpSequenceVariance, double segmentDensity, int iterations, int error)
6
+ {
7
+ _signalLength = signalLength;
8
+
9
+ _binaryEventSequence = binaryEventSequence;
10
+ _numberOfBinaryEvents = numberOfBinaryEvents;
11
+ _filteredSignal = filteredSignal;
12
+ _segmentedLog = segmentedLog;
13
+ _noiseVariance = noiseVariance;
14
+
15
+ _jumpSequenceVariance = jumpSequenceVariance;
16
+ _segmentDensity = segmentDensity;
17
+ _iterations = iterations;
18
+ _error = error;
19
+ }
20
+
21
+ SegmentationResults::~SegmentationResults()
22
+ {
23
+ if (_binaryEventSequence)
24
+ {
25
+ delete _binaryEventSequence;
26
+ delete _filteredSignal;
27
+ delete _segmentedLog;
28
+ delete _noiseVariance;
29
+ }
30
+ }
31
+
32
+ int SegmentationResults::GetSignalLength()
33
+ {
34
+ return _signalLength;
35
+ }
36
+
37
+ int* SegmentationResults::GetBinaryEventSequence()
38
+ {
39
+ return _binaryEventSequence;
40
+ }
41
+
42
+ int SegmentationResults::GetNumberOfBinaryEvents()
43
+ {
44
+ return _numberOfBinaryEvents;
45
+ }
46
+
47
+ double* SegmentationResults::GetFilteredSignal()
48
+ {
49
+ return _filteredSignal;
50
+ }
51
+
52
+ double* SegmentationResults::GetSegmentedLog()
53
+ {
54
+ return _segmentedLog;
55
+ }
56
+
57
+ double* SegmentationResults::GetNoiseVariance()
58
+ {
59
+ return _noiseVariance;
60
+ }
61
+
62
+ double SegmentationResults::GetJumpSequenceVariance()
63
+ {
64
+ return _jumpSequenceVariance;
65
+ }
66
+
67
+ double SegmentationResults::GetSegmentDensity()
68
+ {
69
+ return _segmentDensity;
70
+ }
71
+
72
+ int SegmentationResults::GetIterations()
73
+ {
74
+ return _iterations;
75
+ }
76
+
77
+ int SegmentationResults::GetError()
78
+ {
79
+ return _error;
80
+ }
81
+
82
+ } // End namespace.
@@ -0,0 +1,126 @@
1
+ #include "SegmentationResultsPy.h"
2
+
3
+ namespace PythonAlgorithms
4
+ {
5
+ SegmentationResults::SegmentationResults()
6
+ {
7
+ _numberOfBinaryEvents = 0;
8
+ _jumpSequenceVariance = 0;
9
+ _segmentDensity = 0;
10
+ _iterations = 0;
11
+ _error = 0;
12
+
13
+ _binaryEventSequence = py::array_t<int>();
14
+ _filteredSignal = py::array_t<double>();
15
+ _segmentedLog = py::array_t<double>();
16
+ _noiseVariance = py::array_t<double>();
17
+ }
18
+
19
+ SegmentationResults::SegmentationResults(Algorithms::SegmentationResults* segmentationResults)
20
+ {
21
+ // Initial scalar values from the input.
22
+ _signalLength = segmentationResults->GetSignalLength();
23
+ _numberOfBinaryEvents = segmentationResults->GetNumberOfBinaryEvents();
24
+ _jumpSequenceVariance = segmentationResults->GetJumpSequenceVariance();
25
+ _segmentDensity = segmentationResults->GetSegmentDensity();
26
+ _iterations = segmentationResults->GetIterations();
27
+ _error = segmentationResults->GetError();
28
+
29
+ // Create the arrays.
30
+ _binaryEventSequence = py::array_t<int>(_signalLength);
31
+ _filteredSignal = py::array_t<double>(_signalLength);
32
+ _segmentedLog = py::array_t<double>(_signalLength);
33
+ _noiseVariance = py::array_t<double>(_signalLength);
34
+
35
+ // Get pointers to the results. The data is private, we use the access functions.
36
+ int* binaryEventSequence = segmentationResults->GetBinaryEventSequence();
37
+ double* filteredSignal = segmentationResults->GetFilteredSignal();
38
+ double* segmentedLog = segmentationResults->GetSegmentedLog();
39
+ double* noiseVariance = segmentationResults->GetNoiseVariance();
40
+
41
+ // Get pointers to the actual data inside of the Python arrays.
42
+ int* binaryEventSequenceBuffer = static_cast<int*>(_binaryEventSequence.request().ptr);
43
+ double* filteredSignalBuffer = static_cast<double*>(_filteredSignal.request().ptr);
44
+ double* segmentedLogBuffer = static_cast<double*>(_segmentedLog.request().ptr);
45
+ double* noiseVarianceBuffer = static_cast<double*>(_noiseVariance.request().ptr);
46
+
47
+ // Copy the data to the Python data structures.
48
+ for (int i = 0; i < _signalLength; i++)
49
+ {
50
+ binaryEventSequenceBuffer[i] = binaryEventSequence[i];
51
+ filteredSignalBuffer[i] = filteredSignal[i];
52
+ segmentedLogBuffer[i] = segmentedLog[i];
53
+ noiseVarianceBuffer[i] = noiseVariance[i];
54
+ }
55
+ }
56
+
57
+ SegmentationResults::SegmentationResults(int signalLength, py::array_t<int> binaryEventSequence, int numberOfBinaryEvents, py::array_t<double> filteredSignal,
58
+ py::array_t<double> segmentedLog, py::array_t<double> noiseVariance, double jumpSequenceVariance, double segmentDensity, int iterations, int error)
59
+ {
60
+ _signalLength = signalLength;
61
+ _binaryEventSequence = binaryEventSequence;
62
+ _numberOfBinaryEvents = numberOfBinaryEvents;
63
+ _filteredSignal = filteredSignal;
64
+ _segmentedLog = segmentedLog;
65
+ _noiseVariance = noiseVariance;
66
+ _jumpSequenceVariance = jumpSequenceVariance;
67
+ _segmentDensity = segmentDensity;
68
+ _iterations = iterations;
69
+ _error = error;
70
+ }
71
+
72
+ SegmentationResults::~SegmentationResults()
73
+ {
74
+ }
75
+
76
+ int SegmentationResults::GetSignalLength() const
77
+ {
78
+ return _signalLength;
79
+ }
80
+
81
+ py::array_t<int> SegmentationResults::GetBinaryEventSequence() const
82
+ {
83
+ return _binaryEventSequence;
84
+ }
85
+
86
+ int SegmentationResults::GetNumberOfBinaryEvents() const
87
+ {
88
+ return _numberOfBinaryEvents;
89
+ }
90
+
91
+ py::array_t<double> SegmentationResults::GetFilteredSignal() const
92
+ {
93
+ return _filteredSignal;
94
+ }
95
+
96
+ py::array_t<double> SegmentationResults::GetSegmentedLog() const
97
+ {
98
+ return _segmentedLog;
99
+ }
100
+
101
+ py::array_t<double> SegmentationResults::GetNoiseVariance() const
102
+ {
103
+ return _noiseVariance;
104
+ }
105
+
106
+ double SegmentationResults::GetJumpSequenceVariance() const
107
+ {
108
+ return _jumpSequenceVariance;
109
+ }
110
+
111
+ double SegmentationResults::GetSegmentDensity() const
112
+ {
113
+ return _segmentDensity;
114
+ }
115
+
116
+ int SegmentationResults::GetIterations() const
117
+ {
118
+ return _iterations;
119
+ }
120
+
121
+ int SegmentationResults::GetError() const
122
+ {
123
+ return _error;
124
+ }
125
+
126
+ } // End namespace.
@@ -0,0 +1,140 @@
1
+ #include <stdexcept>
2
+ #include <pybind11/pybind11.h>
3
+ #include <pybind11/numpy.h>
4
+ //#include <pybind11/stl.h>
5
+
6
+ #include "SegmentSignalFunctions.h"
7
+ #include "SegmentSignal.h"
8
+ #include "SegmentationResults.h"
9
+ #include "SegmentationResultsPy.h"
10
+
11
+ #include <iostream>
12
+ #include <fstream>
13
+ #include <iomanip> // std::setprecision
14
+
15
+ namespace py = pybind11;
16
+
17
+ PythonAlgorithms::SegmentationResults* Segment(py::array_t<double> signalAsPyList, double threshold, int jumpSequenceWindowSize, int noiseVarianceWindowSize, int noiseVarianceEstimateMethod, int maxSMLRIterations)
18
+ {
19
+ // Gets the information about the object and a pointer to the actual data (buffer).
20
+ py::buffer_info info = signalAsPyList.request();
21
+ double* signalDataPointer = static_cast<double*>(info.ptr);
22
+
23
+ // Make sure a 1-dimensional array/list was passed and not a scalar, two-dimensional, or other.
24
+ if (info.ndim != 1)
25
+ {
26
+ throw std::runtime_error("Error: The array passed to \"Segment\" function is not 1 dimensional.");
27
+ }
28
+
29
+ // Get the length of the array/list. It is required for the lower level functions operation on C arrays.
30
+ int signalLength = static_cast<int>(info.shape[0]);
31
+
32
+ // Call the algorithm, then convert the results for returning to Python.
33
+ Algorithms::SegmentationResults* cppResults = Algorithms::SegmentSignal::Segment(signalDataPointer, signalLength, threshold, jumpSequenceWindowSize, noiseVarianceWindowSize, (NoiseVarianceEstimateMethod)noiseVarianceEstimateMethod, maxSMLRIterations);
34
+ PythonAlgorithms::SegmentationResults* pythonResults = new PythonAlgorithms::SegmentationResults(cppResults);
35
+
36
+ // The C results are not longer needed. Everything has been copied to the Python results.
37
+ delete cppResults;
38
+
39
+ return pythonResults;
40
+ }
41
+
42
+
43
+ py::array_t<int> FindSignificantZones(py::array_t<int> binaryEvents, py::array_t<double> xData, double threshold, bool includeBoundaries)
44
+ {
45
+ // Gets the information about the object and a pointer to the actual data (buffer).
46
+ py::buffer_info eventsInfo = binaryEvents.request();
47
+ int* binaryEventsPointer = static_cast<int*>(eventsInfo.ptr);
48
+ py::buffer_info xDataInfo = xData.request();
49
+ double* xDataPointer = static_cast<double*>(xDataInfo.ptr);
50
+
51
+ // Make sure a 1-dimensional array/list was passed and not a scalar, two-dimensional, or other.
52
+ if (eventsInfo.ndim != 1 || xDataInfo.ndim != 1)
53
+ {
54
+ throw std::runtime_error("Error: An array passed to \"FindSignificantZones\" function is not 1 dimensional.");
55
+ }
56
+
57
+ // Make sure a data is the same length.
58
+ if (eventsInfo.shape[0] != xDataInfo.shape[0])
59
+ {
60
+ throw std::runtime_error("Error: Arrays passed to \"FindSignificantZones\" function are not the same length.");
61
+ }
62
+
63
+ // Get the length of the array/list. It is required for the lower level functions operation on C arrays.
64
+ int signalLength = static_cast<int>(eventsInfo.shape[0]);
65
+ std::vector<std::array<int, 2>>* cppResults = Algorithms::SegmentSignal::FindSignificantZones(binaryEventsPointer, xDataPointer, signalLength, threshold, includeBoundaries);
66
+
67
+ size_t size = cppResults->size();
68
+ py::array_t<int> pyResults = py::array_t<int>(2*size);
69
+ int* pyResultsBuffer = static_cast<int*>(pyResults.request().ptr);
70
+
71
+ for (int i = 0; i < size; i++)
72
+ {
73
+ std::array<int, 2> indexSet = (*cppResults)[i];
74
+ pyResultsBuffer[2*i] = indexSet[0];
75
+ pyResultsBuffer[2*i+1] = indexSet[1];
76
+ }
77
+
78
+ pyResults.resize({(int)size, 2});
79
+
80
+ delete cppResults;
81
+
82
+ return pyResults;
83
+ }
84
+
85
+
86
+ PYBIND11_MODULE(SegmentSignalPy, m)
87
+ {
88
+ m.def("Segment", &Segment, "Segments a signal based on maximum likelihood estimation");
89
+
90
+ m.def("FindSignificantZones", &FindSignificantZones, "Post processes a binary event sequence to find regions that are greater than the specified threashold.");
91
+
92
+ //py::class_<Algorithms::SegmentSignal>(m, "SegmentSignal")
93
+ // .def_static("Segment", static_cast<Algorithms::SegmentationResults* (*)(double[], int, double, int, int)>(&Algorithms::SegmentSignal::Segment));
94
+
95
+ py::class_<PythonAlgorithms::SegmentationResults>(m, "SegmentationResults")
96
+ .def(py::init<>())
97
+ .def(py::init<int, py::array_t<int>, int, py::array_t<double>, py::array_t<double>, py::array_t<double>, double, double, int, int>())
98
+ .def(py::pickle(
99
+ [](const PythonAlgorithms::SegmentationResults& p) { // __getstate__
100
+ // Return a tuple that fully encodes the state of the object.
101
+ return py::make_tuple(p.GetSignalLength(), p.GetBinaryEventSequence(), p.GetNumberOfBinaryEvents(), p.GetFilteredSignal(), p.GetSegmentedLog(), p.GetNoiseVariance(), p.GetJumpSequenceVariance(), p.GetSegmentDensity(), p.GetIterations(), p.GetError());
102
+ },
103
+ [](py::tuple t) { // __setstate__
104
+ if (t.size() != 10)
105
+ throw std::runtime_error("Invalid state!");
106
+
107
+ // Create a new C++ instance.
108
+ PythonAlgorithms::SegmentationResults p(
109
+ t[0].cast<int>(), // Signal length.
110
+ t[1].cast<py::array_t<int>>(), // Binary event sequence.
111
+ t[2].cast<int>(), // Number of binary events.
112
+ t[3].cast<py::array_t<double>>(), // Filtered signal.
113
+ t[4].cast<py::array_t<double>>(), // Segmented log.
114
+ t[5].cast<py::array_t<double>>(), // Noise variance.
115
+ t[6].cast<double>(), // Noise variance jump sequence.
116
+ t[7].cast<double>(), // Segment density.
117
+ t[8].cast<int>(), // Iterations.
118
+ t[9].cast<int>() // Error.
119
+ );
120
+
121
+ return p;
122
+ }
123
+ ))
124
+ .def_property_readonly("SignalLength", &PythonAlgorithms::SegmentationResults::GetSignalLength)
125
+ .def_property_readonly("BinaryEventSequence", &PythonAlgorithms::SegmentationResults::GetBinaryEventSequence)
126
+ .def_property_readonly("NumberOfBinaryEvents", &PythonAlgorithms::SegmentationResults::GetNumberOfBinaryEvents)
127
+ .def_property_readonly("FilteredSignal", &PythonAlgorithms::SegmentationResults::GetFilteredSignal)
128
+ .def_property_readonly("SegmentedLog", &PythonAlgorithms::SegmentationResults::GetSegmentedLog)
129
+ .def_property_readonly("NoiseVariance", &PythonAlgorithms::SegmentationResults::GetNoiseVariance)
130
+ .def_property_readonly("JumpSequenceVariance", &PythonAlgorithms::SegmentationResults::GetJumpSequenceVariance)
131
+ .def_property_readonly("SegmentDensity", &PythonAlgorithms::SegmentationResults::GetSegmentDensity)
132
+ .def_property_readonly("Iterations", &PythonAlgorithms::SegmentationResults::GetIterations)
133
+ .def_property_readonly("Error", &PythonAlgorithms::SegmentationResults::GetError);
134
+
135
+ #ifdef VERSION_INFO
136
+ m.attr("__version__") = VERSION_INFO;
137
+ #else
138
+ m.attr("__version__") = "dev";
139
+ #endif
140
+ }
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2021-2024 Lance A. Endres
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,35 @@
1
+ Metadata-Version: 2.1
2
+ Name: SegmentSignalPy
3
+ Version: 0.1.2
4
+ Summary: Signal segmentation algorithm by S. Radhakrishnan, et al. This is a Python interface for the C++ algorithm.
5
+ License: Copyright (c) 2021-2024 Lance A. Endres
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining
8
+ a copy of this software and associated documentation files (the
9
+ "Software"), to deal in the Software without restriction, including
10
+ without limitation the rights to use, copy, modify, merge, publish,
11
+ distribute, sublicense, and/or sell copies of the Software, and to
12
+ permit persons to whom the Software is furnished to do so, subject to
13
+ the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be
16
+ included in all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ Project-URL: homepage, https://github.com/lendres/Segment-Signals
27
+ Requires-Python: >=3.11.0
28
+ Description-Content-Type: text/markdown
29
+ License-File: License.txt
30
+
31
+ # Segment Signals
32
+ A signal segmentation algorithm.
33
+
34
+ ## Compiling
35
+ The Python Extension library requires the knowledge of your local Python. See the *Read Me.txt* file in that directory for more information.
@@ -0,0 +1,11 @@
1
+ SegmentSignalPy.cp312-win_amd64.pyd,sha256=D5rwZKT53ySZoyyQWZYK8-Dm78ow_SsY-2yOLgsUndg,174592
2
+ CPP Static Library/SegmentSignal.cpp,sha256=XGf7SdVFowKUA1XTUV3w3vPlVMmObtCqfpLlgtpqhRY,7486
3
+ CPP Static Library/SegmentSignalFunctions.cpp,sha256=nvjUUJrsMl8Bm3EfHlmtepXPw8xHL_4gen54zmbndXE,20026
4
+ CPP Static Library/SegmentationResults.cpp,sha256=TfETLOiGQgIQhEcCUqBjSvT4gejc0ls24hrX8OL8k1s,1812
5
+ Python Extension/SegmentationResultsPy.cpp,sha256=KZXoTBjRYUfwmM_ObRcycDKB4hciLWxElIIJ5WJze4k,4112
6
+ Python Extension/module.cpp,sha256=7vzVS5YOBfL2S21BOwMKiR6z8GDM1hT9wYWvCTJjPv0,6726
7
+ SegmentSignalPy-0.1.2.dist-info/License.txt,sha256=P9Td1RUysGlkcCTbn7PzBHFee-iPtG0zuLzEuVOB_j8,1084
8
+ SegmentSignalPy-0.1.2.dist-info/METADATA,sha256=jAHSBw0IVHV1mnq29CmYR3TkNyy9wA-4ysRn_hb7mgI,1810
9
+ SegmentSignalPy-0.1.2.dist-info/WHEEL,sha256=a7uKbwsC-jaWILXrHBfbCoELaoc3NJo_uE06BJFfWa4,101
10
+ SegmentSignalPy-0.1.2.dist-info/top_level.txt,sha256=Gg1JGAQCkw2ZivMSVOurzJ3yu03GWXQVKWOrCRc_oA0,135
11
+ SegmentSignalPy-0.1.2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (71.1.0)
3
+ Root-Is-Purelib: false
4
+ Tag: cp312-cp312-win_amd64
5
+
@@ -0,0 +1,9 @@
1
+ C DLL
2
+ C Sharp Unit Tests
3
+ C Sharp Wrapper
4
+ CPP Static Library
5
+ CPP Unit Tests
6
+ Matlab Extension
7
+ Python Extension
8
+ SegmentSignalPy
9
+ Test Data
Binary file