/// <summary> /// Fills the array <see cref="_x"/> with <see cref="LongLag"/> new unsigned random numbers. /// </summary> /// <remarks> /// Generated random numbers are 32-bit unsigned integers greater than or equal to 0 /// and less than or equal to <see cref="Int32.MaxValue"/>. /// </remarks> private void Fill() { CommonParallel.For( 0, Control.NumberOfParallelWorkerThreads, index => { // Two loops to avoid costly modulo operations for (var j = index; j < ShortLag; j = j + Control.NumberOfParallelWorkerThreads) { _x[j] += _x[j + (LongLag - ShortLag)]; } for (var j = ShortLag + index; j < LongLag; j = j + Control.NumberOfParallelWorkerThreads) { _x[j] += _x[j - ShortLag - index]; } }); _i = 0; }
private static void LRNKernel(int[] axes, int[] strides, float[] xw, float[] yw, int kernelSize) { CommonParallel.For( 0, axes[0], (a, b) => { for (; a < b; a++) { NativeMethods.LRNKernel( xw, yw, kernelSize, a, axes, strides); } }, new ParallelOptions()); }
public Vector <double> ParallelLoop4096() { var z = _b; for (int i = 0; i < _rounds; i++) { var aa = ((DenseVectorStorage <double>)_a.Storage).Data; var az = ((DenseVectorStorage <double>)z.Storage).Data; var ar = new Double[aa.Length]; CommonParallel.For(0, ar.Length, 4096, (u, v) => { for (int k = u; k < v; k++) { ar[k] = aa[k] + az[k]; } }); z = Vector <double> .Build.Dense(ar); } return(z); }
static void SamplesUnchecked(System.Random rnd, double[] values, int freedom) { var standard = new double[values.Length * freedom]; Normal.SamplesUnchecked(rnd, standard, 0.0, 1.0); CommonParallel.For(0, values.Length, 4096, (a, b) => { for (int i = a; i < b; i++) { int k = i * freedom; double sum = 0; for (int j = 0; j < freedom; j++) { sum += standard[k + j] * standard[k + j]; } values[i] = Math.Sqrt(sum); } }); }
/// <summary> /// Returns a negated vector. /// </summary> /// <returns>The negated vector.</returns> /// <remarks>Added as an alternative to the unary negation operator.</remarks> public override Vector <Complex> Negate() { var result = new SparseVector(Count) { _nonZeroValues = new Complex[NonZerosCount], _nonZeroIndices = new int[NonZerosCount], NonZerosCount = NonZerosCount }; if (NonZerosCount != 0) { CommonParallel.For( 0, NonZerosCount, index => result._nonZeroValues[index] = -_nonZeroValues[index]); Buffer.BlockCopy(_nonZeroIndices, 0, result._nonZeroIndices, 0, NonZerosCount * Constants.SizeOfInt); } return(result); }
/// <summary> /// Create a piecewise log-linear interpolation from a set of (x,y) value pairs, sorted ascending by x. /// </summary> public new static LogLinearInterpolation Interpolate(double[] x, double[] y) { if (x.Length != y.Length) { throw new ArgumentException("ArgumentVectorsSameLength"); } if (x.Length < 1) { throw new ArgumentException(string.Format("ArrayTooSmall"), nameof(x)); } var logy = new double[y.Length]; CommonParallel.For(0, y.Length, 4096, (a, b) => { for (int i = a; i < b; i++) { logy[i] = -Math.Log(y[i]); } }); return(new LogLinearInterpolation(x, logy)); }
/// <summary> /// Radix-2 generic FFT for power-of-two sample vectors (Parallel Version). /// </summary> /// <param name="samples">Sample vector, where the FFT is evaluated in place.</param> /// <param name="exponentSign">Fourier series exponent sign.</param> /// <exception cref="ArgumentException"/> internal static void Radix2Parallel(Complex[] samples, int exponentSign) { if (!samples.Length.IsPowerOfTwo()) { throw new ArgumentException(Resources.ArgumentPowerOfTwo); } Radix2Reorder(samples); for (var levelSize = 1; levelSize < samples.Length; levelSize *= 2) { var size = levelSize; CommonParallel.For(0, size, (u, v) => { for (int i = u; i < v; i++) { Radix2Step(samples, exponentSign, size, i); } }); } }
internal override void MapIndexedToUnchecked <TU>(VectorStorage <TU> target, Func <int, T, TU> f, Zeros zeros, ExistingData existingData) { if (target is DenseVectorStorage <TU> denseTarget) { CommonParallel.For(0, Data.Length, 4096, (a, b) => { for (int i = a; i < b; i++) { denseTarget.Data[i] = f(i, Data[i]); } }); return; } // FALL BACK for (int i = 0; i < Length; i++) { target.At(i, f(i, Data[i])); } }
/// <summary> /// Divides a scalar by each element of the matrix and stores the result in the result matrix. /// </summary> /// <param name="dividend">The scalar to add.</param> /// <param name="result">The matrix to store the result of the division.</param> protected override void DoDivideByThis(Complex dividend, Matrix <Complex> result) { if (result is DiagonalMatrix diagResult) { var resultData = diagResult._data; CommonParallel.For(0, _data.Length, 4096, (a, b) => { for (int i = a; i < b; i++) { resultData[i] = dividend / _data[i]; } }); return; } result.Clear(); for (int i = 0; i < _data.Length; i++) { result.At(i, i, dividend / _data[i]); } }
/// <summary> /// Computes the modulus for each element of the matrix. /// </summary> /// <param name="divisor">The divisor to use.</param> /// <param name="result">Matrix to store the results in.</param> protected override void DoModulus(float divisor, Matrix <float> result) { var denseResult = result as DenseMatrix; if (denseResult == null) { base.DoModulus(divisor, result); } else { if (!ReferenceEquals(this, result)) { CopyTo(result); } CommonParallel.For( 0, Data.Length, index => denseResult.Data[index] %= divisor); } }
/// <summary> /// Subtracts another vector to this vector and stores the result into the result vector. /// </summary> /// <param name="other">The vector to subtract from this one.</param> /// <param name="result">The vector to store the result of the subtraction.</param> /// <exception cref="ArgumentNullException">If the other vector is <see langword="null"/>.</exception> /// <exception cref="ArgumentNullException">If the result vector is <see langword="null"/>.</exception> /// <exception cref="ArgumentException">If this vector and <paramref name="other"/> are not the same size.</exception> /// <exception cref="ArgumentException">If this vector and <paramref name="result"/> are not the same size.</exception> public override void Subtract(Vector <Complex> other, Vector <Complex> result) { if (result == null) { throw new ArgumentNullException("result"); } if (Count != other.Count) { throw new ArgumentException(Resources.ArgumentVectorsSameLength, "other"); } if (Count != result.Count) { throw new ArgumentException(Resources.ArgumentVectorsSameLength, "result"); } if (ReferenceEquals(this, result) || ReferenceEquals(other, result)) { var tmp = Subtract(other); tmp.CopyTo(result); } else { var rdense = result as DenseVector; var odense = other as DenseVector; if (rdense != null && odense != null) { CopyTo(result); Control.LinearAlgebraProvider.AddVectorToScaledVector(rdense.Data, -Complex.One, odense.Data); } else { CommonParallel.For( 0, Data.Length, index => result[index] = Data[index] - other[index]); } } }
/// <summary> /// Initializes a new instance of the <see cref="SparseVector"/> class with a given size /// and each element set to the given value; /// </summary> /// <param name="size"> /// the size of the vector. /// </param> /// <param name="value"> /// the value to set each element to. /// </param> /// <exception cref="ArgumentException"> /// If <paramref name="size"/> is less than one. /// </exception> public SparseVector(int size, Complex32 value) : this(size) { if (value == Complex32.Zero) { // Skip adding values return; } // We already know that this vector is "full", let's allocate all needed memory _nonZeroValues = new Complex32[size]; _nonZeroIndices = new int[size]; NonZerosCount = size; CommonParallel.For( 0, Count, index => { _nonZeroValues[index] = value; _nonZeroIndices[index] = index; }); }
/// <param name="x">Sample points (N+1), sorted ascending</param> /// <param name="y">Sample values (N or N+1) at the corresponding points; intercept, zero order coefficients</param> public override void Initialize(double[] x, double[] y) { if (x.Length != y.Length) { throw new ArgumentException("ArgumentVectorsSameLength"); } if (x.Length < 1) { throw new ArgumentException(string.Format("ArrayTooSmall"), nameof(x)); } X = x; var logy = new double[y.Length]; CommonParallel.For(0, y.Length, 4096, (a, b) => { for (int i = a; i < b; i++) { logy[i] = -Math.Log(y[i]); } }); Y = logy; }
/// <summary> /// Conjugates vector and save result to <paramref name="target"/> /// </summary> /// <param name="target">Target vector</param> public override void Conjugate(Vector <Complex32> target) { if (target == null) { throw new ArgumentNullException("target"); } if (Count != target.Count) { throw new ArgumentException(Resources.ArgumentVectorsSameLength, "target"); } if (ReferenceEquals(this, target)) { var tmp = CreateVector(Count); Conjugate(tmp); tmp.CopyTo(target); } var otherVector = target as SparseVector; if (otherVector == null) { base.Conjugate(target); } else { // Lets copy only needed data. Portion of needed data is determined by NonZerosCount value otherVector._nonZeroValues = new Complex32[NonZerosCount]; otherVector._nonZeroIndices = new int[NonZerosCount]; otherVector.NonZerosCount = NonZerosCount; if (NonZerosCount != 0) { CommonParallel.For(0, NonZerosCount, index => otherVector._nonZeroValues[index] = _nonZeroValues[index].Conjugate()); Buffer.BlockCopy(_nonZeroIndices, 0, otherVector._nonZeroIndices, 0, NonZerosCount * Constants.SizeOfInt); } } }
/// <summary> /// Create a linear spline interpolation from an unsorted set of (x,y) value pairs. /// WARNING: Works in-place and can thus causes the data array to be reordered and modified. /// </summary> public static TransformedInterpolation InterpolateInplace( Func <double, double> transform, Func <double, double> transformInverse, double[] x, double[] y) { if (x.Length != y.Length) { throw new ArgumentException("All vectors must have the same dimensionality."); } Sorting.Sort(x, y); CommonParallel.For(0, y.Length, 4096, (a, b) => { for (int i = a; i < b; i++) { y[i] = transformInverse(y[i]); } }); return(new TransformedInterpolation(LinearSpline.InterpolateSorted(x, y), transform)); }
internal override void MapSubMatrixIndexedToUnchecked <TU>(MatrixStorage <TU> target, Func <int, int, T, TU> f, int sourceRowIndex, int targetRowIndex, int rowCount, int sourceColumnIndex, int targetColumnIndex, int columnCount, Zeros zeros, ExistingData existingData) { var denseTarget = target as DenseColumnMajorMatrixStorage <TU>; if (denseTarget != null) { CommonParallel.For(0, columnCount, Math.Max(4096 / rowCount, 32), (a, b) => { for (var j = a; j < b; j++) { var sourceIndex = sourceRowIndex + (j + sourceColumnIndex) * RowCount; var targetIndex = targetRowIndex + (j + targetColumnIndex) * target.RowCount; for (var i = 0; i < rowCount; i++) { denseTarget.Data[targetIndex++] = f(targetRowIndex + i, targetColumnIndex + j, Data[sourceIndex++]); } } }); return; } // TODO: Proper Sparse Implementation // FALL BACK for (int j = sourceColumnIndex, jj = targetColumnIndex; j < sourceColumnIndex + columnCount; j++, jj++) { var index = sourceRowIndex + j * RowCount; for (var ii = targetRowIndex; ii < targetRowIndex + rowCount; ii++) { target.At(ii, jj, f(ii, jj, Data[index++])); } } }
/// <summary> /// Computes the modulus for each element of the matrix. /// </summary> /// <param name="divisor">The divisor to use.</param> /// <param name="result">Matrix to store the results in.</param> protected override void DoModulus(double divisor, Matrix<double> result) { var denseResult = result as DenseMatrix; if (denseResult == null) { base.DoModulus(divisor, result); return; } if (!ReferenceEquals(this, result)) { CopyTo(result); } CommonParallel.For(0, _values.Length, (a, b) => { var v = denseResult._values; for (int i = a; i < b; i++) { v[i] %= divisor; } }); }
static void SamplesUnchecked(System.Random rnd, int[] values, double lambda, double nu, double z) { var uniform = rnd.NextDoubles(values.Length); CommonParallel.For(0, values.Length, 4096, (a, b) => { for (int i = a; i < b; i++) { var u = uniform[i]; var p = 1.0 / z; var cdf = p; var k = 0; while (u > cdf) { k++; p = p * lambda / Math.Pow(k, nu); cdf += p; } values[i] = k; } }); }
/// <summary> /// Divides a scalar by each element of the matrix and stores the result in the result matrix. /// </summary> /// <param name="dividend">The scalar to add.</param> /// <param name="result">The matrix to store the result of the division.</param> protected override void DoDivideByThis(float dividend, Matrix <float> result) { var diagResult = result as DiagonalMatrix; if (diagResult != null) { var resultData = diagResult._data; CommonParallel.For(0, _data.Length, 4096, (a, b) => { for (int i = a; i < b; i++) { resultData[i] = dividend / _data[i]; } }); return; } result.Clear(); for (int i = 0; i < _data.Length; i++) { result.At(i, i, dividend / _data[i]); } }
// FUNCTIONAL COMBINATORS internal override void MapToUnchecked <TU>(VectorStorage <TU> target, Func <T, TU> f, Zeros zeros, ExistingData existingData) { var denseTarget = target as DenseVectorStorage <TU>; if (denseTarget != null) { CommonParallel.For(0, Data.Length, 4096, (a, b) => { for (int i = a; i < b; i++) { denseTarget.Data[i] = f(Data[i]); } }); return; } // FALL BACK for (int i = 0; i < Length; i++) { target.At(i, f(Data[i])); } }
/// <summary> /// Create a linear spline interpolation from a set of (x,y) value pairs, sorted ascendingly by x. /// </summary> public static TransformedInterpolation InterpolateSorted( Func <double, double> transform, Func <double, double> transformInverse, double[] x, double[] y) { if (x.Length != y.Length) { throw new ArgumentException(Resource.ArgumentVectorsSameLength); } var yhat = new double[y.Length]; CommonParallel.For(0, y.Length, 4096, (a, b) => { for (int i = a; i < b; i++) { yhat[i] = transformInverse(y[i]); } }); return(new TransformedInterpolation(LinearSpline.InterpolateSorted(x, yhat), transform)); }
/// <summary> /// Naive generic DFT, useful e.g. to verify faster algorithms. /// </summary> /// <param name="samples">Time-space sample vector.</param> /// <param name="exponentSign">Fourier series exponent sign.</param> /// <returns>Corresponding frequency-space vector.</returns> static void Naive(Complex32[] samples, int exponentSign) { var w0 = exponentSign * Constants.Pi2 / samples.Length; var spectrum = new Complex32[samples.Length]; CommonParallel.For(0, samples.Length, (u, v) => { for (int i = u; i < v; i++) { var wk = w0 * i; var sum = Complex32.Zero; for (var n = 0; n < samples.Length; n++) { var w = n * wk; sum += samples[n] * new Complex32((float)Math.Cos(w), (float)Math.Sin(w)); } spectrum[i] = sum; } }); spectrum.Copy(samples); }
/// <summary> /// Naive generic DFT, useful e.g. to verify faster algorithms. /// </summary> /// <param name="samples">Time-space sample vector.</param> /// <param name="exponentSign">Fourier series exponent sign.</param> /// <returns>Corresponding frequency-space vector.</returns> internal static Complex[] Naive(Complex[] samples, int exponentSign) { var w0 = exponentSign * Constants.Pi2 / samples.Length; var spectrum = new Complex[samples.Length]; CommonParallel.For(0, samples.Length, (u, v) => { for (int i = u; i < v; i++) { var wk = w0 * i; var sum = Complex.Zero; for (var n = 0; n < samples.Length; n++) { var w = n * wk; sum += samples[n] * new Complex(Math.Cos(w), Math.Sin(w)); } spectrum[i] = sum; } }); return(spectrum); }
/// <summary> /// Naive generic DHT, useful e.g. to verify faster algorithms. /// </summary> /// <param name="samples">Time-space sample vector.</param> /// <returns>Corresponding frequency-space vector.</returns> internal static double[] Naive(double[] samples) { var w0 = Constants.Pi2 / samples.Length; var spectrum = new double[samples.Length]; CommonParallel.For(0, samples.Length, (u, v) => { for (int i = u; i < v; i++) { var wk = w0 * i; var sum = 0.0; for (var n = 0; n < samples.Length; n++) { var w = n * wk; sum += samples[n] * Constants.Sqrt2 * Math.Cos(w - Constants.PiOver4); } spectrum[i] = sum; } }); return(spectrum); }
public float[] Assign(int startingIndex, int count, IList <IVector <float> > x, float[] result, CancellationToken cancellationToken) { if (result == null) { result = new float[x.Count]; } CommonParallel.For( 0, x.Count, (a, b) => { for (int i = a; i < b; i++) { this.Assign(startingIndex, count, x[i], out result[i]); } }, new ParallelOptions() { CancellationToken = cancellationToken, }); return(result); }
void MapSubMatrixIndexedToUnchecked <TU>(DenseColumnMajorMatrixStorage <TU> target, Func <int, int, T, TU> f, int sourceRowIndex, int targetRowIndex, int rowCount, int sourceColumnIndex, int targetColumnIndex, int columnCount, Zeros zeros, ExistingData existingData) where TU : struct, IEquatable <TU>, IFormattable { var processZeros = zeros == Zeros.Include || !Zero.Equals(f(0, 1, Zero)); if (existingData == ExistingData.Clear && !processZeros) { target.ClearUnchecked(targetRowIndex, rowCount, targetColumnIndex, columnCount); } if (processZeros) { CommonParallel.For(0, columnCount, Math.Max(4096 / rowCount, 32), (a, b) => { int sourceColumn = sourceColumnIndex + a; int targetColumn = targetColumnIndex + a; for (int j = a; j < b; j++) { int targetIndex = targetRowIndex + (j + targetColumnIndex) * target.RowCount; int sourceRow = sourceRowIndex; int targetRow = targetRowIndex; for (int i = 0; i < rowCount; i++) { target.Data[targetIndex++] = f(targetRow++, targetColumn, sourceRow++ == sourceColumn ? Data[sourceColumn] : Zero); } sourceColumn++; targetColumn++; } }); } else { if (sourceRowIndex > sourceColumnIndex && sourceColumnIndex + columnCount > sourceRowIndex) { // column by column, but skip resulting zero columns at the beginning int columnInit = sourceRowIndex - sourceColumnIndex; int offset = (columnInit + targetColumnIndex) * target.RowCount + targetRowIndex; int step = target.RowCount + 1; int count = Math.Min(columnCount - columnInit, rowCount); for (int k = 0, j = offset; k < count; j += step, k++) { target.Data[j] = f(targetRowIndex + k, targetColumnIndex + columnInit + k, Data[sourceRowIndex + k]); } } else if (sourceRowIndex < sourceColumnIndex && sourceRowIndex + rowCount > sourceColumnIndex) { // row by row, but skip resulting zero rows at the beginning int rowInit = sourceColumnIndex - sourceRowIndex; int offset = targetColumnIndex * target.RowCount + rowInit + targetRowIndex; int step = target.RowCount + 1; int count = Math.Min(columnCount, rowCount - rowInit); for (int k = 0, j = offset; k < count; j += step, k++) { target.Data[j] = f(targetRowIndex + rowInit + k, targetColumnIndex + k, Data[sourceColumnIndex + k]); } } else { int offset = targetColumnIndex * target.RowCount + targetRowIndex; int step = target.RowCount + 1; var count = Math.Min(columnCount, rowCount); for (int k = 0, j = offset; k < count; j += step, k++) { target.Data[j] = f(targetRowIndex + k, targetColumnIndex + k, Data[sourceRowIndex + k]); } } } }
/// <summary> /// Solves A*X=B for X using a previously QR factored matrix. /// </summary> /// <param name="q"> /// The Q matrix obtained by calling <seecreQRFactor( double[], int, int, double[], double[]).</param> /// <param name="r"> /// The R matrix obtained by calling <seecreQRFactor( double[], int, int, double[], double[]). </param> /// <param name="rowsA">The number of rows in the A matrix.</param> /// <param name="columnsA">The number of columns in the A matrix.</param> /// <param name="tau"> /// Contains additional information on Q. Only used for the native solver /// and can be <c>null</c> for the managed provider. /// </param> /// <param name="b">The B matrix.</param> /// <param name="columnsB">The number of columns of B.</param> /// <param name="x">On exit, the solution matrix.</param> /// <param name="method">The type of QR factorization to perform. <seealsocreQRMethod</param> /// <remarks>Rows must be greater or equal to columns.</remarks> public virtual void QRSolveFactored(double[] q, double[] r, int rowsA, int columnsA, double[] tau, double[] b, int columnsB, double[] x, QRMethod method = QRMethod.Full) { if (r == null) { throw new ArgumentNullException(nameof(r)); } if (q == null) { throw new ArgumentNullException(nameof(q)); } if (b == null) { throw new ArgumentNullException(nameof(q)); } if (x == null) { throw new ArgumentNullException(nameof(q)); } if (rowsA < columnsA) { //throw new ArgumentException(Resources.RowsLessThanColumns); } int rowsQ, columnsQ, rowsR, columnsR; if (method == QRMethod.Full) { rowsQ = columnsQ = rowsR = rowsA; columnsR = columnsA; } else { rowsQ = rowsA; columnsQ = rowsR = columnsR = columnsA; } if (r.Length != rowsR * columnsR) { //throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsR*columnsR), nameof(r)); } if (q.Length != rowsQ * columnsQ) { //throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsQ*columnsQ), nameof(q)); } if (b.Length != rowsA * columnsB) { //throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, rowsA*columnsB), nameof(b)); } if (x.Length != columnsA * columnsB) { //throw new ArgumentException(string.Format(Resources.ArgumentArrayWrongLength, columnsA*columnsB), nameof(x)); } var sol = new double[b.Length]; // Copy B matrix to "sol", so B data will not be changed Buffer.BlockCopy(b, 0, sol, 0, b.Length * Constants.SizeOfDouble); // Compute Y = transpose(Q)*B var column = new double[rowsA]; for (var j = 0; j < columnsB; j++) { var jm = j * rowsA; Array.Copy(sol, jm, column, 0, rowsA); CommonParallel.For(0, columnsA, (u, v) => { for (var i = u; i < v; i++) { var im = i * rowsA; var sum = 0.0; for (var k = 0; k < rowsA; k++) { sum += q[im + k] * column[k]; } sol[jm + i] = sum; } }); } // Solve R*X = Y; for (var k = columnsA - 1; k >= 0; k--) { var km = k * rowsR; for (var j = 0; j < columnsB; j++) { sol[j * rowsA + k] /= r[km + k]; } for (var i = 0; i < k; i++) { for (var j = 0; j < columnsB; j++) { var jm = j * rowsA; sol[jm + i] -= sol[jm + k] * r[km + i]; } } } // Fill result matrix for (var col = 0; col < columnsB; col++) { Array.Copy(sol, col * rowsA, x, col * columnsA, columnsR); } }
public override void MatrixMultiplyWithUpdate(Transpose transposeA, Transpose transposeB, double alpha, double[] a, int rowsA, int columnsA, double[] b, int rowsB, int columnsB, double beta, double[] c) { if (a == null) { throw new ArgumentNullException("a"); } if (b == null) { throw new ArgumentNullException("b"); } if (c == null) { throw new ArgumentNullException("c"); } if (transposeA != Transpose.DontTranspose) { Swap(ref rowsA, ref columnsA); } if (transposeB != Transpose.DontTranspose) { Swap(ref rowsB, ref columnsB); } if (columnsA != rowsB) { throw new ArgumentOutOfRangeException(String.Format("columnsA ({0}) != rowsB ({1})", columnsA, rowsB)); } if (rowsA * columnsA != a.Length) { throw new ArgumentOutOfRangeException(String.Format("rowsA ({0}) * columnsA ({1}) != a.Length ({2})", rowsA, columnsA, a.Length)); } if (rowsB * columnsB != b.Length) { throw new ArgumentOutOfRangeException(String.Format("rowsB ({0}) * columnsB ({1}) != b.Length ({2})", rowsB, columnsB, b.Length)); } if (rowsA * columnsB != c.Length) { throw new ArgumentOutOfRangeException(String.Format("rowsA ({0}) * columnsB ({1}) != c.Length ({2})", rowsA, columnsB, c.Length)); } // handle the degenerate cases if (beta == 0.0) { Array.Clear(c, 0, c.Length); } else if (beta != 1.0) { ScaleArray(beta, c, c); } if (alpha == 0.0) { return; } // Extract column arrays var columnDataB = new double[columnsB][]; for (int i = 0; i < columnDataB.Length; i++) { columnDataB[i] = GetColumn(transposeB, i, rowsB, columnsB, b); } var shouldNotParallelize = rowsA + columnsB + columnsA < Control.ParallelizeOrder || Control.MaxDegreeOfParallelism < 2; if (shouldNotParallelize) { for (int i = 0; i < rowsA; i++) { var row = GetRow(transposeA, i, rowsA, columnsA, a); for (int j = 0; j < columnsB; j++) { var col = columnDataB[j]; double sum = 0; for (int ii = 0; ii < row.Length; ii++) { sum += row[ii] * col[ii]; } c[j * rowsA + i] += alpha * sum; } } } else { CommonParallel.For(0, rowsA, 1, (u, v) => { for (int i = u; i < v; i++) { // for each row in a var row = GetRow(transposeA, i, rowsA, columnsA, a); for (int j = 0; j < columnsB; j++) { var column = columnDataB[j]; double sum = 0; for (int ii = 0; ii < row.Length; ii++) { sum += row[ii] * column[ii]; } c[j * rowsA + i] += alpha * sum; } } }); } }
internal override void MapIndexedToUnchecked <TU>(VectorStorage <TU> target, Func <int, T, TU> f, Zeros zeros, ExistingData existingData) { var sparseTarget = target as SparseVectorStorage <TU>; if (sparseTarget != null) { var indices = new List <int>(); var values = new List <TU>(); if (zeros == Zeros.Include || !Zero.Equals(f(0, Zero))) { int k = 0; for (int i = 0; i < Length; i++) { var item = k < ValueCount && (Indices[k]) == i?f(i, Values[k++]) : f(i, Zero); if (!Zero.Equals(item)) { values.Add(item); indices.Add(i); } } } else { for (int i = 0; i < ValueCount; i++) { var item = f(Indices[i], Values[i]); if (!Zero.Equals(item)) { values.Add(item); indices.Add(Indices[i]); } } } sparseTarget.Indices = indices.ToArray(); sparseTarget.Values = values.ToArray(); sparseTarget.ValueCount = values.Count; return; } var denseTarget = target as DenseVectorStorage <TU>; if (denseTarget != null) { if (existingData == ExistingData.Clear) { denseTarget.Clear(); } if (zeros == Zeros.Include || !Zero.Equals(f(0, Zero))) { int k = 0; for (int i = 0; i < Length; i++) { denseTarget.Data[i] = k < ValueCount && (Indices[k]) == i ? f(i, Values[k++]) : f(i, Zero); } } else { CommonParallel.For(0, ValueCount, 4096, (a, b) => { for (int i = a; i < b; i++) { denseTarget.Data[Indices[i]] = f(Indices[i], Values[i]); } }); } return; } // FALL BACK base.MapIndexedToUnchecked(target, f, zeros, existingData); }
/// <summary> /// Learns a <see cref="KMeans"/> model that can map the given inputs to the desired outputs. /// </summary> /// <param name="k">The number of clusters.</param> /// <param name="seeding">The cluster initialization algorithm.</param> /// <param name="maxiter">The maximum number of iterations.</param> /// <param name="distance">The distance function.</param> /// <param name="x">The data points <paramref name="x"/> to clusterize.</param> /// <param name="weights">The <c>weight</c> of importance for each data point.</param> /// <param name="cancellationToken">The cancellationToken token used to notify the classifier that the operation should be canceled.</param> /// <returns> /// The <see cref="KMeans"/> clusterizer learned by this method. /// </returns> /// <exception cref="ArgumentNullException"> /// <para><paramref name="x"/> is <b>null</b>.</para> /// <para>-or-</para> /// <para><paramref name="distance"/> is <b>null</b>.</para> /// </exception> /// <exception cref="ArgumentException"> /// <para><paramref name="weights"/> is not <b>null</b> and the number of elements in <paramref name="weights"/> does not match the number of elements in <paramref name="x"/>.</para> /// </exception> public static KMeans Learn( int k, KMeansSeeding seeding, int maxiter, IVectorDistance <float, IVector <float>, float> distance, IList <IVector <float> > x, IList <float> weights, CancellationToken cancellationToken) { if (x == null) { throw new ArgumentNullException(nameof(x)); } if (weights != null && weights.Count != x.Count) { throw new ArgumentException("The number of weights must match the number of input vectors.", nameof(weights)); } int sampleCount = x.Count; int dimension = x[0].Length; KMeansClusterCollection clusters = new KMeansClusterCollection(k, dimension, distance); switch (seeding) { case KMeansSeeding.KMeansPlusPlus: clusters.KMeansPlusPlusSeeding(x, weights, cancellationToken); break; default: clusters.RandomSeeding(x, weights, cancellationToken); break; } float[] counts = new float[k]; float[] means = new float[k * dimension]; object sync = new object(); for (int iter = 0; iter < maxiter; iter++) { cancellationToken.ThrowIfCancellationRequested(); // reset means and counts if (iter > 0) { Vectors.Set(counts.Length, 0.0f, counts, 0); Vectors.Set(means.Length, 0.0f, means, 0); } // assign vectors to new clusters CommonParallel.For( 0, sampleCount, (a, b) => { float[] lcounts = new float[counts.Length]; float[] lmeans = new float[means.Length]; for (int i = a; i < b; i++) { int index = clusters.Assign(x[i]); float weight = weights?[i] ?? 1.0f; lcounts[index] += weight; x[i].AddProductC(weight, lmeans, index * dimension); } lock (sync) { Mathematics.Add(lcounts.Length, lcounts, 0, counts, 0); Mathematics.Add(lmeans.Length, lmeans, 0, means, 0); } }, new ParallelOptions()); // calculate new centroids for (int i = 0, off = 0; i < k; i++, off += dimension) { if (counts[i] != 0) { Mathematics.DivC(dimension, means, off, counts[i], clusters[i].Centroid, 0); } } } return(new KMeans(clusters) { Seeding = seeding, }); }