/// /// This file is part of ILNumerics Community Edition. /// /// ILNumerics Community Edition - high performance computing for applications. /// Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net /// /// ILNumerics Community Edition is free software: you can redistribute it and/or modify /// it under the terms of the GNU General Public License version 3 as published by /// the Free Software Foundation. /// /// ILNumerics Community Edition is distributed in the hope that it will be useful, /// but WITHOUT ANY WARRANTY; without even the implied warranty of /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /// GNU General Public License for more details. /// /// You should have received a copy of the GNU General Public License /// along with ILNumerics Community Edition. See the file License.txt in the root /// of your distribution package. If not, see . /// /// In addition this software uses the following components and/or licenses: /// /// ================================================================================= /// The Open Toolkit Library License /// /// Copyright (c) 2006 - 2009 the Open Toolkit library. /// /// Permission is hereby granted, free of charge, to any person obtaining a copy /// of this software and associated documentation files (the "Software"), to deal /// in the Software without restriction, including without limitation the rights to /// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of /// the Software, and to permit persons to whom the Software is furnished to do /// so, subject to the following conditions: /// /// The above copyright notice and this permission notice shall be included in all /// copies or substantial portions of the Software. /// /// ================================================================================= /// using System; using System.Collections.Generic; using System.Text; using System.Threading; using ILNumerics.Storage; using ILNumerics.Misc; using ILNumerics.Exceptions; using System.Linq; namespace ILNumerics { public partial class ILMath { /// /// Calculate median along the specified dimension /// /// Input Array /// Array having the specified dimension reduced to the length 1 with the median of /// all elements along that dimension. /// [Optional] Index of dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1). /// The result will have the same number of dimensions as A, but the specified dimension will have the /// size 1.If the specified dimension of A is empty, the median along that dimension will be NaN and that dimension will be 1. public static ILRetArray median(ILInArray A, int dim = -1) { using (ILScope.Enter(A)) { if (dim < 0) dim = A.Size.WorkingDimension(); if (dim >= A.Size.NumberOfDimensions) return A.C; if (A.IsScalar) { return array(new double[] { A.GetValue(0) }, 1, 1); } if (A.S[dim] == 1) return A.C; int[] newDims = A.S.ToIntArray(); newDims[dim] = 1; ILSize retDimension = new ILSize(newDims); if (A.IsEmpty) return array(double.NaN,retDimension); double[] retArr = ILMemoryPool.Pool.New< double>(retDimension.NumberOfElements); int maxRuns = retDimension.NumberOfElements; double[] aArray = null; if (maxRuns == 1) { // ho: easier would be to use a new local array: // ILArray aClone = A.C; // aArray = aClone.GetArrayForWrite(); here... (but the implemented way works just as well) aArray = ILMemoryPool.Pool.New< double>(A.S[dim]); A.ExportValues(ref aArray); retArr[0] = median_worker(aArray, A.S[dim]); ILMemoryPool.Pool.Free(aArray); } else { #region may run parallel aArray = A.GetArrayForRead(); int inc = A.Size.SequentialIndexDistance(dim); int dimLen = A.Size[dim]; int modHelp = A.Size.NumberOfElements - 1; int modOut = retDimension.NumberOfElements - 1; int incOut = retDimension.SequentialIndexDistance(dim); int numelA = A.S.NumberOfElements; int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength, workerCount = 1; if (Settings.s_maxNumberThreads > 1 && maxRuns > 1 && numelA / 2 >= Settings.s_minParallelElement1Count) { if (maxRuns >= Settings.s_maxNumberThreads && numelA / Settings.s_maxNumberThreads > Settings.s_minParallelElement1Count) { workItemLength = maxRuns / workItemCount; } else { workItemLength = maxRuns / 2; workItemCount = 2; } } else { workItemLength = maxRuns; workItemCount = 1; } Action action = (data) => { Tuple range = (Tuple)data; int from = range.Item1, to = range.Item2; double[] tmpArr = ILMemoryPool.Pool.New< double>(dimLen); for (int c = from; c < to; c++) { int pos = (int)(((long)dimLen * c * inc) % modHelp); long posOut = ((long)c * incOut); if (posOut > modOut) posOut = ((posOut - 1) % modOut) + 1; int end = pos + dimLen * inc; int k = 0; // ho: TODO: probably faster if operating on a full clone of A. median_worker would handle LDA, start, end than ... for (int j = pos; j < end; j += inc) tmpArr[k++] = aArray[j]; retArr[posOut] = median_worker(tmpArr, dimLen); } ILMemoryPool.Pool.Free(tmpArr); System.Threading.Interlocked.Decrement(ref workerCount); }; for (; i < workItemCount - 1; i++) { Interlocked.Increment(ref workerCount); ILThreadPool.QueueUserWorkItem(i,action, Tuple.Create(i * workItemLength, (i + 1) * workItemLength)); } action(Tuple.Create(i * workItemLength, maxRuns)); ILThreadPool.Wait4Workers(ref workerCount); #endregion } return array(retArr, newDims); } } #region HYCALPER AUTO GENERATED CODE /// /// Calculate median along the specified dimension /// /// Input Array /// Array having the specified dimension reduced to the length 1 with the median of /// all elements along that dimension. /// [Optional] Index of dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1). /// The result will have the same number of dimensions as A, but the specified dimension will have the /// size 1.If the specified dimension of A is empty, the median along that dimension will be NaN and that dimension will be 1. public static ILRetArray median(ILInArray A, int dim = -1) { using (ILScope.Enter(A)) { if (dim < 0) dim = A.Size.WorkingDimension(); if (dim >= A.Size.NumberOfDimensions) return todouble(A.C); if (A.IsScalar) { return array(new double[] { A.GetValue(0) }, 1, 1); } if (A.S[dim] == 1) return todouble(A.C); int[] newDims = A.S.ToIntArray(); newDims[dim] = 1; ILSize retDimension = new ILSize(newDims); if (A.IsEmpty) return array(double.NaN,retDimension); double[] retArr = ILMemoryPool.Pool.New< double>(retDimension.NumberOfElements); int maxRuns = retDimension.NumberOfElements; Int64[] aArray = null; if (maxRuns == 1) { // ho: easier would be to use a new local array: // ILArray aClone = A.C; // aArray = aClone.GetArrayForWrite(); here... (but the implemented way works just as well) aArray = ILMemoryPool.Pool.New< Int64>(A.S[dim]); A.ExportValues(ref aArray); retArr[0] = median_worker(aArray, A.S[dim]); ILMemoryPool.Pool.Free(aArray); } else { #region may run parallel aArray = A.GetArrayForRead(); int inc = A.Size.SequentialIndexDistance(dim); int dimLen = A.Size[dim]; int modHelp = A.Size.NumberOfElements - 1; int modOut = retDimension.NumberOfElements - 1; int incOut = retDimension.SequentialIndexDistance(dim); int numelA = A.S.NumberOfElements; int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength, workerCount = 1; if (Settings.s_maxNumberThreads > 1 && maxRuns > 1 && numelA / 2 >= Settings.s_minParallelElement1Count) { if (maxRuns >= Settings.s_maxNumberThreads && numelA / Settings.s_maxNumberThreads > Settings.s_minParallelElement1Count) { workItemLength = maxRuns / workItemCount; } else { workItemLength = maxRuns / 2; workItemCount = 2; } } else { workItemLength = maxRuns; workItemCount = 1; } Action action = (data) => { Tuple range = (Tuple)data; int from = range.Item1, to = range.Item2; Int64[] tmpArr = ILMemoryPool.Pool.New< Int64>(dimLen); for (int c = from; c < to; c++) { int pos = (int)(((long)dimLen * c * inc) % modHelp); long posOut = ((long)c * incOut); if (posOut > modOut) posOut = ((posOut - 1) % modOut) + 1; int end = pos + dimLen * inc; int k = 0; // ho: TODO: probably faster if operating on a full clone of A. median_worker would handle LDA, start, end than ... for (int j = pos; j < end; j += inc) tmpArr[k++] = aArray[j]; retArr[posOut] = median_worker(tmpArr, dimLen); } ILMemoryPool.Pool.Free(tmpArr); System.Threading.Interlocked.Decrement(ref workerCount); }; for (; i < workItemCount - 1; i++) { Interlocked.Increment(ref workerCount); ILThreadPool.QueueUserWorkItem(i,action, Tuple.Create(i * workItemLength, (i + 1) * workItemLength)); } action(Tuple.Create(i * workItemLength, maxRuns)); ILThreadPool.Wait4Workers(ref workerCount); #endregion } return array(retArr, newDims); } } /// /// Calculate median along the specified dimension /// /// Input Array /// Array having the specified dimension reduced to the length 1 with the median of /// all elements along that dimension. /// [Optional] Index of dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1). /// The result will have the same number of dimensions as A, but the specified dimension will have the /// size 1.If the specified dimension of A is empty, the median along that dimension will be NaN and that dimension will be 1. public static ILRetArray median(ILInArray A, int dim = -1) { using (ILScope.Enter(A)) { if (dim < 0) dim = A.Size.WorkingDimension(); if (dim >= A.Size.NumberOfDimensions) return todouble(A.C); if (A.IsScalar) { return array(new double[] { A.GetValue(0) }, 1, 1); } if (A.S[dim] == 1) return todouble(A.C); int[] newDims = A.S.ToIntArray(); newDims[dim] = 1; ILSize retDimension = new ILSize(newDims); if (A.IsEmpty) return array(double.NaN,retDimension); double[] retArr = ILMemoryPool.Pool.New< double>(retDimension.NumberOfElements); int maxRuns = retDimension.NumberOfElements; Int32[] aArray = null; if (maxRuns == 1) { // ho: easier would be to use a new local array: // ILArray aClone = A.C; // aArray = aClone.GetArrayForWrite(); here... (but the implemented way works just as well) aArray = ILMemoryPool.Pool.New< Int32>(A.S[dim]); A.ExportValues(ref aArray); retArr[0] = median_worker(aArray, A.S[dim]); ILMemoryPool.Pool.Free(aArray); } else { #region may run parallel aArray = A.GetArrayForRead(); int inc = A.Size.SequentialIndexDistance(dim); int dimLen = A.Size[dim]; int modHelp = A.Size.NumberOfElements - 1; int modOut = retDimension.NumberOfElements - 1; int incOut = retDimension.SequentialIndexDistance(dim); int numelA = A.S.NumberOfElements; int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength, workerCount = 1; if (Settings.s_maxNumberThreads > 1 && maxRuns > 1 && numelA / 2 >= Settings.s_minParallelElement1Count) { if (maxRuns >= Settings.s_maxNumberThreads && numelA / Settings.s_maxNumberThreads > Settings.s_minParallelElement1Count) { workItemLength = maxRuns / workItemCount; } else { workItemLength = maxRuns / 2; workItemCount = 2; } } else { workItemLength = maxRuns; workItemCount = 1; } Action action = (data) => { Tuple range = (Tuple)data; int from = range.Item1, to = range.Item2; Int32[] tmpArr = ILMemoryPool.Pool.New< Int32>(dimLen); for (int c = from; c < to; c++) { int pos = (int)(((long)dimLen * c * inc) % modHelp); long posOut = ((long)c * incOut); if (posOut > modOut) posOut = ((posOut - 1) % modOut) + 1; int end = pos + dimLen * inc; int k = 0; // ho: TODO: probably faster if operating on a full clone of A. median_worker would handle LDA, start, end than ... for (int j = pos; j < end; j += inc) tmpArr[k++] = aArray[j]; retArr[posOut] = median_worker(tmpArr, dimLen); } ILMemoryPool.Pool.Free(tmpArr); System.Threading.Interlocked.Decrement(ref workerCount); }; for (; i < workItemCount - 1; i++) { Interlocked.Increment(ref workerCount); ILThreadPool.QueueUserWorkItem(i,action, Tuple.Create(i * workItemLength, (i + 1) * workItemLength)); } action(Tuple.Create(i * workItemLength, maxRuns)); ILThreadPool.Wait4Workers(ref workerCount); #endregion } return array(retArr, newDims); } } /// /// Calculate median along the specified dimension /// /// Input Array /// Array having the specified dimension reduced to the length 1 with the median of /// all elements along that dimension. /// [Optional] Index of dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1). /// The result will have the same number of dimensions as A, but the specified dimension will have the /// size 1.If the specified dimension of A is empty, the median along that dimension will be NaN and that dimension will be 1. public static ILRetArray median(ILInArray A, int dim = -1) { using (ILScope.Enter(A)) { if (dim < 0) dim = A.Size.WorkingDimension(); if (dim >= A.Size.NumberOfDimensions) return todouble(A.C); if (A.IsScalar) { return array(new double[] { A.GetValue(0) }, 1, 1); } if (A.S[dim] == 1) return todouble(A.C); int[] newDims = A.S.ToIntArray(); newDims[dim] = 1; ILSize retDimension = new ILSize(newDims); if (A.IsEmpty) return array(double.NaN,retDimension); double[] retArr = ILMemoryPool.Pool.New< double>(retDimension.NumberOfElements); int maxRuns = retDimension.NumberOfElements; byte[] aArray = null; if (maxRuns == 1) { // ho: easier would be to use a new local array: // ILArray aClone = A.C; // aArray = aClone.GetArrayForWrite(); here... (but the implemented way works just as well) aArray = ILMemoryPool.Pool.New< byte>(A.S[dim]); A.ExportValues(ref aArray); retArr[0] = median_worker(aArray, A.S[dim]); ILMemoryPool.Pool.Free(aArray); } else { #region may run parallel aArray = A.GetArrayForRead(); int inc = A.Size.SequentialIndexDistance(dim); int dimLen = A.Size[dim]; int modHelp = A.Size.NumberOfElements - 1; int modOut = retDimension.NumberOfElements - 1; int incOut = retDimension.SequentialIndexDistance(dim); int numelA = A.S.NumberOfElements; int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength, workerCount = 1; if (Settings.s_maxNumberThreads > 1 && maxRuns > 1 && numelA / 2 >= Settings.s_minParallelElement1Count) { if (maxRuns >= Settings.s_maxNumberThreads && numelA / Settings.s_maxNumberThreads > Settings.s_minParallelElement1Count) { workItemLength = maxRuns / workItemCount; } else { workItemLength = maxRuns / 2; workItemCount = 2; } } else { workItemLength = maxRuns; workItemCount = 1; } Action action = (data) => { Tuple range = (Tuple)data; int from = range.Item1, to = range.Item2; byte[] tmpArr = ILMemoryPool.Pool.New< byte>(dimLen); for (int c = from; c < to; c++) { int pos = (int)(((long)dimLen * c * inc) % modHelp); long posOut = ((long)c * incOut); if (posOut > modOut) posOut = ((posOut - 1) % modOut) + 1; int end = pos + dimLen * inc; int k = 0; // ho: TODO: probably faster if operating on a full clone of A. median_worker would handle LDA, start, end than ... for (int j = pos; j < end; j += inc) tmpArr[k++] = aArray[j]; retArr[posOut] = median_worker(tmpArr, dimLen); } ILMemoryPool.Pool.Free(tmpArr); System.Threading.Interlocked.Decrement(ref workerCount); }; for (; i < workItemCount - 1; i++) { Interlocked.Increment(ref workerCount); ILThreadPool.QueueUserWorkItem(i,action, Tuple.Create(i * workItemLength, (i + 1) * workItemLength)); } action(Tuple.Create(i * workItemLength, maxRuns)); ILThreadPool.Wait4Workers(ref workerCount); #endregion } return array(retArr, newDims); } } /// /// Calculate median along the specified dimension /// /// Input Array /// Array having the specified dimension reduced to the length 1 with the median of /// all elements along that dimension. /// [Optional] Index of dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1). /// The result will have the same number of dimensions as A, but the specified dimension will have the /// size 1.If the specified dimension of A is empty, the median along that dimension will be NaN and that dimension will be 1. public static ILRetArray median(ILInArray A, int dim = -1) { using (ILScope.Enter(A)) { if (dim < 0) dim = A.Size.WorkingDimension(); if (dim >= A.Size.NumberOfDimensions) return A.C; if (A.IsScalar) { return array(new fcomplex[] { A.GetValue(0) }, 1, 1); } if (A.S[dim] == 1) return A.C; int[] newDims = A.S.ToIntArray(); newDims[dim] = 1; ILSize retDimension = new ILSize(newDims); if (A.IsEmpty) return array(fcomplex.NaN,retDimension); fcomplex[] retArr = ILMemoryPool.Pool.New< fcomplex>(retDimension.NumberOfElements); int maxRuns = retDimension.NumberOfElements; fcomplex[] aArray = null; if (maxRuns == 1) { // ho: easier would be to use a new local array: // ILArray aClone = A.C; // aArray = aClone.GetArrayForWrite(); here... (but the implemented way works just as well) aArray = ILMemoryPool.Pool.New< fcomplex>(A.S[dim]); A.ExportValues(ref aArray); retArr[0] = median_worker(aArray, A.S[dim]); ILMemoryPool.Pool.Free(aArray); } else { #region may run parallel aArray = A.GetArrayForRead(); int inc = A.Size.SequentialIndexDistance(dim); int dimLen = A.Size[dim]; int modHelp = A.Size.NumberOfElements - 1; int modOut = retDimension.NumberOfElements - 1; int incOut = retDimension.SequentialIndexDistance(dim); int numelA = A.S.NumberOfElements; int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength, workerCount = 1; if (Settings.s_maxNumberThreads > 1 && maxRuns > 1 && numelA / 2 >= Settings.s_minParallelElement1Count) { if (maxRuns >= Settings.s_maxNumberThreads && numelA / Settings.s_maxNumberThreads > Settings.s_minParallelElement1Count) { workItemLength = maxRuns / workItemCount; } else { workItemLength = maxRuns / 2; workItemCount = 2; } } else { workItemLength = maxRuns; workItemCount = 1; } Action action = (data) => { Tuple range = (Tuple)data; int from = range.Item1, to = range.Item2; fcomplex[] tmpArr = ILMemoryPool.Pool.New< fcomplex>(dimLen); for (int c = from; c < to; c++) { int pos = (int)(((long)dimLen * c * inc) % modHelp); long posOut = ((long)c * incOut); if (posOut > modOut) posOut = ((posOut - 1) % modOut) + 1; int end = pos + dimLen * inc; int k = 0; // ho: TODO: probably faster if operating on a full clone of A. median_worker would handle LDA, start, end than ... for (int j = pos; j < end; j += inc) tmpArr[k++] = aArray[j]; retArr[posOut] = median_worker(tmpArr, dimLen); } ILMemoryPool.Pool.Free(tmpArr); System.Threading.Interlocked.Decrement(ref workerCount); }; for (; i < workItemCount - 1; i++) { Interlocked.Increment(ref workerCount); ILThreadPool.QueueUserWorkItem(i,action, Tuple.Create(i * workItemLength, (i + 1) * workItemLength)); } action(Tuple.Create(i * workItemLength, maxRuns)); ILThreadPool.Wait4Workers(ref workerCount); #endregion } return array(retArr, newDims); } } /// /// Calculate median along the specified dimension /// /// Input Array /// Array having the specified dimension reduced to the length 1 with the median of /// all elements along that dimension. /// [Optional] Index of dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1). /// The result will have the same number of dimensions as A, but the specified dimension will have the /// size 1.If the specified dimension of A is empty, the median along that dimension will be NaN and that dimension will be 1. public static ILRetArray median(ILInArray A, int dim = -1) { using (ILScope.Enter(A)) { if (dim < 0) dim = A.Size.WorkingDimension(); if (dim >= A.Size.NumberOfDimensions) return A.C; if (A.IsScalar) { return array(new float[] { A.GetValue(0) }, 1, 1); } if (A.S[dim] == 1) return A.C; int[] newDims = A.S.ToIntArray(); newDims[dim] = 1; ILSize retDimension = new ILSize(newDims); if (A.IsEmpty) return array(float.NaN,retDimension); float[] retArr = ILMemoryPool.Pool.New< float>(retDimension.NumberOfElements); int maxRuns = retDimension.NumberOfElements; float[] aArray = null; if (maxRuns == 1) { // ho: easier would be to use a new local array: // ILArray aClone = A.C; // aArray = aClone.GetArrayForWrite(); here... (but the implemented way works just as well) aArray = ILMemoryPool.Pool.New< float>(A.S[dim]); A.ExportValues(ref aArray); retArr[0] = median_worker(aArray, A.S[dim]); ILMemoryPool.Pool.Free(aArray); } else { #region may run parallel aArray = A.GetArrayForRead(); int inc = A.Size.SequentialIndexDistance(dim); int dimLen = A.Size[dim]; int modHelp = A.Size.NumberOfElements - 1; int modOut = retDimension.NumberOfElements - 1; int incOut = retDimension.SequentialIndexDistance(dim); int numelA = A.S.NumberOfElements; int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength, workerCount = 1; if (Settings.s_maxNumberThreads > 1 && maxRuns > 1 && numelA / 2 >= Settings.s_minParallelElement1Count) { if (maxRuns >= Settings.s_maxNumberThreads && numelA / Settings.s_maxNumberThreads > Settings.s_minParallelElement1Count) { workItemLength = maxRuns / workItemCount; } else { workItemLength = maxRuns / 2; workItemCount = 2; } } else { workItemLength = maxRuns; workItemCount = 1; } Action action = (data) => { Tuple range = (Tuple)data; int from = range.Item1, to = range.Item2; float[] tmpArr = ILMemoryPool.Pool.New< float>(dimLen); for (int c = from; c < to; c++) { int pos = (int)(((long)dimLen * c * inc) % modHelp); long posOut = ((long)c * incOut); if (posOut > modOut) posOut = ((posOut - 1) % modOut) + 1; int end = pos + dimLen * inc; int k = 0; // ho: TODO: probably faster if operating on a full clone of A. median_worker would handle LDA, start, end than ... for (int j = pos; j < end; j += inc) tmpArr[k++] = aArray[j]; retArr[posOut] = median_worker(tmpArr, dimLen); } ILMemoryPool.Pool.Free(tmpArr); System.Threading.Interlocked.Decrement(ref workerCount); }; for (; i < workItemCount - 1; i++) { Interlocked.Increment(ref workerCount); ILThreadPool.QueueUserWorkItem(i,action, Tuple.Create(i * workItemLength, (i + 1) * workItemLength)); } action(Tuple.Create(i * workItemLength, maxRuns)); ILThreadPool.Wait4Workers(ref workerCount); #endregion } return array(retArr, newDims); } } /// /// Calculate median along the specified dimension /// /// Input Array /// Array having the specified dimension reduced to the length 1 with the median of /// all elements along that dimension. /// [Optional] Index of dimension to operate along. If omitted operates along the first non singleton dimension (i.e. != 1). /// The result will have the same number of dimensions as A, but the specified dimension will have the /// size 1.If the specified dimension of A is empty, the median along that dimension will be NaN and that dimension will be 1. public static ILRetArray median(ILInArray A, int dim = -1) { using (ILScope.Enter(A)) { if (dim < 0) dim = A.Size.WorkingDimension(); if (dim >= A.Size.NumberOfDimensions) return A.C; if (A.IsScalar) { return array(new complex[] { A.GetValue(0) }, 1, 1); } if (A.S[dim] == 1) return A.C; int[] newDims = A.S.ToIntArray(); newDims[dim] = 1; ILSize retDimension = new ILSize(newDims); if (A.IsEmpty) return array(complex.NaN,retDimension); complex[] retArr = ILMemoryPool.Pool.New< complex>(retDimension.NumberOfElements); int maxRuns = retDimension.NumberOfElements; complex[] aArray = null; if (maxRuns == 1) { // ho: easier would be to use a new local array: // ILArray aClone = A.C; // aArray = aClone.GetArrayForWrite(); here... (but the implemented way works just as well) aArray = ILMemoryPool.Pool.New< complex>(A.S[dim]); A.ExportValues(ref aArray); retArr[0] = median_worker(aArray, A.S[dim]); ILMemoryPool.Pool.Free(aArray); } else { #region may run parallel aArray = A.GetArrayForRead(); int inc = A.Size.SequentialIndexDistance(dim); int dimLen = A.Size[dim]; int modHelp = A.Size.NumberOfElements - 1; int modOut = retDimension.NumberOfElements - 1; int incOut = retDimension.SequentialIndexDistance(dim); int numelA = A.S.NumberOfElements; int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength, workerCount = 1; if (Settings.s_maxNumberThreads > 1 && maxRuns > 1 && numelA / 2 >= Settings.s_minParallelElement1Count) { if (maxRuns >= Settings.s_maxNumberThreads && numelA / Settings.s_maxNumberThreads > Settings.s_minParallelElement1Count) { workItemLength = maxRuns / workItemCount; } else { workItemLength = maxRuns / 2; workItemCount = 2; } } else { workItemLength = maxRuns; workItemCount = 1; } Action action = (data) => { Tuple range = (Tuple)data; int from = range.Item1, to = range.Item2; complex[] tmpArr = ILMemoryPool.Pool.New< complex>(dimLen); for (int c = from; c < to; c++) { int pos = (int)(((long)dimLen * c * inc) % modHelp); long posOut = ((long)c * incOut); if (posOut > modOut) posOut = ((posOut - 1) % modOut) + 1; int end = pos + dimLen * inc; int k = 0; // ho: TODO: probably faster if operating on a full clone of A. median_worker would handle LDA, start, end than ... for (int j = pos; j < end; j += inc) tmpArr[k++] = aArray[j]; retArr[posOut] = median_worker(tmpArr, dimLen); } ILMemoryPool.Pool.Free(tmpArr); System.Threading.Interlocked.Decrement(ref workerCount); }; for (; i < workItemCount - 1; i++) { Interlocked.Increment(ref workerCount); ILThreadPool.QueueUserWorkItem(i,action, Tuple.Create(i * workItemLength, (i + 1) * workItemLength)); } action(Tuple.Create(i * workItemLength, maxRuns)); ILThreadPool.Wait4Workers(ref workerCount); #endregion } return array(retArr, newDims); } } #endregion HYCALPER AUTO GENERATED CODE #region private helpers static double median_worker(double[] list, int length) { // ATTENTION: list will be changed in here!!! if (length % 2 == 0) { // even number of elements int newRight; double a = (double)quickselect_worker(list, 0, length - 1, length / 2, out newRight); double b = (double)quickselect_worker(list, newRight + 1, length - 1, 1, out newRight); return b - (b - a) / (double) 2.0; // SMA: Reduces rounding errors...apparently. } else { // odd number of elements int dummy; return (double) quickselect_worker(list, 0, length - 1, (length - 1) / 2 + 1, out dummy); } } #region HYCALPER AUTO GENERATED CODE static double median_worker(Int64[] list, int length) { // ATTENTION: list will be changed in here!!! if (length % 2 == 0) { // even number of elements int newRight; double a = (double)quickselect_worker(list, 0, length - 1, length / 2, out newRight); double b = (double)quickselect_worker(list, newRight + 1, length - 1, 1, out newRight); return b - (b - a) / (double) 2.0; // SMA: Reduces rounding errors...apparently. } else { // odd number of elements int dummy; return (double) quickselect_worker(list, 0, length - 1, (length - 1) / 2 + 1, out dummy); } } static double median_worker(Int32[] list, int length) { // ATTENTION: list will be changed in here!!! if (length % 2 == 0) { // even number of elements int newRight; double a = (double)quickselect_worker(list, 0, length - 1, length / 2, out newRight); double b = (double)quickselect_worker(list, newRight + 1, length - 1, 1, out newRight); return b - (b - a) / (double) 2.0; // SMA: Reduces rounding errors...apparently. } else { // odd number of elements int dummy; return (double) quickselect_worker(list, 0, length - 1, (length - 1) / 2 + 1, out dummy); } } static double median_worker(byte[] list, int length) { // ATTENTION: list will be changed in here!!! if (length % 2 == 0) { // even number of elements int newRight; double a = (double)quickselect_worker(list, 0, length - 1, length / 2, out newRight); double b = (double)quickselect_worker(list, newRight + 1, length - 1, 1, out newRight); return b - (b - a) / (double) 2.0; // SMA: Reduces rounding errors...apparently. } else { // odd number of elements int dummy; return (double) quickselect_worker(list, 0, length - 1, (length - 1) / 2 + 1, out dummy); } } static fcomplex median_worker(fcomplex[] list, int length) { // ATTENTION: list will be changed in here!!! if (length % 2 == 0) { // even number of elements int newRight; fcomplex a = (fcomplex)quickselect_worker(list, 0, length - 1, length / 2, out newRight); fcomplex b = (fcomplex)quickselect_worker(list, newRight + 1, length - 1, 1, out newRight); return b - (b - a) / (fcomplex) 2.0; // SMA: Reduces rounding errors...apparently. } else { // odd number of elements int dummy; return (fcomplex) quickselect_worker(list, 0, length - 1, (length - 1) / 2 + 1, out dummy); } } static float median_worker(float[] list, int length) { // ATTENTION: list will be changed in here!!! if (length % 2 == 0) { // even number of elements int newRight; float a = (float)quickselect_worker(list, 0, length - 1, length / 2, out newRight); float b = (float)quickselect_worker(list, newRight + 1, length - 1, 1, out newRight); return b - (b - a) / (float) 2.0; // SMA: Reduces rounding errors...apparently. } else { // odd number of elements int dummy; return (float) quickselect_worker(list, 0, length - 1, (length - 1) / 2 + 1, out dummy); } } static complex median_worker(complex[] list, int length) { // ATTENTION: list will be changed in here!!! if (length % 2 == 0) { // even number of elements int newRight; complex a = (complex)quickselect_worker(list, 0, length - 1, length / 2, out newRight); complex b = (complex)quickselect_worker(list, newRight + 1, length - 1, 1, out newRight); return b - (b - a) / (complex) 2.0; // SMA: Reduces rounding errors...apparently. } else { // odd number of elements int dummy; return (complex) quickselect_worker(list, 0, length - 1, (length - 1) / 2 + 1, out dummy); } } #endregion HYCALPER AUTO GENERATED CODE #endregion } }