Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GaussianProcessTuning/ILNumerics.2.14.4735.573/Functions/statistics/median.cs @ 9102

Last change on this file since 9102 was 9102, checked in by gkronber, 12 years ago

#1967: ILNumerics source for experimentation

File size: 46.3 KB
Line 
1///
2///    This file is part of ILNumerics Community Edition.
3///
4///    ILNumerics Community Edition - high performance computing for applications.
5///    Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net
6///
7///    ILNumerics Community Edition is free software: you can redistribute it and/or modify
8///    it under the terms of the GNU General Public License version 3 as published by
9///    the Free Software Foundation.
10///
11///    ILNumerics Community Edition is distributed in the hope that it will be useful,
12///    but WITHOUT ANY WARRANTY; without even the implied warranty of
13///    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14///    GNU General Public License for more details.
15///
16///    You should have received a copy of the GNU General Public License
17///    along with ILNumerics Community Edition. See the file License.txt in the root
18///    of your distribution package. If not, see <http://www.gnu.org/licenses/>.
19///
20///    In addition this software uses the following components and/or licenses:
21///
22///    =================================================================================
23///    The Open Toolkit Library License
24///   
25///    Copyright (c) 2006 - 2009 the Open Toolkit library.
26///   
27///    Permission is hereby granted, free of charge, to any person obtaining a copy
28///    of this software and associated documentation files (the "Software"), to deal
29///    in the Software without restriction, including without limitation the rights to
30///    use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
31///    the Software, and to permit persons to whom the Software is furnished to do
32///    so, subject to the following conditions:
33///
34///    The above copyright notice and this permission notice shall be included in all
35///    copies or substantial portions of the Software.
36///
37///    =================================================================================
38///   
39
40using System;
41using System.Collections.Generic;
42using System.Text;
43using System.Threading;
44using ILNumerics.Storage;
45using ILNumerics.Misc;
46using ILNumerics.Exceptions;
47using System.Linq;
48
49
50namespace ILNumerics  {
51    public partial class ILMath {
52
53        /// <summary>
54        /// Calculate median along the specified dimension
55        /// </summary>
56        /// <param name="A">Input Array</param>
57        /// <returns><para>Array having the specified dimension reduced to the length 1 with the median of
58        /// all elements along that dimension.</para>
59        /// <param name="dim">[Optional] Index of dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1).</param>
60        /// <para>The result will have the same number of dimensions as A, but the specified dimension will have the
61        /// size 1.</para><para>If the specified dimension of A is empty, the median along that dimension will be NaN and that dimension will be 1.</para></returns>
62        public static ILRetArray<double>  median(ILInArray<double> A, int dim = -1)
63        {
64           
65            using (ILScope.Enter(A)) {
66                if (dim < 0)
67                    dim = A.Size.WorkingDimension();
68
69                if (dim >= A.Size.NumberOfDimensions)
70                    return   A.C;
71               
72                if (A.IsScalar) {
73                   
74                    return array<double>(new double[] { A.GetValue(0) }, 1, 1);
75                }
76
77                if (A.S[dim] == 1)
78                    return  A.C;
79
80                int[] newDims = A.S.ToIntArray();
81                newDims[dim] = 1;
82                ILSize retDimension = new ILSize(newDims);
83
84                if (A.IsEmpty)
85                    return array<double>(double.NaN,retDimension);
86
87                 double[] retArr = ILMemoryPool.Pool.New< double>(retDimension.NumberOfElements);
88
89                int maxRuns = retDimension.NumberOfElements;
90               
91                double[] aArray = null;
92                if (maxRuns == 1) {
93                    // ho: easier would be to use a new local array:
94                    // ILArray<double> aClone = A.C;
95                    // aArray = aClone.GetArrayForWrite();  here... (but the implemented way works just as well)
96                    aArray = ILMemoryPool.Pool.New< double>(A.S[dim]);
97                    A.ExportValues(ref aArray);
98                    retArr[0] = median_worker(aArray, A.S[dim]);
99                    ILMemoryPool.Pool.Free(aArray);
100                } else
101                {
102                    #region may run parallel
103                    aArray = A.GetArrayForRead();
104                    int inc = A.Size.SequentialIndexDistance(dim);
105                    int dimLen = A.Size[dim];
106                    int modHelp = A.Size.NumberOfElements - 1;
107                    int modOut = retDimension.NumberOfElements - 1;
108                    int incOut = retDimension.SequentialIndexDistance(dim);
109                    int numelA = A.S.NumberOfElements;
110                    int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength, workerCount = 1;
111                    if (Settings.s_maxNumberThreads > 1 && maxRuns > 1
112                        && numelA / 2 >= Settings.s_minParallelElement1Count) {
113
114                        if (maxRuns >= Settings.s_maxNumberThreads
115                            && numelA / Settings.s_maxNumberThreads > Settings.s_minParallelElement1Count) {
116                            workItemLength = maxRuns / workItemCount;
117                        } else {
118                            workItemLength = maxRuns / 2;
119                            workItemCount = 2;
120                        }
121                       
122                    } else {
123                        workItemLength = maxRuns;
124                        workItemCount = 1;
125                    }
126                    Action<object> action = (data) => {
127                        Tuple<int, int> range = (Tuple<int, int>)data;
128                        int from = range.Item1, to = range.Item2;
129                       
130                        double[] tmpArr = ILMemoryPool.Pool.New< double>(dimLen);
131                        for (int c = from; c < to; c++)
132                        {
133                            int pos = (int)(((long)dimLen * c * inc) % modHelp);
134
135                            long posOut = ((long)c * incOut);
136                            if (posOut > modOut)
137                                posOut = ((posOut - 1) % modOut) + 1;
138                            int end = pos + dimLen * inc;
139                            int k = 0;
140                            // ho: TODO: probably faster if operating on a full clone of A. median_worker would handle LDA, start, end than ...
141                            for (int j = pos; j < end; j += inc)
142                                tmpArr[k++] = aArray[j];
143                            retArr[posOut] = median_worker(tmpArr, dimLen);
144                        }
145                        ILMemoryPool.Pool.Free(tmpArr);
146                        System.Threading.Interlocked.Decrement(ref workerCount);
147                    };
148                    for (; i < workItemCount - 1; i++) {
149                        Interlocked.Increment(ref workerCount);
150                        ILThreadPool.QueueUserWorkItem(i,action, Tuple.Create(i * workItemLength, (i + 1) * workItemLength));
151                    }
152                    action(Tuple.Create(i * workItemLength, maxRuns));
153                    ILThreadPool.Wait4Workers(ref workerCount);
154                    #endregion
155                }
156                return array(retArr, newDims);
157            }
158        }
159
160#region HYCALPER AUTO GENERATED CODE
161
162        /// <summary>
163        /// Calculate median along the specified dimension
164        /// </summary>
165        /// <param name="A">Input Array</param>
166        /// <returns><para>Array having the specified dimension reduced to the length 1 with the median of
167        /// all elements along that dimension.</para>
168        /// <param name="dim">[Optional] Index of dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1).</param>
169        /// <para>The result will have the same number of dimensions as A, but the specified dimension will have the
170        /// size 1.</para><para>If the specified dimension of A is empty, the median along that dimension will be NaN and that dimension will be 1.</para></returns>
171        public static ILRetArray<double>  median(ILInArray<Int64> A, int dim = -1)
172        {
173           
174            using (ILScope.Enter(A)) {
175                if (dim < 0)
176                    dim = A.Size.WorkingDimension();
177
178                if (dim >= A.Size.NumberOfDimensions)
179                    return  todouble(A.C);
180               
181                if (A.IsScalar) {
182                   
183                    return array<double>(new double[] { A.GetValue(0) }, 1, 1);
184                }
185
186                if (A.S[dim] == 1)
187                    return  todouble(A.C);
188
189                int[] newDims = A.S.ToIntArray();
190                newDims[dim] = 1;
191                ILSize retDimension = new ILSize(newDims);
192
193                if (A.IsEmpty)
194                    return array<double>(double.NaN,retDimension);
195
196                double[] retArr = ILMemoryPool.Pool.New< double>(retDimension.NumberOfElements);
197
198                int maxRuns = retDimension.NumberOfElements;
199               
200                Int64[] aArray = null;
201                if (maxRuns == 1) {
202                    // ho: easier would be to use a new local array:
203                    // ILArray<double> aClone = A.C;
204                    // aArray = aClone.GetArrayForWrite();  here... (but the implemented way works just as well)
205                    aArray = ILMemoryPool.Pool.New< Int64>(A.S[dim]);
206                    A.ExportValues(ref aArray);
207                    retArr[0] = median_worker(aArray, A.S[dim]);
208                    ILMemoryPool.Pool.Free(aArray);
209                } else
210                {
211                    #region may run parallel
212                    aArray = A.GetArrayForRead();
213                    int inc = A.Size.SequentialIndexDistance(dim);
214                    int dimLen = A.Size[dim];
215                    int modHelp = A.Size.NumberOfElements - 1;
216                    int modOut = retDimension.NumberOfElements - 1;
217                    int incOut = retDimension.SequentialIndexDistance(dim);
218                    int numelA = A.S.NumberOfElements;
219                    int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength, workerCount = 1;
220                    if (Settings.s_maxNumberThreads > 1 && maxRuns > 1
221                        && numelA / 2 >= Settings.s_minParallelElement1Count) {
222
223                        if (maxRuns >= Settings.s_maxNumberThreads
224                            && numelA / Settings.s_maxNumberThreads > Settings.s_minParallelElement1Count) {
225                            workItemLength = maxRuns / workItemCount;
226                        } else {
227                            workItemLength = maxRuns / 2;
228                            workItemCount = 2;
229                        }
230                       
231                    } else {
232                        workItemLength = maxRuns;
233                        workItemCount = 1;
234                    }
235                    Action<object> action = (data) => {
236                        Tuple<int, int> range = (Tuple<int, int>)data;
237                        int from = range.Item1, to = range.Item2;
238                       
239                        Int64[] tmpArr = ILMemoryPool.Pool.New< Int64>(dimLen);
240                        for (int c = from; c < to; c++)
241                        {
242                            int pos = (int)(((long)dimLen * c * inc) % modHelp);
243
244                            long posOut = ((long)c * incOut);
245                            if (posOut > modOut)
246                                posOut = ((posOut - 1) % modOut) + 1;
247                            int end = pos + dimLen * inc;
248                            int k = 0;
249                            // ho: TODO: probably faster if operating on a full clone of A. median_worker would handle LDA, start, end than ...
250                            for (int j = pos; j < end; j += inc)
251                                tmpArr[k++] = aArray[j];
252                            retArr[posOut] = median_worker(tmpArr, dimLen);
253                        }
254                        ILMemoryPool.Pool.Free(tmpArr);
255                        System.Threading.Interlocked.Decrement(ref workerCount);
256                    };
257                    for (; i < workItemCount - 1; i++) {
258                        Interlocked.Increment(ref workerCount);
259                        ILThreadPool.QueueUserWorkItem(i,action, Tuple.Create(i * workItemLength, (i + 1) * workItemLength));
260                    }
261                    action(Tuple.Create(i * workItemLength, maxRuns));
262                    ILThreadPool.Wait4Workers(ref workerCount);
263                    #endregion
264                }
265                return array(retArr, newDims);
266            }
267        }
268        /// <summary>
269        /// Calculate median along the specified dimension
270        /// </summary>
271        /// <param name="A">Input Array</param>
272        /// <returns><para>Array having the specified dimension reduced to the length 1 with the median of
273        /// all elements along that dimension.</para>
274        /// <param name="dim">[Optional] Index of dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1).</param>
275        /// <para>The result will have the same number of dimensions as A, but the specified dimension will have the
276        /// size 1.</para><para>If the specified dimension of A is empty, the median along that dimension will be NaN and that dimension will be 1.</para></returns>
277        public static ILRetArray<double>  median(ILInArray<Int32> A, int dim = -1)
278        {
279           
280            using (ILScope.Enter(A)) {
281                if (dim < 0)
282                    dim = A.Size.WorkingDimension();
283
284                if (dim >= A.Size.NumberOfDimensions)
285                    return  todouble(A.C);
286               
287                if (A.IsScalar) {
288                   
289                    return array<double>(new double[] { A.GetValue(0) }, 1, 1);
290                }
291
292                if (A.S[dim] == 1)
293                    return  todouble(A.C);
294
295                int[] newDims = A.S.ToIntArray();
296                newDims[dim] = 1;
297                ILSize retDimension = new ILSize(newDims);
298
299                if (A.IsEmpty)
300                    return array<double>(double.NaN,retDimension);
301
302                double[] retArr = ILMemoryPool.Pool.New< double>(retDimension.NumberOfElements);
303
304                int maxRuns = retDimension.NumberOfElements;
305               
306                Int32[] aArray = null;
307                if (maxRuns == 1) {
308                    // ho: easier would be to use a new local array:
309                    // ILArray<double> aClone = A.C;
310                    // aArray = aClone.GetArrayForWrite();  here... (but the implemented way works just as well)
311                    aArray = ILMemoryPool.Pool.New< Int32>(A.S[dim]);
312                    A.ExportValues(ref aArray);
313                    retArr[0] = median_worker(aArray, A.S[dim]);
314                    ILMemoryPool.Pool.Free(aArray);
315                } else
316                {
317                    #region may run parallel
318                    aArray = A.GetArrayForRead();
319                    int inc = A.Size.SequentialIndexDistance(dim);
320                    int dimLen = A.Size[dim];
321                    int modHelp = A.Size.NumberOfElements - 1;
322                    int modOut = retDimension.NumberOfElements - 1;
323                    int incOut = retDimension.SequentialIndexDistance(dim);
324                    int numelA = A.S.NumberOfElements;
325                    int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength, workerCount = 1;
326                    if (Settings.s_maxNumberThreads > 1 && maxRuns > 1
327                        && numelA / 2 >= Settings.s_minParallelElement1Count) {
328
329                        if (maxRuns >= Settings.s_maxNumberThreads
330                            && numelA / Settings.s_maxNumberThreads > Settings.s_minParallelElement1Count) {
331                            workItemLength = maxRuns / workItemCount;
332                        } else {
333                            workItemLength = maxRuns / 2;
334                            workItemCount = 2;
335                        }
336                       
337                    } else {
338                        workItemLength = maxRuns;
339                        workItemCount = 1;
340                    }
341                    Action<object> action = (data) => {
342                        Tuple<int, int> range = (Tuple<int, int>)data;
343                        int from = range.Item1, to = range.Item2;
344                       
345                        Int32[] tmpArr = ILMemoryPool.Pool.New< Int32>(dimLen);
346                        for (int c = from; c < to; c++)
347                        {
348                            int pos = (int)(((long)dimLen * c * inc) % modHelp);
349
350                            long posOut = ((long)c * incOut);
351                            if (posOut > modOut)
352                                posOut = ((posOut - 1) % modOut) + 1;
353                            int end = pos + dimLen * inc;
354                            int k = 0;
355                            // ho: TODO: probably faster if operating on a full clone of A. median_worker would handle LDA, start, end than ...
356                            for (int j = pos; j < end; j += inc)
357                                tmpArr[k++] = aArray[j];
358                            retArr[posOut] = median_worker(tmpArr, dimLen);
359                        }
360                        ILMemoryPool.Pool.Free(tmpArr);
361                        System.Threading.Interlocked.Decrement(ref workerCount);
362                    };
363                    for (; i < workItemCount - 1; i++) {
364                        Interlocked.Increment(ref workerCount);
365                        ILThreadPool.QueueUserWorkItem(i,action, Tuple.Create(i * workItemLength, (i + 1) * workItemLength));
366                    }
367                    action(Tuple.Create(i * workItemLength, maxRuns));
368                    ILThreadPool.Wait4Workers(ref workerCount);
369                    #endregion
370                }
371                return array(retArr, newDims);
372            }
373        }
374        /// <summary>
375        /// Calculate median along the specified dimension
376        /// </summary>
377        /// <param name="A">Input Array</param>
378        /// <returns><para>Array having the specified dimension reduced to the length 1 with the median of
379        /// all elements along that dimension.</para>
380        /// <param name="dim">[Optional] Index of dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1).</param>
381        /// <para>The result will have the same number of dimensions as A, but the specified dimension will have the
382        /// size 1.</para><para>If the specified dimension of A is empty, the median along that dimension will be NaN and that dimension will be 1.</para></returns>
383        public static ILRetArray<double>  median(ILInArray<byte> A, int dim = -1)
384        {
385           
386            using (ILScope.Enter(A)) {
387                if (dim < 0)
388                    dim = A.Size.WorkingDimension();
389
390                if (dim >= A.Size.NumberOfDimensions)
391                    return  todouble(A.C);
392               
393                if (A.IsScalar) {
394                   
395                    return array<double>(new double[] { A.GetValue(0) }, 1, 1);
396                }
397
398                if (A.S[dim] == 1)
399                    return  todouble(A.C);
400
401                int[] newDims = A.S.ToIntArray();
402                newDims[dim] = 1;
403                ILSize retDimension = new ILSize(newDims);
404
405                if (A.IsEmpty)
406                    return array<double>(double.NaN,retDimension);
407
408                double[] retArr = ILMemoryPool.Pool.New< double>(retDimension.NumberOfElements);
409
410                int maxRuns = retDimension.NumberOfElements;
411               
412                byte[] aArray = null;
413                if (maxRuns == 1) {
414                    // ho: easier would be to use a new local array:
415                    // ILArray<double> aClone = A.C;
416                    // aArray = aClone.GetArrayForWrite();  here... (but the implemented way works just as well)
417                    aArray = ILMemoryPool.Pool.New< byte>(A.S[dim]);
418                    A.ExportValues(ref aArray);
419                    retArr[0] = median_worker(aArray, A.S[dim]);
420                    ILMemoryPool.Pool.Free(aArray);
421                } else
422                {
423                    #region may run parallel
424                    aArray = A.GetArrayForRead();
425                    int inc = A.Size.SequentialIndexDistance(dim);
426                    int dimLen = A.Size[dim];
427                    int modHelp = A.Size.NumberOfElements - 1;
428                    int modOut = retDimension.NumberOfElements - 1;
429                    int incOut = retDimension.SequentialIndexDistance(dim);
430                    int numelA = A.S.NumberOfElements;
431                    int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength, workerCount = 1;
432                    if (Settings.s_maxNumberThreads > 1 && maxRuns > 1
433                        && numelA / 2 >= Settings.s_minParallelElement1Count) {
434
435                        if (maxRuns >= Settings.s_maxNumberThreads
436                            && numelA / Settings.s_maxNumberThreads > Settings.s_minParallelElement1Count) {
437                            workItemLength = maxRuns / workItemCount;
438                        } else {
439                            workItemLength = maxRuns / 2;
440                            workItemCount = 2;
441                        }
442                       
443                    } else {
444                        workItemLength = maxRuns;
445                        workItemCount = 1;
446                    }
447                    Action<object> action = (data) => {
448                        Tuple<int, int> range = (Tuple<int, int>)data;
449                        int from = range.Item1, to = range.Item2;
450                       
451                        byte[] tmpArr = ILMemoryPool.Pool.New< byte>(dimLen);
452                        for (int c = from; c < to; c++)
453                        {
454                            int pos = (int)(((long)dimLen * c * inc) % modHelp);
455
456                            long posOut = ((long)c * incOut);
457                            if (posOut > modOut)
458                                posOut = ((posOut - 1) % modOut) + 1;
459                            int end = pos + dimLen * inc;
460                            int k = 0;
461                            // ho: TODO: probably faster if operating on a full clone of A. median_worker would handle LDA, start, end than ...
462                            for (int j = pos; j < end; j += inc)
463                                tmpArr[k++] = aArray[j];
464                            retArr[posOut] = median_worker(tmpArr, dimLen);
465                        }
466                        ILMemoryPool.Pool.Free(tmpArr);
467                        System.Threading.Interlocked.Decrement(ref workerCount);
468                    };
469                    for (; i < workItemCount - 1; i++) {
470                        Interlocked.Increment(ref workerCount);
471                        ILThreadPool.QueueUserWorkItem(i,action, Tuple.Create(i * workItemLength, (i + 1) * workItemLength));
472                    }
473                    action(Tuple.Create(i * workItemLength, maxRuns));
474                    ILThreadPool.Wait4Workers(ref workerCount);
475                    #endregion
476                }
477                return array(retArr, newDims);
478            }
479        }
480        /// <summary>
481        /// Calculate median along the specified dimension
482        /// </summary>
483        /// <param name="A">Input Array</param>
484        /// <returns><para>Array having the specified dimension reduced to the length 1 with the median of
485        /// all elements along that dimension.</para>
486        /// <param name="dim">[Optional] Index of dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1).</param>
487        /// <para>The result will have the same number of dimensions as A, but the specified dimension will have the
488        /// size 1.</para><para>If the specified dimension of A is empty, the median along that dimension will be NaN and that dimension will be 1.</para></returns>
489        public static ILRetArray<fcomplex>  median(ILInArray<fcomplex> A, int dim = -1)
490        {
491           
492            using (ILScope.Enter(A)) {
493                if (dim < 0)
494                    dim = A.Size.WorkingDimension();
495
496                if (dim >= A.Size.NumberOfDimensions)
497                    return  A.C;
498               
499                if (A.IsScalar) {
500                   
501                    return array<fcomplex>(new fcomplex[] { A.GetValue(0) }, 1, 1);
502                }
503
504                if (A.S[dim] == 1)
505                    return  A.C;
506
507                int[] newDims = A.S.ToIntArray();
508                newDims[dim] = 1;
509                ILSize retDimension = new ILSize(newDims);
510
511                if (A.IsEmpty)
512                    return array<fcomplex>(fcomplex.NaN,retDimension);
513
514                fcomplex[] retArr = ILMemoryPool.Pool.New< fcomplex>(retDimension.NumberOfElements);
515
516                int maxRuns = retDimension.NumberOfElements;
517               
518                fcomplex[] aArray = null;
519                if (maxRuns == 1) {
520                    // ho: easier would be to use a new local array:
521                    // ILArray<double> aClone = A.C;
522                    // aArray = aClone.GetArrayForWrite();  here... (but the implemented way works just as well)
523                    aArray = ILMemoryPool.Pool.New< fcomplex>(A.S[dim]);
524                    A.ExportValues(ref aArray);
525                    retArr[0] = median_worker(aArray, A.S[dim]);
526                    ILMemoryPool.Pool.Free(aArray);
527                } else
528                {
529                    #region may run parallel
530                    aArray = A.GetArrayForRead();
531                    int inc = A.Size.SequentialIndexDistance(dim);
532                    int dimLen = A.Size[dim];
533                    int modHelp = A.Size.NumberOfElements - 1;
534                    int modOut = retDimension.NumberOfElements - 1;
535                    int incOut = retDimension.SequentialIndexDistance(dim);
536                    int numelA = A.S.NumberOfElements;
537                    int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength, workerCount = 1;
538                    if (Settings.s_maxNumberThreads > 1 && maxRuns > 1
539                        && numelA / 2 >= Settings.s_minParallelElement1Count) {
540
541                        if (maxRuns >= Settings.s_maxNumberThreads
542                            && numelA / Settings.s_maxNumberThreads > Settings.s_minParallelElement1Count) {
543                            workItemLength = maxRuns / workItemCount;
544                        } else {
545                            workItemLength = maxRuns / 2;
546                            workItemCount = 2;
547                        }
548                       
549                    } else {
550                        workItemLength = maxRuns;
551                        workItemCount = 1;
552                    }
553                    Action<object> action = (data) => {
554                        Tuple<int, int> range = (Tuple<int, int>)data;
555                        int from = range.Item1, to = range.Item2;
556                       
557                        fcomplex[] tmpArr = ILMemoryPool.Pool.New< fcomplex>(dimLen);
558                        for (int c = from; c < to; c++)
559                        {
560                            int pos = (int)(((long)dimLen * c * inc) % modHelp);
561
562                            long posOut = ((long)c * incOut);
563                            if (posOut > modOut)
564                                posOut = ((posOut - 1) % modOut) + 1;
565                            int end = pos + dimLen * inc;
566                            int k = 0;
567                            // ho: TODO: probably faster if operating on a full clone of A. median_worker would handle LDA, start, end than ...
568                            for (int j = pos; j < end; j += inc)
569                                tmpArr[k++] = aArray[j];
570                            retArr[posOut] = median_worker(tmpArr, dimLen);
571                        }
572                        ILMemoryPool.Pool.Free(tmpArr);
573                        System.Threading.Interlocked.Decrement(ref workerCount);
574                    };
575                    for (; i < workItemCount - 1; i++) {
576                        Interlocked.Increment(ref workerCount);
577                        ILThreadPool.QueueUserWorkItem(i,action, Tuple.Create(i * workItemLength, (i + 1) * workItemLength));
578                    }
579                    action(Tuple.Create(i * workItemLength, maxRuns));
580                    ILThreadPool.Wait4Workers(ref workerCount);
581                    #endregion
582                }
583                return array(retArr, newDims);
584            }
585        }
586        /// <summary>
587        /// Calculate median along the specified dimension
588        /// </summary>
589        /// <param name="A">Input Array</param>
590        /// <returns><para>Array having the specified dimension reduced to the length 1 with the median of
591        /// all elements along that dimension.</para>
592        /// <param name="dim">[Optional] Index of dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1).</param>
593        /// <para>The result will have the same number of dimensions as A, but the specified dimension will have the
594        /// size 1.</para><para>If the specified dimension of A is empty, the median along that dimension will be NaN and that dimension will be 1.</para></returns>
595        public static ILRetArray<float>  median(ILInArray<float> A, int dim = -1)
596        {
597           
598            using (ILScope.Enter(A)) {
599                if (dim < 0)
600                    dim = A.Size.WorkingDimension();
601
602                if (dim >= A.Size.NumberOfDimensions)
603                    return  A.C;
604               
605                if (A.IsScalar) {
606                   
607                    return array<float>(new float[] { A.GetValue(0) }, 1, 1);
608                }
609
610                if (A.S[dim] == 1)
611                    return  A.C;
612
613                int[] newDims = A.S.ToIntArray();
614                newDims[dim] = 1;
615                ILSize retDimension = new ILSize(newDims);
616
617                if (A.IsEmpty)
618                    return array<float>(float.NaN,retDimension);
619
620                float[] retArr = ILMemoryPool.Pool.New< float>(retDimension.NumberOfElements);
621
622                int maxRuns = retDimension.NumberOfElements;
623               
624                float[] aArray = null;
625                if (maxRuns == 1) {
626                    // ho: easier would be to use a new local array:
627                    // ILArray<double> aClone = A.C;
628                    // aArray = aClone.GetArrayForWrite();  here... (but the implemented way works just as well)
629                    aArray = ILMemoryPool.Pool.New< float>(A.S[dim]);
630                    A.ExportValues(ref aArray);
631                    retArr[0] = median_worker(aArray, A.S[dim]);
632                    ILMemoryPool.Pool.Free(aArray);
633                } else
634                {
635                    #region may run parallel
636                    aArray = A.GetArrayForRead();
637                    int inc = A.Size.SequentialIndexDistance(dim);
638                    int dimLen = A.Size[dim];
639                    int modHelp = A.Size.NumberOfElements - 1;
640                    int modOut = retDimension.NumberOfElements - 1;
641                    int incOut = retDimension.SequentialIndexDistance(dim);
642                    int numelA = A.S.NumberOfElements;
643                    int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength, workerCount = 1;
644                    if (Settings.s_maxNumberThreads > 1 && maxRuns > 1
645                        && numelA / 2 >= Settings.s_minParallelElement1Count) {
646
647                        if (maxRuns >= Settings.s_maxNumberThreads
648                            && numelA / Settings.s_maxNumberThreads > Settings.s_minParallelElement1Count) {
649                            workItemLength = maxRuns / workItemCount;
650                        } else {
651                            workItemLength = maxRuns / 2;
652                            workItemCount = 2;
653                        }
654                       
655                    } else {
656                        workItemLength = maxRuns;
657                        workItemCount = 1;
658                    }
659                    Action<object> action = (data) => {
660                        Tuple<int, int> range = (Tuple<int, int>)data;
661                        int from = range.Item1, to = range.Item2;
662                       
663                        float[] tmpArr = ILMemoryPool.Pool.New< float>(dimLen);
664                        for (int c = from; c < to; c++)
665                        {
666                            int pos = (int)(((long)dimLen * c * inc) % modHelp);
667
668                            long posOut = ((long)c * incOut);
669                            if (posOut > modOut)
670                                posOut = ((posOut - 1) % modOut) + 1;
671                            int end = pos + dimLen * inc;
672                            int k = 0;
673                            // ho: TODO: probably faster if operating on a full clone of A. median_worker would handle LDA, start, end than ...
674                            for (int j = pos; j < end; j += inc)
675                                tmpArr[k++] = aArray[j];
676                            retArr[posOut] = median_worker(tmpArr, dimLen);
677                        }
678                        ILMemoryPool.Pool.Free(tmpArr);
679                        System.Threading.Interlocked.Decrement(ref workerCount);
680                    };
681                    for (; i < workItemCount - 1; i++) {
682                        Interlocked.Increment(ref workerCount);
683                        ILThreadPool.QueueUserWorkItem(i,action, Tuple.Create(i * workItemLength, (i + 1) * workItemLength));
684                    }
685                    action(Tuple.Create(i * workItemLength, maxRuns));
686                    ILThreadPool.Wait4Workers(ref workerCount);
687                    #endregion
688                }
689                return array(retArr, newDims);
690            }
691        }
692        /// <summary>
693        /// Calculate median along the specified dimension
694        /// </summary>
695        /// <param name="A">Input Array</param>
696        /// <returns><para>Array having the specified dimension reduced to the length 1 with the median of
697        /// all elements along that dimension.</para>
698        /// <param name="dim">[Optional] Index of dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1).</param>
699        /// <para>The result will have the same number of dimensions as A, but the specified dimension will have the
700        /// size 1.</para><para>If the specified dimension of A is empty, the median along that dimension will be NaN and that dimension will be 1.</para></returns>
701        public static ILRetArray<complex>  median(ILInArray<complex> A, int dim = -1)
702        {
703           
704            using (ILScope.Enter(A)) {
705                if (dim < 0)
706                    dim = A.Size.WorkingDimension();
707
708                if (dim >= A.Size.NumberOfDimensions)
709                    return  A.C;
710               
711                if (A.IsScalar) {
712                   
713                    return array<complex>(new complex[] { A.GetValue(0) }, 1, 1);
714                }
715
716                if (A.S[dim] == 1)
717                    return  A.C;
718
719                int[] newDims = A.S.ToIntArray();
720                newDims[dim] = 1;
721                ILSize retDimension = new ILSize(newDims);
722
723                if (A.IsEmpty)
724                    return array<complex>(complex.NaN,retDimension);
725
726                complex[] retArr = ILMemoryPool.Pool.New< complex>(retDimension.NumberOfElements);
727
728                int maxRuns = retDimension.NumberOfElements;
729               
730                complex[] aArray = null;
731                if (maxRuns == 1) {
732                    // ho: easier would be to use a new local array:
733                    // ILArray<double> aClone = A.C;
734                    // aArray = aClone.GetArrayForWrite();  here... (but the implemented way works just as well)
735                    aArray = ILMemoryPool.Pool.New< complex>(A.S[dim]);
736                    A.ExportValues(ref aArray);
737                    retArr[0] = median_worker(aArray, A.S[dim]);
738                    ILMemoryPool.Pool.Free(aArray);
739                } else
740                {
741                    #region may run parallel
742                    aArray = A.GetArrayForRead();
743                    int inc = A.Size.SequentialIndexDistance(dim);
744                    int dimLen = A.Size[dim];
745                    int modHelp = A.Size.NumberOfElements - 1;
746                    int modOut = retDimension.NumberOfElements - 1;
747                    int incOut = retDimension.SequentialIndexDistance(dim);
748                    int numelA = A.S.NumberOfElements;
749                    int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength, workerCount = 1;
750                    if (Settings.s_maxNumberThreads > 1 && maxRuns > 1
751                        && numelA / 2 >= Settings.s_minParallelElement1Count) {
752
753                        if (maxRuns >= Settings.s_maxNumberThreads
754                            && numelA / Settings.s_maxNumberThreads > Settings.s_minParallelElement1Count) {
755                            workItemLength = maxRuns / workItemCount;
756                        } else {
757                            workItemLength = maxRuns / 2;
758                            workItemCount = 2;
759                        }
760                       
761                    } else {
762                        workItemLength = maxRuns;
763                        workItemCount = 1;
764                    }
765                    Action<object> action = (data) => {
766                        Tuple<int, int> range = (Tuple<int, int>)data;
767                        int from = range.Item1, to = range.Item2;
768                       
769                        complex[] tmpArr = ILMemoryPool.Pool.New< complex>(dimLen);
770                        for (int c = from; c < to; c++)
771                        {
772                            int pos = (int)(((long)dimLen * c * inc) % modHelp);
773
774                            long posOut = ((long)c * incOut);
775                            if (posOut > modOut)
776                                posOut = ((posOut - 1) % modOut) + 1;
777                            int end = pos + dimLen * inc;
778                            int k = 0;
779                            // ho: TODO: probably faster if operating on a full clone of A. median_worker would handle LDA, start, end than ...
780                            for (int j = pos; j < end; j += inc)
781                                tmpArr[k++] = aArray[j];
782                            retArr[posOut] = median_worker(tmpArr, dimLen);
783                        }
784                        ILMemoryPool.Pool.Free(tmpArr);
785                        System.Threading.Interlocked.Decrement(ref workerCount);
786                    };
787                    for (; i < workItemCount - 1; i++) {
788                        Interlocked.Increment(ref workerCount);
789                        ILThreadPool.QueueUserWorkItem(i,action, Tuple.Create(i * workItemLength, (i + 1) * workItemLength));
790                    }
791                    action(Tuple.Create(i * workItemLength, maxRuns));
792                    ILThreadPool.Wait4Workers(ref workerCount);
793                    #endregion
794                }
795                return array(retArr, newDims);
796            }
797        }
798
799#endregion HYCALPER AUTO GENERATED CODE
800
801        #region private helpers
802
803        static double median_worker(double[] list, int length)
804        {
805            // ATTENTION: list will be changed in here!!!
806            if (length % 2 == 0)
807            {
808                // even number of elements
809                int newRight;
810               
811                double a = (double)quickselect_worker(list, 0, length - 1, length / 2, out newRight);
812               
813               
814                double b = (double)quickselect_worker(list, newRight + 1, length - 1, 1, out newRight);
815                return b - (b - a) / (double) 2.0; // SMA: Reduces rounding errors...apparently.
816            }
817            else
818            {
819                // odd number of elements
820                int dummy;
821                return (double) quickselect_worker(list, 0, length - 1, (length - 1) / 2 + 1, out dummy);
822            }
823        }
824
825#region HYCALPER AUTO GENERATED CODE
826
827        static double median_worker(Int64[] list, int length)
828        {
829            // ATTENTION: list will be changed in here!!!
830            if (length % 2 == 0)
831            {
832                // even number of elements
833                int newRight;
834               
835                double a = (double)quickselect_worker(list, 0, length - 1, length / 2, out newRight);
836               
837               
838                double b = (double)quickselect_worker(list, newRight + 1, length - 1, 1, out newRight);
839                return b - (b - a) / (double) 2.0; // SMA: Reduces rounding errors...apparently.
840            }
841            else
842            {
843                // odd number of elements
844                int dummy;
845                return (double) quickselect_worker(list, 0, length - 1, (length - 1) / 2 + 1, out dummy);
846            }
847        }
848        static double median_worker(Int32[] list, int length)
849        {
850            // ATTENTION: list will be changed in here!!!
851            if (length % 2 == 0)
852            {
853                // even number of elements
854                int newRight;
855               
856                double a = (double)quickselect_worker(list, 0, length - 1, length / 2, out newRight);
857               
858               
859                double b = (double)quickselect_worker(list, newRight + 1, length - 1, 1, out newRight);
860                return b - (b - a) / (double) 2.0; // SMA: Reduces rounding errors...apparently.
861            }
862            else
863            {
864                // odd number of elements
865                int dummy;
866                return (double) quickselect_worker(list, 0, length - 1, (length - 1) / 2 + 1, out dummy);
867            }
868        }
869        static double median_worker(byte[] list, int length)
870        {
871            // ATTENTION: list will be changed in here!!!
872            if (length % 2 == 0)
873            {
874                // even number of elements
875                int newRight;
876               
877                double a = (double)quickselect_worker(list, 0, length - 1, length / 2, out newRight);
878               
879               
880                double b = (double)quickselect_worker(list, newRight + 1, length - 1, 1, out newRight);
881                return b - (b - a) / (double) 2.0; // SMA: Reduces rounding errors...apparently.
882            }
883            else
884            {
885                // odd number of elements
886                int dummy;
887                return (double) quickselect_worker(list, 0, length - 1, (length - 1) / 2 + 1, out dummy);
888            }
889        }
890        static fcomplex median_worker(fcomplex[] list, int length)
891        {
892            // ATTENTION: list will be changed in here!!!
893            if (length % 2 == 0)
894            {
895                // even number of elements
896                int newRight;
897               
898                fcomplex a = (fcomplex)quickselect_worker(list, 0, length - 1, length / 2, out newRight);
899               
900               
901                fcomplex b = (fcomplex)quickselect_worker(list, newRight + 1, length - 1, 1, out newRight);
902                return b - (b - a) / (fcomplex) 2.0; // SMA: Reduces rounding errors...apparently.
903            }
904            else
905            {
906                // odd number of elements
907                int dummy;
908                return (fcomplex) quickselect_worker(list, 0, length - 1, (length - 1) / 2 + 1, out dummy);
909            }
910        }
911        static float median_worker(float[] list, int length)
912        {
913            // ATTENTION: list will be changed in here!!!
914            if (length % 2 == 0)
915            {
916                // even number of elements
917                int newRight;
918               
919                float a = (float)quickselect_worker(list, 0, length - 1, length / 2, out newRight);
920               
921               
922                float b = (float)quickselect_worker(list, newRight + 1, length - 1, 1, out newRight);
923                return b - (b - a) / (float) 2.0; // SMA: Reduces rounding errors...apparently.
924            }
925            else
926            {
927                // odd number of elements
928                int dummy;
929                return (float) quickselect_worker(list, 0, length - 1, (length - 1) / 2 + 1, out dummy);
930            }
931        }
932        static complex median_worker(complex[] list, int length)
933        {
934            // ATTENTION: list will be changed in here!!!
935            if (length % 2 == 0)
936            {
937                // even number of elements
938                int newRight;
939               
940                complex a = (complex)quickselect_worker(list, 0, length - 1, length / 2, out newRight);
941               
942               
943                complex b = (complex)quickselect_worker(list, newRight + 1, length - 1, 1, out newRight);
944                return b - (b - a) / (complex) 2.0; // SMA: Reduces rounding errors...apparently.
945            }
946            else
947            {
948                // odd number of elements
949                int dummy;
950                return (complex) quickselect_worker(list, 0, length - 1, (length - 1) / 2 + 1, out dummy);
951            }
952        }
953
954#endregion HYCALPER AUTO GENERATED CODE
955       #endregion
956    }
957}
Note: See TracBrowser for help on using the repository browser.