/// <summary> /// Generates a matrix with <paramref name="xDim"/> being the leading dimension in column-major storage. /// </summary> /// <param name="unmanagedVectors">A memory block to store the generated matrix. /// Must be as large as <paramref name="xDim"/> x <paramref name="yDim"/>.</param> /// <param name="unmanagedBaseVectors">A temporary block to store all the base vectors. /// Must be as large as Max(<paramref name="xDim"/>, <paramref name="yDim"/>)^2. /// Only neccessary when <paramref name="mode"/> is set to <see cref="VectorGenerationMode.AverageBaseVectors"/>.</param> /// <param name="temp">The temporary storage. It should be as long as the longer of the dimensions.</param> /// <param name="random">The random object for number generation.</param> /// <param name="xDim">The size of the other dimension.</param> /// <param name="yDim">The size of the leading dimension.</param> /// <param name="mode">If true, the vectors along the longer dimension will be orthonormalized.</param> /// <param name="axisToNormalize">The axis along which to normalize vectors after orthonormalization.</param> public static void GenerateTransformMatrix( MyMemoryBlock<float> unmanagedVectors, MyMemoryBlock<float> unmanagedBaseVectors, MyMemoryBlock<float> temp, Random random, int xDim, int yDim, MyProductKernel<float> dotKernel, MyCudaKernel multKernel, MyCudaKernel transposeKernel, int GPU, VectorGenerationMode mode = VectorGenerationMode.Normal, AxisToNormalizeEnum axisToNormalize = AxisToNormalizeEnum.yDim) { Debug.Assert(random != null, "Missing random object"); Debug.Assert(unmanagedVectors != null && (mode != VectorGenerationMode.AverageBaseVectors || unmanagedBaseVectors != null) && temp != null, "Missing data!"); Debug.Assert(dotKernel != null && multKernel != null && transposeKernel != null, "Missing a kernel!"); // Mapping to rows --- Column-major storage --- rows will the leading dimension // The larger dimension vectors will be orthogonal; the cols dimension vectors will be normalized switch (mode) { case VectorGenerationMode.Normal: if (axisToNormalize == AxisToNormalizeEnum.xDim) { // Generate normalized vectors with xDim as the leading dim GenerateRandomNormalVectors(unmanagedVectors.Host, random, xDim, yDim); unmanagedVectors.SafeCopyToDevice(); // Transpose to the correct position transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } else { GenerateRandomNormalVectors(unmanagedVectors.Host, random, yDim, xDim); unmanagedVectors.SafeCopyToDevice(); } break; case VectorGenerationMode.Orthonormalize: int largerDim = Math.Max(xDim, yDim); int smallerDim = Math.Min(xDim, yDim); // Generate vectors with larger leading dimension GenerateRandomNormalVectors(unmanagedVectors.Host, random, largerDim, smallerDim, normalize: false); unmanagedVectors.SafeCopyToDevice(); // Orthonormalize along the larger dimension OrthonormalizeVectors(unmanagedVectors, temp, largerDim, smallerDim, dotKernel, multKernel, GPU); if (xDim > yDim) { // xDim is leading and is normalized // We need to transpose to get the correct dims transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); if (axisToNormalize == AxisToNormalizeEnum.yDim) NormalizeLeadingDim(unmanagedVectors, temp, yDim, xDim, dotKernel, multKernel, GPU); } else { // yDim is leading and is normalized // The matrix is in correct position if (axisToNormalize == AxisToNormalizeEnum.xDim) { // TODO: generate the matrix with transposed dims? // TODO: SMELLY VERSION: transposeKernel.Run(unmanagedVectors, unmanagedVectors, yDim, xDim); NormalizeLeadingDim(unmanagedVectors, temp, xDim, yDim, dotKernel, multKernel, GPU); transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } } break; case VectorGenerationMode.AverageBaseVectors: int longerDim = Math.Max(xDim, yDim); int shorterDim = Math.Min(xDim, yDim); GenerateTransformMatrix( unmanagedBaseVectors, null, temp, random, longerDim, longerDim, dotKernel, multKernel, transposeKernel, GPU, VectorGenerationMode.Orthonormalize); if (shorterDim == longerDim) break; float it = 0f; float step = longerDim / (float)shorterDim; int beg, end = 0; for (int i = 0; i < shorterDim; i++) { beg = end; it += step; end = (int)it; var vect = unmanagedVectors.GetDevicePtr(GPU, i * longerDim); for (int j = beg; j < end; j++) { var baseVect = unmanagedBaseVectors.GetDevicePtr(GPU, j * longerDim); multKernel.Run(baseVect, vect, vect, (int)MyJoin.MyJoinOperation.Addition, longerDim, longerDim); } } if (xDim > yDim) { // xDim is leading and is not normalized // We need to transpose to get the correct dims if (axisToNormalize == AxisToNormalizeEnum.xDim) { NormalizeLeadingDim(unmanagedVectors, temp, xDim, yDim, dotKernel, multKernel, GPU); transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } else { transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); NormalizeLeadingDim(unmanagedVectors, temp, yDim, xDim, dotKernel, multKernel, GPU); } } else { // yDim is leading and is not normalized // The matrix is in correct position if (axisToNormalize == AxisToNormalizeEnum.yDim) NormalizeLeadingDim(unmanagedVectors, temp, yDim, xDim, dotKernel, multKernel, GPU); else { // TODO: SMELLY VERSION: transposeKernel.Run(unmanagedVectors, unmanagedVectors, yDim, xDim); NormalizeLeadingDim(unmanagedVectors, temp, xDim, yDim, dotKernel, multKernel, GPU); transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } } break; } }
/// <summary> /// Generates a matrix with <paramref name="xDim"/> being the leading dimension in column-major storage. /// </summary> /// <param name="unmanagedVectors">A memory block to store the generated matrix. /// Must be as large as <paramref name="xDim"/> x <paramref name="yDim"/>.</param> /// <param name="unmanagedBaseVectors">A temporary block to store all the base vectors. /// Must be as large as Max(<paramref name="xDim"/>, <paramref name="yDim"/>)^2. /// Only neccessary when <paramref name="mode"/> is set to <see cref="VectorGenerationMode.AverageBaseVectors"/>.</param> /// <param name="temp">The temporary storage. It should be as long as the longer of the dimensions.</param> /// <param name="random">The random object for number generation.</param> /// <param name="xDim">The size of the other dimension.</param> /// <param name="yDim">The size of the leading dimension.</param> /// <param name="mode">If true, the vectors along the longer dimension will be orthonormalized.</param> /// <param name="axisToNormalize">The axis along which to normalize vectors after orthonormalization.</param> public static void GenerateTransformMatrix( MyMemoryBlock <float> unmanagedVectors, MyMemoryBlock <float> unmanagedBaseVectors, MyMemoryBlock <float> temp, Random random, int xDim, int yDim, MyCudaKernel dotKernel, MyCudaKernel multKernel, MyCudaKernel transposeKernel, int GPU, VectorGenerationMode mode = VectorGenerationMode.Normal, AxisToNormalizeEnum axisToNormalize = AxisToNormalizeEnum.yDim) { Debug.Assert(random != null, "Missing random object"); Debug.Assert(unmanagedVectors != null && (mode != VectorGenerationMode.AverageBaseVectors || unmanagedBaseVectors != null) && temp != null, "Missing data!"); Debug.Assert(dotKernel != null && multKernel != null && transposeKernel != null, "Missing a kernel!"); // Mapping to rows --- Column-major storage --- rows will the leading dimension // The larger dimension vectors will be orthogonal; the cols dimension vectors will be normalized switch (mode) { case VectorGenerationMode.Normal: if (axisToNormalize == AxisToNormalizeEnum.xDim) { // Generate normalized vectors with xDim as the leading dim GenerateRandomNormalVectors(unmanagedVectors.Host, random, xDim, yDim); unmanagedVectors.SafeCopyToDevice(); // Transpose to the correct position transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } else { GenerateRandomNormalVectors(unmanagedVectors.Host, random, yDim, xDim); unmanagedVectors.SafeCopyToDevice(); } break; case VectorGenerationMode.Orthonormalize: int largerDim = Math.Max(xDim, yDim); int smallerDim = Math.Min(xDim, yDim); // Generate vectors with larger leading dimension GenerateRandomNormalVectors(unmanagedVectors.Host, random, largerDim, smallerDim, normalize: false); unmanagedVectors.SafeCopyToDevice(); // Orthonormalize along the larger dimension OrthonormalizeVectors(unmanagedVectors, temp, largerDim, smallerDim, dotKernel, multKernel, GPU); if (xDim > yDim) { // xDim is leading and is normalized // We need to transpose to get the correct dims transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); if (axisToNormalize == AxisToNormalizeEnum.yDim) { NormalizeLeadingDim(unmanagedVectors, temp, yDim, xDim, dotKernel, multKernel, GPU); } } else { // yDim is leading and is normalized // The matrix is in correct position if (axisToNormalize == AxisToNormalizeEnum.xDim) { // TODO: generate the matrix with transposed dims? // TODO: SMELLY VERSION: transposeKernel.Run(unmanagedVectors, unmanagedVectors, yDim, xDim); NormalizeLeadingDim(unmanagedVectors, temp, xDim, yDim, dotKernel, multKernel, GPU); transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } } break; case VectorGenerationMode.AverageBaseVectors: int longerDim = Math.Max(xDim, yDim); int shorterDim = Math.Min(xDim, yDim); GenerateTransformMatrix( unmanagedBaseVectors, null, temp, random, longerDim, longerDim, dotKernel, multKernel, transposeKernel, GPU, VectorGenerationMode.Orthonormalize); if (shorterDim == longerDim) { break; } float it = 0f; float step = longerDim / (float)shorterDim; int beg, end = 0; for (int i = 0; i < shorterDim; i++) { beg = end; it += step; end = (int)it; var vect = unmanagedVectors.GetDevicePtr(GPU, i * longerDim); for (int j = beg; j < end; j++) { var baseVect = unmanagedBaseVectors.GetDevicePtr(GPU, j * longerDim); multKernel.Run(baseVect, vect, vect, (int)MyJoin.MyJoinOperation.Addition, longerDim, longerDim); } } if (xDim > yDim) { // xDim is leading and is not normalized // We need to transpose to get the correct dims if (axisToNormalize == AxisToNormalizeEnum.xDim) { NormalizeLeadingDim(unmanagedVectors, temp, xDim, yDim, dotKernel, multKernel, GPU); transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } else { transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); NormalizeLeadingDim(unmanagedVectors, temp, yDim, xDim, dotKernel, multKernel, GPU); } } else { // yDim is leading and is not normalized // The matrix is in correct position if (axisToNormalize == AxisToNormalizeEnum.yDim) { NormalizeLeadingDim(unmanagedVectors, temp, yDim, xDim, dotKernel, multKernel, GPU); } else { // TODO: SMELLY VERSION: transposeKernel.Run(unmanagedVectors, unmanagedVectors, yDim, xDim); NormalizeLeadingDim(unmanagedVectors, temp, xDim, yDim, dotKernel, multKernel, GPU); transposeKernel.Run(unmanagedVectors, unmanagedVectors, xDim, yDim); } } break; } }