public static float[][] DotProduct(DxShader.GpuDevice gpu, float[][] M, bool isCorrelation) { using (var cc = gpu.CreateConstantBuffer <ShaderConstant>(0)) using (var sd = gpu.LoadShader("SingleCellAnalysis.DotProduct.cso", Assembly.GetExecutingAssembly())) { return(CallShadere(gpu, cc, sd, M, isCorrelation)); } }
static void WriteMarix(DxShader.GpuDevice gpu, GBuf buffer, float[][] matrix, int col0, int col1, float[] uploadBuf) { int rows = matrix.Length; Array.Clear(uploadBuf, 0, uploadBuf.Length); MT.Loop(col0, col1, col => { int offset = (col - col0) * rows; for (int row = 0; row < rows; row++) { uploadBuf[offset + row] = matrix[row][col]; } }); gpu.WriteArray(uploadBuf, buffer); }
static float[][] CallShadere(DxShader.GpuDevice gpu, CBuf cc, ComputeShader sd, float[][] M, bool isCorrelation) { cc.c.N = M.Length; int columns = M[0].Length; const int groupSize = 256; int distSize = groupSize * cc.c.N; float[][] dMatrix = new float[M.Length][]; for (int row = 0; row < M.Length; row++) { dMatrix[row] = new float[row]; } int maxColumns = MaxGpuFloats / cc.c.N; int secSize = Math.Min(columns, (maxColumns > 4096) ? 4096 : (maxColumns - 32)); float[] uploadBuf = new float[cc.c.N * secSize]; using (var dataBuf = gpu.CreateBufferRO(cc.c.N * secSize, 4, 0)) using (var distBuf = gpu.CreateBufferRW(distSize, 4, 0)) using (var distStaging = gpu.CreateStagingBuffer(distBuf)) { gpu.SetShader(sd); for (int s0 = 0; s0 < columns; s0 += secSize) { int s1 = Math.Min(s0 + secSize, columns); WriteMarix(gpu, dataBuf, M, s0, s1, uploadBuf); float[] blockDist = new float[distSize]; for (cc.c.iBlock = 1; cc.c.iBlock < cc.c.N; cc.c.iBlock += groupSize) { cc.c.columns = s1 - s0; cc.Upload(); gpu.Run(groupSize); int iBlock2 = Math.Min(cc.c.iBlock + groupSize, cc.c.N); int bSize = (iBlock2 - cc.c.iBlock) * (iBlock2 + cc.c.iBlock - 1) / 2; gpu.ReadRange <float>(blockDist, 0, distStaging, distBuf, bSize); int offset = 0; for (int row = cc.c.iBlock; row < iBlock2; row++) { float[] R = dMatrix[row]; for (int k = 0; k < row; k++) { R[k] += blockDist[offset + k]; } offset += row; } Application.DoEvents(); } } } if (isCorrelation) { MT.ForEach(dMatrix, R => { for (int col = 0; col < R.Length; col++) { R[col] = 1.0f - R[col]; } }); } else // Euclidean distance is wanted. { float[] norm2 = new float[M.Length]; Array.Clear(norm2, 0, M.Length); int L = M[0].Length; MT.ForEach(M, (R, row) => { float sumSquared = 0.0f; for (int col = 0; col < L; col++) { sumSquared += R[col] * R[col]; } norm2[row] = sumSquared; }); MT.Loop(1, M.Length, row => { float[] R = dMatrix[row]; for (int col = 0; col < row; col++) { R[col] = (float)Math.Sqrt(Math.Abs(norm2[row] + norm2[col] - 2 * R[col])); } }); } return(dMatrix); }