/// /// 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 ILNumerics; using ILNumerics.Misc; using ILNumerics.Storage; using ILNumerics.Native; using ILNumerics.Exceptions; namespace ILNumerics { public partial class ILMath { /// /// pairwise L1 distance /// /// input points (matrix) /// input point (vector) /// pairwise L1 distances between the data point provided in the input vector and the data points stored in the matrix . /// /// If is a colum vector, the distances between and the columns of are calculated. The number of rows of /// must match the length of vector than. Therefore, the length of the returned vector of distances matches the number of columns of : A.S[1]. /// If is a row vector, the distances between and the rows of are calculated. The number of columns of /// must match the length of vector than. Therefore, the length of the returned vector of distances matches the number of rows of : A.S[0]. /// This function is cummulative, the single data point may be provided in and the data point matrix may be provided in as well. /// public static unsafe ILRetArray distL1(ILInArray A, ILInArray B) { using (ILScope.Enter(A, B)) { #region parameter checking if (isnull(A) || isnull(B)) return empty(ILSize.Empty00); if (A.IsEmpty) { return empty(B.S); } else if (B.IsEmpty) { return empty(A.S); } // early exit: make the function cummutative if (A.IsVector && !B.IsVector) { return distL1(B, A); } int dim = -1; for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) { if (A.S[l] != B.S[l]) { if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) { throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B"); } dim = l; } } dim = -(dim - 1); // 0 -> 1, 1 -> 0 #endregion #region parameter preparation ILSize outDims; if (dim == 0) { outDims = size(1,A.S[1]); } else if (dim == 1) { outDims = size(A.S[0], 1); } else if (A.S.IsSameSize(B.S)) { outDims = A.S; dim = 0; } else throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors"); double[] retArr = ILMemoryPool.Pool.New(outDims.NumberOfElements); double[] arrA = A.GetArrayForRead(); double[] arrB = B.GetArrayForRead(); int itLen = A.S[0]; #endregion #region worker loops definition ILDenseStorage retStorage = new ILDenseStorage(retArr, outDims); int workerCount = 1; Action worker = data => { // expects: iStart, iLen, ap, bp, cp Tuple range = (Tuple)data; double* ap; double* bp; double* cp; if (dim == 0) { ap = (double*)range.Item2; cp = (double*)range.Item4; for (int s = 0; s < range.Item1; s++) { bp = (double*)range.Item3; double sum = 0; int l = itLen; while (l > 20) { sum += Math.Abs(ap[0] - bp[0]) + Math.Abs(ap[1] - bp[1]) + Math.Abs(ap[2] - bp[2]) + Math.Abs(ap[3] - bp[3]) + Math.Abs(ap[4] - bp[4]) + Math.Abs(ap[5] - bp[5]) + Math.Abs(ap[6] - bp[6]) + Math.Abs(ap[7] - bp[7]) + Math.Abs(ap[8] - bp[8]) + Math.Abs(ap[9] - bp[9]) + Math.Abs(ap[10] - bp[10]) + Math.Abs(ap[11] - bp[11]) + Math.Abs(ap[12] - bp[12]) + Math.Abs(ap[13] - bp[13]) + Math.Abs(ap[14] - bp[14]) + Math.Abs(ap[15] - bp[15]) + Math.Abs(ap[16] - bp[16]) + Math.Abs(ap[17] - bp[17]) + Math.Abs(ap[18] - bp[18]) + Math.Abs(ap[19] - bp[19]) + Math.Abs(ap[20] - bp[20]); ap += 21; bp += 21; l -= 21; } while (l-- > 0) { sum += Math.Abs(*ap - *bp); ap++; bp++; } *cp++ = sum; } } else { // dim = 1 ap = (double*)range.Item2; bp = (double*)range.Item3; cp = (double*)range.Item4; for (int s = 0; s < range.Item1; s++) { // TODO: further potential speedup: unroll in s direction! double val = *bp++; int l = itLen; while (l > 10) { cp[0] += Math.Abs(ap[0] - val); cp[1] += Math.Abs(ap[1] - val); cp[2] += Math.Abs(ap[2] - val); cp[3] += Math.Abs(ap[3] - val); cp[4] += Math.Abs(ap[4] - val); cp[5] += Math.Abs(ap[5] - val); cp[6] += Math.Abs(ap[6] - val); cp[7] += Math.Abs(ap[7] - val); cp[8] += Math.Abs(ap[8] - val); cp[9] += Math.Abs(ap[9] - val); cp[10] += Math.Abs(ap[10] - val); cp[11] += Math.Abs(ap[11] - val); cp[12] += Math.Abs(ap[12] - val); cp[13] += Math.Abs(ap[13] - val); cp[14] += Math.Abs(ap[14] - val); cp[15] += Math.Abs(ap[15] - val); cp[16] += Math.Abs(ap[16] - val); cp[17] += Math.Abs(ap[17] - val); cp[18] += Math.Abs(ap[18] - val); cp[19] += Math.Abs(ap[19] - val); cp[20] += Math.Abs(ap[20] - val); ap += 21; cp += 21; l -= 21; } while (l-- > 0) { *cp += Math.Abs(*ap - val); ap++; cp++; } } } System.Threading.Interlocked.Decrement(ref workerCount); }; #endregion #region work distribution int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength; if (Settings.s_maxNumberThreads > 1 && outDims.NumberOfElements >= Settings.s_minParallelElement1Count && outDims[1] > 1) { if (outDims[1] > workItemCount) { workItemLength = outDims[1] / workItemCount; } else { workItemLength = outDims[1] / 2; workItemCount = 2; } } else { workItemLength = outDims[1]; workItemCount = 1; } //int[] partResults = new int[workItemCount]; fixed ( double* arrAP = arrA) fixed ( double* arrBP = arrB) fixed ( double* retArrP = retArr) { for (; i < workItemCount - 1; i++) { Tuple range = new Tuple (workItemLength , (IntPtr)(arrAP + i * outDims[0] * workItemLength) , (IntPtr)(arrBP + i * dim * workItemLength) , (IntPtr)(retArrP + i * workItemLength)); System.Threading.Interlocked.Increment(ref workerCount); ILThreadPool.QueueUserWorkItem(i, worker, range); } // the last (or may the only) chunk is done right here //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks); worker(new Tuple (outDims[1] - i * workItemLength , (IntPtr)(arrAP + i * outDims[0] * workItemLength) , (IntPtr)(arrBP + i * dim * workItemLength) , (IntPtr)(retArrP + i * workItemLength))); ILThreadPool.Wait4Workers(ref workerCount); } #endregion return new ILRetArray(retStorage); } } #region HYCALPER AUTO GENERATED CODE /// /// pairwise L1 distance /// /// input points (matrix) /// input point (vector) /// pairwise L1 distances between the data point provided in the input vector and the data points stored in the matrix . /// /// If is a colum vector, the distances between and the columns of are calculated. The number of rows of /// must match the length of vector than. Therefore, the length of the returned vector of distances matches the number of columns of : A.S[1]. /// If is a row vector, the distances between and the rows of are calculated. The number of columns of /// must match the length of vector than. Therefore, the length of the returned vector of distances matches the number of rows of : A.S[0]. /// This function is cummulative, the single data point may be provided in and the data point matrix may be provided in as well. /// public static unsafe ILRetArray distL1(ILInArray A, ILInArray B) { using (ILScope.Enter(A, B)) { #region parameter checking if (isnull(A) || isnull(B)) return empty(ILSize.Empty00); if (A.IsEmpty) { return empty(B.S); } else if (B.IsEmpty) { return empty(A.S); } // early exit: make the function cummutative if (A.IsVector && !B.IsVector) { return distL1(B, A); } int dim = -1; for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) { if (A.S[l] != B.S[l]) { if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) { throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B"); } dim = l; } } dim = -(dim - 1); // 0 -> 1, 1 -> 0 #endregion #region parameter preparation ILSize outDims; if (dim == 0) { outDims = size(1,A.S[1]); } else if (dim == 1) { outDims = size(A.S[0], 1); } else if (A.S.IsSameSize(B.S)) { outDims = A.S; dim = 0; } else throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors"); Int64[] retArr = ILMemoryPool.Pool.New(outDims.NumberOfElements); Int64[] arrA = A.GetArrayForRead(); Int64[] arrB = B.GetArrayForRead(); int itLen = A.S[0]; #endregion #region worker loops definition ILDenseStorage retStorage = new ILDenseStorage(retArr, outDims); int workerCount = 1; Action worker = data => { // expects: iStart, iLen, ap, bp, cp Tuple range = (Tuple)data; Int64* ap; Int64* bp; Int64* cp; if (dim == 0) { ap = (Int64*)range.Item2; cp = (Int64*)range.Item4; for (int s = 0; s < range.Item1; s++) { bp = (Int64*)range.Item3; Int64 sum = 0; int l = itLen; while (l > 20) { sum += Math.Abs(ap[0] - bp[0]) + Math.Abs(ap[1] - bp[1]) + Math.Abs(ap[2] - bp[2]) + Math.Abs(ap[3] - bp[3]) + Math.Abs(ap[4] - bp[4]) + Math.Abs(ap[5] - bp[5]) + Math.Abs(ap[6] - bp[6]) + Math.Abs(ap[7] - bp[7]) + Math.Abs(ap[8] - bp[8]) + Math.Abs(ap[9] - bp[9]) + Math.Abs(ap[10] - bp[10]) + Math.Abs(ap[11] - bp[11]) + Math.Abs(ap[12] - bp[12]) + Math.Abs(ap[13] - bp[13]) + Math.Abs(ap[14] - bp[14]) + Math.Abs(ap[15] - bp[15]) + Math.Abs(ap[16] - bp[16]) + Math.Abs(ap[17] - bp[17]) + Math.Abs(ap[18] - bp[18]) + Math.Abs(ap[19] - bp[19]) + Math.Abs(ap[20] - bp[20]); ap += 21; bp += 21; l -= 21; } while (l-- > 0) { sum += Math.Abs(*ap - *bp); ap++; bp++; } *cp++ = sum; } } else { // dim = 1 ap = (Int64*)range.Item2; bp = (Int64*)range.Item3; cp = (Int64*)range.Item4; for (int s = 0; s < range.Item1; s++) { // TODO: further potential speedup: unroll in s direction! Int64 val = *bp++; int l = itLen; while (l > 10) { cp[0] += Math.Abs(ap[0] - val); cp[1] += Math.Abs(ap[1] - val); cp[2] += Math.Abs(ap[2] - val); cp[3] += Math.Abs(ap[3] - val); cp[4] += Math.Abs(ap[4] - val); cp[5] += Math.Abs(ap[5] - val); cp[6] += Math.Abs(ap[6] - val); cp[7] += Math.Abs(ap[7] - val); cp[8] += Math.Abs(ap[8] - val); cp[9] += Math.Abs(ap[9] - val); cp[10] += Math.Abs(ap[10] - val); cp[11] += Math.Abs(ap[11] - val); cp[12] += Math.Abs(ap[12] - val); cp[13] += Math.Abs(ap[13] - val); cp[14] += Math.Abs(ap[14] - val); cp[15] += Math.Abs(ap[15] - val); cp[16] += Math.Abs(ap[16] - val); cp[17] += Math.Abs(ap[17] - val); cp[18] += Math.Abs(ap[18] - val); cp[19] += Math.Abs(ap[19] - val); cp[20] += Math.Abs(ap[20] - val); ap += 21; cp += 21; l -= 21; } while (l-- > 0) { *cp += Math.Abs(*ap - val); ap++; cp++; } } } System.Threading.Interlocked.Decrement(ref workerCount); }; #endregion #region work distribution int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength; if (Settings.s_maxNumberThreads > 1 && outDims.NumberOfElements >= Settings.s_minParallelElement1Count && outDims[1] > 1) { if (outDims[1] > workItemCount) { workItemLength = outDims[1] / workItemCount; } else { workItemLength = outDims[1] / 2; workItemCount = 2; } } else { workItemLength = outDims[1]; workItemCount = 1; } //int[] partResults = new int[workItemCount]; fixed ( Int64* arrAP = arrA) fixed ( Int64* arrBP = arrB) fixed ( Int64* retArrP = retArr) { for (; i < workItemCount - 1; i++) { Tuple range = new Tuple (workItemLength , (IntPtr)(arrAP + i * outDims[0] * workItemLength) , (IntPtr)(arrBP + i * dim * workItemLength) , (IntPtr)(retArrP + i * workItemLength)); System.Threading.Interlocked.Increment(ref workerCount); ILThreadPool.QueueUserWorkItem(i, worker, range); } // the last (or may the only) chunk is done right here //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks); worker(new Tuple (outDims[1] - i * workItemLength , (IntPtr)(arrAP + i * outDims[0] * workItemLength) , (IntPtr)(arrBP + i * dim * workItemLength) , (IntPtr)(retArrP + i * workItemLength))); ILThreadPool.Wait4Workers(ref workerCount); } #endregion return new ILRetArray(retStorage); } } /// /// pairwise L1 distance /// /// input points (matrix) /// input point (vector) /// pairwise L1 distances between the data point provided in the input vector and the data points stored in the matrix . /// /// If is a colum vector, the distances between and the columns of are calculated. The number of rows of /// must match the length of vector than. Therefore, the length of the returned vector of distances matches the number of columns of : A.S[1]. /// If is a row vector, the distances between and the rows of are calculated. The number of columns of /// must match the length of vector than. Therefore, the length of the returned vector of distances matches the number of rows of : A.S[0]. /// This function is cummulative, the single data point may be provided in and the data point matrix may be provided in as well. /// public static unsafe ILRetArray distL1(ILInArray A, ILInArray B) { using (ILScope.Enter(A, B)) { #region parameter checking if (isnull(A) || isnull(B)) return empty(ILSize.Empty00); if (A.IsEmpty) { return empty(B.S); } else if (B.IsEmpty) { return empty(A.S); } // early exit: make the function cummutative if (A.IsVector && !B.IsVector) { return distL1(B, A); } int dim = -1; for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) { if (A.S[l] != B.S[l]) { if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) { throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B"); } dim = l; } } dim = -(dim - 1); // 0 -> 1, 1 -> 0 #endregion #region parameter preparation ILSize outDims; if (dim == 0) { outDims = size(1,A.S[1]); } else if (dim == 1) { outDims = size(A.S[0], 1); } else if (A.S.IsSameSize(B.S)) { outDims = A.S; dim = 0; } else throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors"); Int32[] retArr = ILMemoryPool.Pool.New(outDims.NumberOfElements); Int32[] arrA = A.GetArrayForRead(); Int32[] arrB = B.GetArrayForRead(); int itLen = A.S[0]; #endregion #region worker loops definition ILDenseStorage retStorage = new ILDenseStorage(retArr, outDims); int workerCount = 1; Action worker = data => { // expects: iStart, iLen, ap, bp, cp Tuple range = (Tuple)data; Int32* ap; Int32* bp; Int32* cp; if (dim == 0) { ap = (Int32*)range.Item2; cp = (Int32*)range.Item4; for (int s = 0; s < range.Item1; s++) { bp = (Int32*)range.Item3; Int32 sum = 0; int l = itLen; while (l > 20) { sum += Math.Abs(ap[0] - bp[0]) + Math.Abs(ap[1] - bp[1]) + Math.Abs(ap[2] - bp[2]) + Math.Abs(ap[3] - bp[3]) + Math.Abs(ap[4] - bp[4]) + Math.Abs(ap[5] - bp[5]) + Math.Abs(ap[6] - bp[6]) + Math.Abs(ap[7] - bp[7]) + Math.Abs(ap[8] - bp[8]) + Math.Abs(ap[9] - bp[9]) + Math.Abs(ap[10] - bp[10]) + Math.Abs(ap[11] - bp[11]) + Math.Abs(ap[12] - bp[12]) + Math.Abs(ap[13] - bp[13]) + Math.Abs(ap[14] - bp[14]) + Math.Abs(ap[15] - bp[15]) + Math.Abs(ap[16] - bp[16]) + Math.Abs(ap[17] - bp[17]) + Math.Abs(ap[18] - bp[18]) + Math.Abs(ap[19] - bp[19]) + Math.Abs(ap[20] - bp[20]); ap += 21; bp += 21; l -= 21; } while (l-- > 0) { sum += Math.Abs(*ap - *bp); ap++; bp++; } *cp++ = sum; } } else { // dim = 1 ap = (Int32*)range.Item2; bp = (Int32*)range.Item3; cp = (Int32*)range.Item4; for (int s = 0; s < range.Item1; s++) { // TODO: further potential speedup: unroll in s direction! Int32 val = *bp++; int l = itLen; while (l > 10) { cp[0] += Math.Abs(ap[0] - val); cp[1] += Math.Abs(ap[1] - val); cp[2] += Math.Abs(ap[2] - val); cp[3] += Math.Abs(ap[3] - val); cp[4] += Math.Abs(ap[4] - val); cp[5] += Math.Abs(ap[5] - val); cp[6] += Math.Abs(ap[6] - val); cp[7] += Math.Abs(ap[7] - val); cp[8] += Math.Abs(ap[8] - val); cp[9] += Math.Abs(ap[9] - val); cp[10] += Math.Abs(ap[10] - val); cp[11] += Math.Abs(ap[11] - val); cp[12] += Math.Abs(ap[12] - val); cp[13] += Math.Abs(ap[13] - val); cp[14] += Math.Abs(ap[14] - val); cp[15] += Math.Abs(ap[15] - val); cp[16] += Math.Abs(ap[16] - val); cp[17] += Math.Abs(ap[17] - val); cp[18] += Math.Abs(ap[18] - val); cp[19] += Math.Abs(ap[19] - val); cp[20] += Math.Abs(ap[20] - val); ap += 21; cp += 21; l -= 21; } while (l-- > 0) { *cp += Math.Abs(*ap - val); ap++; cp++; } } } System.Threading.Interlocked.Decrement(ref workerCount); }; #endregion #region work distribution int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength; if (Settings.s_maxNumberThreads > 1 && outDims.NumberOfElements >= Settings.s_minParallelElement1Count && outDims[1] > 1) { if (outDims[1] > workItemCount) { workItemLength = outDims[1] / workItemCount; } else { workItemLength = outDims[1] / 2; workItemCount = 2; } } else { workItemLength = outDims[1]; workItemCount = 1; } //int[] partResults = new int[workItemCount]; fixed ( Int32* arrAP = arrA) fixed ( Int32* arrBP = arrB) fixed ( Int32* retArrP = retArr) { for (; i < workItemCount - 1; i++) { Tuple range = new Tuple (workItemLength , (IntPtr)(arrAP + i * outDims[0] * workItemLength) , (IntPtr)(arrBP + i * dim * workItemLength) , (IntPtr)(retArrP + i * workItemLength)); System.Threading.Interlocked.Increment(ref workerCount); ILThreadPool.QueueUserWorkItem(i, worker, range); } // the last (or may the only) chunk is done right here //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks); worker(new Tuple (outDims[1] - i * workItemLength , (IntPtr)(arrAP + i * outDims[0] * workItemLength) , (IntPtr)(arrBP + i * dim * workItemLength) , (IntPtr)(retArrP + i * workItemLength))); ILThreadPool.Wait4Workers(ref workerCount); } #endregion return new ILRetArray(retStorage); } } /// /// pairwise L1 distance /// /// input points (matrix) /// input point (vector) /// pairwise L1 distances between the data point provided in the input vector and the data points stored in the matrix . /// /// If is a colum vector, the distances between and the columns of are calculated. The number of rows of /// must match the length of vector than. Therefore, the length of the returned vector of distances matches the number of columns of : A.S[1]. /// If is a row vector, the distances between and the rows of are calculated. The number of columns of /// must match the length of vector than. Therefore, the length of the returned vector of distances matches the number of rows of : A.S[0]. /// This function is cummulative, the single data point may be provided in and the data point matrix may be provided in as well. /// public static unsafe ILRetArray distL1(ILInArray A, ILInArray B) { using (ILScope.Enter(A, B)) { #region parameter checking if (isnull(A) || isnull(B)) return empty(ILSize.Empty00); if (A.IsEmpty) { return empty(B.S); } else if (B.IsEmpty) { return empty(A.S); } // early exit: make the function cummutative if (A.IsVector && !B.IsVector) { return distL1(B, A); } int dim = -1; for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) { if (A.S[l] != B.S[l]) { if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) { throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B"); } dim = l; } } dim = -(dim - 1); // 0 -> 1, 1 -> 0 #endregion #region parameter preparation ILSize outDims; if (dim == 0) { outDims = size(1,A.S[1]); } else if (dim == 1) { outDims = size(A.S[0], 1); } else if (A.S.IsSameSize(B.S)) { outDims = A.S; dim = 0; } else throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors"); float[] retArr = ILMemoryPool.Pool.New(outDims.NumberOfElements); float[] arrA = A.GetArrayForRead(); float[] arrB = B.GetArrayForRead(); int itLen = A.S[0]; #endregion #region worker loops definition ILDenseStorage retStorage = new ILDenseStorage(retArr, outDims); int workerCount = 1; Action worker = data => { // expects: iStart, iLen, ap, bp, cp Tuple range = (Tuple)data; float* ap; float* bp; float* cp; if (dim == 0) { ap = (float*)range.Item2; cp = (float*)range.Item4; for (int s = 0; s < range.Item1; s++) { bp = (float*)range.Item3; float sum = 0; int l = itLen; while (l > 20) { sum += Math.Abs(ap[0] - bp[0]) + Math.Abs(ap[1] - bp[1]) + Math.Abs(ap[2] - bp[2]) + Math.Abs(ap[3] - bp[3]) + Math.Abs(ap[4] - bp[4]) + Math.Abs(ap[5] - bp[5]) + Math.Abs(ap[6] - bp[6]) + Math.Abs(ap[7] - bp[7]) + Math.Abs(ap[8] - bp[8]) + Math.Abs(ap[9] - bp[9]) + Math.Abs(ap[10] - bp[10]) + Math.Abs(ap[11] - bp[11]) + Math.Abs(ap[12] - bp[12]) + Math.Abs(ap[13] - bp[13]) + Math.Abs(ap[14] - bp[14]) + Math.Abs(ap[15] - bp[15]) + Math.Abs(ap[16] - bp[16]) + Math.Abs(ap[17] - bp[17]) + Math.Abs(ap[18] - bp[18]) + Math.Abs(ap[19] - bp[19]) + Math.Abs(ap[20] - bp[20]); ap += 21; bp += 21; l -= 21; } while (l-- > 0) { sum += Math.Abs(*ap - *bp); ap++; bp++; } *cp++ = sum; } } else { // dim = 1 ap = (float*)range.Item2; bp = (float*)range.Item3; cp = (float*)range.Item4; for (int s = 0; s < range.Item1; s++) { // TODO: further potential speedup: unroll in s direction! float val = *bp++; int l = itLen; while (l > 10) { cp[0] += Math.Abs(ap[0] - val); cp[1] += Math.Abs(ap[1] - val); cp[2] += Math.Abs(ap[2] - val); cp[3] += Math.Abs(ap[3] - val); cp[4] += Math.Abs(ap[4] - val); cp[5] += Math.Abs(ap[5] - val); cp[6] += Math.Abs(ap[6] - val); cp[7] += Math.Abs(ap[7] - val); cp[8] += Math.Abs(ap[8] - val); cp[9] += Math.Abs(ap[9] - val); cp[10] += Math.Abs(ap[10] - val); cp[11] += Math.Abs(ap[11] - val); cp[12] += Math.Abs(ap[12] - val); cp[13] += Math.Abs(ap[13] - val); cp[14] += Math.Abs(ap[14] - val); cp[15] += Math.Abs(ap[15] - val); cp[16] += Math.Abs(ap[16] - val); cp[17] += Math.Abs(ap[17] - val); cp[18] += Math.Abs(ap[18] - val); cp[19] += Math.Abs(ap[19] - val); cp[20] += Math.Abs(ap[20] - val); ap += 21; cp += 21; l -= 21; } while (l-- > 0) { *cp += Math.Abs(*ap - val); ap++; cp++; } } } System.Threading.Interlocked.Decrement(ref workerCount); }; #endregion #region work distribution int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength; if (Settings.s_maxNumberThreads > 1 && outDims.NumberOfElements >= Settings.s_minParallelElement1Count && outDims[1] > 1) { if (outDims[1] > workItemCount) { workItemLength = outDims[1] / workItemCount; } else { workItemLength = outDims[1] / 2; workItemCount = 2; } } else { workItemLength = outDims[1]; workItemCount = 1; } //int[] partResults = new int[workItemCount]; fixed ( float* arrAP = arrA) fixed ( float* arrBP = arrB) fixed ( float* retArrP = retArr) { for (; i < workItemCount - 1; i++) { Tuple range = new Tuple (workItemLength , (IntPtr)(arrAP + i * outDims[0] * workItemLength) , (IntPtr)(arrBP + i * dim * workItemLength) , (IntPtr)(retArrP + i * workItemLength)); System.Threading.Interlocked.Increment(ref workerCount); ILThreadPool.QueueUserWorkItem(i, worker, range); } // the last (or may the only) chunk is done right here //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks); worker(new Tuple (outDims[1] - i * workItemLength , (IntPtr)(arrAP + i * outDims[0] * workItemLength) , (IntPtr)(arrBP + i * dim * workItemLength) , (IntPtr)(retArrP + i * workItemLength))); ILThreadPool.Wait4Workers(ref workerCount); } #endregion return new ILRetArray(retStorage); } } /// /// pairwise L1 distance /// /// input points (matrix) /// input point (vector) /// pairwise L1 distances between the data point provided in the input vector and the data points stored in the matrix . /// /// If is a colum vector, the distances between and the columns of are calculated. The number of rows of /// must match the length of vector than. Therefore, the length of the returned vector of distances matches the number of columns of : A.S[1]. /// If is a row vector, the distances between and the rows of are calculated. The number of columns of /// must match the length of vector than. Therefore, the length of the returned vector of distances matches the number of rows of : A.S[0]. /// This function is cummulative, the single data point may be provided in and the data point matrix may be provided in as well. /// public static unsafe ILRetArray distL1(ILInArray A, ILInArray B) { using (ILScope.Enter(A, B)) { #region parameter checking if (isnull(A) || isnull(B)) return empty(ILSize.Empty00); if (A.IsEmpty) { return empty(B.S); } else if (B.IsEmpty) { return empty(A.S); } // early exit: make the function cummutative if (A.IsVector && !B.IsVector) { return distL1(B, A); } int dim = -1; for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) { if (A.S[l] != B.S[l]) { if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) { throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B"); } dim = l; } } dim = -(dim - 1); // 0 -> 1, 1 -> 0 #endregion #region parameter preparation ILSize outDims; if (dim == 0) { outDims = size(1,A.S[1]); } else if (dim == 1) { outDims = size(A.S[0], 1); } else if (A.S.IsSameSize(B.S)) { outDims = A.S; dim = 0; } else throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors"); fcomplex[] retArr = ILMemoryPool.Pool.New(outDims.NumberOfElements); fcomplex[] arrA = A.GetArrayForRead(); fcomplex[] arrB = B.GetArrayForRead(); int itLen = A.S[0]; #endregion #region worker loops definition ILDenseStorage retStorage = new ILDenseStorage(retArr, outDims); int workerCount = 1; Action worker = data => { // expects: iStart, iLen, ap, bp, cp Tuple range = (Tuple)data; fcomplex* ap; fcomplex* bp; fcomplex* cp; if (dim == 0) { ap = (fcomplex*)range.Item2; cp = (fcomplex*)range.Item4; for (int s = 0; s < range.Item1; s++) { bp = (fcomplex*)range.Item3; fcomplex sum = 0; int l = itLen; while (l > 20) { sum += fcomplex.Abs(ap[0] - bp[0]) + fcomplex.Abs(ap[1] - bp[1]) + fcomplex.Abs(ap[2] - bp[2]) + fcomplex.Abs(ap[3] - bp[3]) + fcomplex.Abs(ap[4] - bp[4]) + fcomplex.Abs(ap[5] - bp[5]) + fcomplex.Abs(ap[6] - bp[6]) + fcomplex.Abs(ap[7] - bp[7]) + fcomplex.Abs(ap[8] - bp[8]) + fcomplex.Abs(ap[9] - bp[9]) + fcomplex.Abs(ap[10] - bp[10]) + fcomplex.Abs(ap[11] - bp[11]) + fcomplex.Abs(ap[12] - bp[12]) + fcomplex.Abs(ap[13] - bp[13]) + fcomplex.Abs(ap[14] - bp[14]) + fcomplex.Abs(ap[15] - bp[15]) + fcomplex.Abs(ap[16] - bp[16]) + fcomplex.Abs(ap[17] - bp[17]) + fcomplex.Abs(ap[18] - bp[18]) + fcomplex.Abs(ap[19] - bp[19]) + fcomplex.Abs(ap[20] - bp[20]); ap += 21; bp += 21; l -= 21; } while (l-- > 0) { sum += fcomplex.Abs(*ap - *bp); ap++; bp++; } *cp++ = sum; } } else { // dim = 1 ap = (fcomplex*)range.Item2; bp = (fcomplex*)range.Item3; cp = (fcomplex*)range.Item4; for (int s = 0; s < range.Item1; s++) { // TODO: further potential speedup: unroll in s direction! fcomplex val = *bp++; int l = itLen; while (l > 10) { cp[0] += fcomplex.Abs(ap[0] - val); cp[1] += fcomplex.Abs(ap[1] - val); cp[2] += fcomplex.Abs(ap[2] - val); cp[3] += fcomplex.Abs(ap[3] - val); cp[4] += fcomplex.Abs(ap[4] - val); cp[5] += fcomplex.Abs(ap[5] - val); cp[6] += fcomplex.Abs(ap[6] - val); cp[7] += fcomplex.Abs(ap[7] - val); cp[8] += fcomplex.Abs(ap[8] - val); cp[9] += fcomplex.Abs(ap[9] - val); cp[10] += fcomplex.Abs(ap[10] - val); cp[11] += fcomplex.Abs(ap[11] - val); cp[12] += fcomplex.Abs(ap[12] - val); cp[13] += fcomplex.Abs(ap[13] - val); cp[14] += fcomplex.Abs(ap[14] - val); cp[15] += fcomplex.Abs(ap[15] - val); cp[16] += fcomplex.Abs(ap[16] - val); cp[17] += fcomplex.Abs(ap[17] - val); cp[18] += fcomplex.Abs(ap[18] - val); cp[19] += fcomplex.Abs(ap[19] - val); cp[20] += fcomplex.Abs(ap[20] - val); ap += 21; cp += 21; l -= 21; } while (l-- > 0) { *cp += fcomplex.Abs(*ap - val); ap++; cp++; } } } System.Threading.Interlocked.Decrement(ref workerCount); }; #endregion #region work distribution int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength; if (Settings.s_maxNumberThreads > 1 && outDims.NumberOfElements >= Settings.s_minParallelElement1Count && outDims[1] > 1) { if (outDims[1] > workItemCount) { workItemLength = outDims[1] / workItemCount; } else { workItemLength = outDims[1] / 2; workItemCount = 2; } } else { workItemLength = outDims[1]; workItemCount = 1; } //int[] partResults = new int[workItemCount]; fixed ( fcomplex* arrAP = arrA) fixed ( fcomplex* arrBP = arrB) fixed ( fcomplex* retArrP = retArr) { for (; i < workItemCount - 1; i++) { Tuple range = new Tuple (workItemLength , (IntPtr)(arrAP + i * outDims[0] * workItemLength) , (IntPtr)(arrBP + i * dim * workItemLength) , (IntPtr)(retArrP + i * workItemLength)); System.Threading.Interlocked.Increment(ref workerCount); ILThreadPool.QueueUserWorkItem(i, worker, range); } // the last (or may the only) chunk is done right here //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks); worker(new Tuple (outDims[1] - i * workItemLength , (IntPtr)(arrAP + i * outDims[0] * workItemLength) , (IntPtr)(arrBP + i * dim * workItemLength) , (IntPtr)(retArrP + i * workItemLength))); ILThreadPool.Wait4Workers(ref workerCount); } #endregion return new ILRetArray(retStorage); } } /// /// pairwise L1 distance /// /// input points (matrix) /// input point (vector) /// pairwise L1 distances between the data point provided in the input vector and the data points stored in the matrix . /// /// If is a colum vector, the distances between and the columns of are calculated. The number of rows of /// must match the length of vector than. Therefore, the length of the returned vector of distances matches the number of columns of : A.S[1]. /// If is a row vector, the distances between and the rows of are calculated. The number of columns of /// must match the length of vector than. Therefore, the length of the returned vector of distances matches the number of rows of : A.S[0]. /// This function is cummulative, the single data point may be provided in and the data point matrix may be provided in as well. /// public static unsafe ILRetArray distL1(ILInArray A, ILInArray B) { using (ILScope.Enter(A, B)) { #region parameter checking if (isnull(A) || isnull(B)) return empty(ILSize.Empty00); if (A.IsEmpty) { return empty(B.S); } else if (B.IsEmpty) { return empty(A.S); } // early exit: make the function cummutative if (A.IsVector && !B.IsVector) { return distL1(B, A); } int dim = -1; for (int l = 0; l < Math.Max(A.S.NumberOfDimensions, B.S.NumberOfDimensions); l++) { if (A.S[l] != B.S[l]) { if (dim >= 0 || (A.S[l] != 1 && B.S[l] != 1)) { throw new ILArgumentException("A and B must have the same size except for one simgleton dimension in A or B"); } dim = l; } } dim = -(dim - 1); // 0 -> 1, 1 -> 0 #endregion #region parameter preparation ILSize outDims; if (dim == 0) { outDims = size(1,A.S[1]); } else if (dim == 1) { outDims = size(A.S[0], 1); } else if (A.S.IsSameSize(B.S)) { outDims = A.S; dim = 0; } else throw new ILArgumentException("singleton dimension expansion currently is only supported for colum- and row vectors"); complex[] retArr = ILMemoryPool.Pool.New(outDims.NumberOfElements); complex[] arrA = A.GetArrayForRead(); complex[] arrB = B.GetArrayForRead(); int itLen = A.S[0]; #endregion #region worker loops definition ILDenseStorage retStorage = new ILDenseStorage(retArr, outDims); int workerCount = 1; Action worker = data => { // expects: iStart, iLen, ap, bp, cp Tuple range = (Tuple)data; complex* ap; complex* bp; complex* cp; if (dim == 0) { ap = (complex*)range.Item2; cp = (complex*)range.Item4; for (int s = 0; s < range.Item1; s++) { bp = (complex*)range.Item3; complex sum = 0; int l = itLen; while (l > 20) { sum += complex.Abs(ap[0] - bp[0]) + complex.Abs(ap[1] - bp[1]) + complex.Abs(ap[2] - bp[2]) + complex.Abs(ap[3] - bp[3]) + complex.Abs(ap[4] - bp[4]) + complex.Abs(ap[5] - bp[5]) + complex.Abs(ap[6] - bp[6]) + complex.Abs(ap[7] - bp[7]) + complex.Abs(ap[8] - bp[8]) + complex.Abs(ap[9] - bp[9]) + complex.Abs(ap[10] - bp[10]) + complex.Abs(ap[11] - bp[11]) + complex.Abs(ap[12] - bp[12]) + complex.Abs(ap[13] - bp[13]) + complex.Abs(ap[14] - bp[14]) + complex.Abs(ap[15] - bp[15]) + complex.Abs(ap[16] - bp[16]) + complex.Abs(ap[17] - bp[17]) + complex.Abs(ap[18] - bp[18]) + complex.Abs(ap[19] - bp[19]) + complex.Abs(ap[20] - bp[20]); ap += 21; bp += 21; l -= 21; } while (l-- > 0) { sum += complex.Abs(*ap - *bp); ap++; bp++; } *cp++ = sum; } } else { // dim = 1 ap = (complex*)range.Item2; bp = (complex*)range.Item3; cp = (complex*)range.Item4; for (int s = 0; s < range.Item1; s++) { // TODO: further potential speedup: unroll in s direction! complex val = *bp++; int l = itLen; while (l > 10) { cp[0] += complex.Abs(ap[0] - val); cp[1] += complex.Abs(ap[1] - val); cp[2] += complex.Abs(ap[2] - val); cp[3] += complex.Abs(ap[3] - val); cp[4] += complex.Abs(ap[4] - val); cp[5] += complex.Abs(ap[5] - val); cp[6] += complex.Abs(ap[6] - val); cp[7] += complex.Abs(ap[7] - val); cp[8] += complex.Abs(ap[8] - val); cp[9] += complex.Abs(ap[9] - val); cp[10] += complex.Abs(ap[10] - val); cp[11] += complex.Abs(ap[11] - val); cp[12] += complex.Abs(ap[12] - val); cp[13] += complex.Abs(ap[13] - val); cp[14] += complex.Abs(ap[14] - val); cp[15] += complex.Abs(ap[15] - val); cp[16] += complex.Abs(ap[16] - val); cp[17] += complex.Abs(ap[17] - val); cp[18] += complex.Abs(ap[18] - val); cp[19] += complex.Abs(ap[19] - val); cp[20] += complex.Abs(ap[20] - val); ap += 21; cp += 21; l -= 21; } while (l-- > 0) { *cp += complex.Abs(*ap - val); ap++; cp++; } } } System.Threading.Interlocked.Decrement(ref workerCount); }; #endregion #region work distribution int i = 0, workItemCount = Settings.s_maxNumberThreads, workItemLength; if (Settings.s_maxNumberThreads > 1 && outDims.NumberOfElements >= Settings.s_minParallelElement1Count && outDims[1] > 1) { if (outDims[1] > workItemCount) { workItemLength = outDims[1] / workItemCount; } else { workItemLength = outDims[1] / 2; workItemCount = 2; } } else { workItemLength = outDims[1]; workItemCount = 1; } //int[] partResults = new int[workItemCount]; fixed ( complex* arrAP = arrA) fixed ( complex* arrBP = arrB) fixed ( complex* retArrP = retArr) { for (; i < workItemCount - 1; i++) { Tuple range = new Tuple (workItemLength , (IntPtr)(arrAP + i * outDims[0] * workItemLength) , (IntPtr)(arrBP + i * dim * workItemLength) , (IntPtr)(retArrP + i * workItemLength)); System.Threading.Interlocked.Increment(ref workerCount); ILThreadPool.QueueUserWorkItem(i, worker, range); } // the last (or may the only) chunk is done right here //System.Threading.Interlocked.Increment(ref retStorage.PendingTasks); worker(new Tuple (outDims[1] - i * workItemLength , (IntPtr)(arrAP + i * outDims[0] * workItemLength) , (IntPtr)(arrBP + i * dim * workItemLength) , (IntPtr)(retArrP + i * workItemLength))); ILThreadPool.Wait4Workers(ref workerCount); } #endregion return new ILRetArray(retStorage); } } #endregion HYCALPER AUTO GENERATED CODE } }