public ICudaResult <double[][]> Multiply( CUBLAS_OP a_op, CUBLAS_OP b_op, double alpha, double[][] a, double[][] b, double beta) { // C(m, n) = A(m, k) * B(k, n) var matrix_a_dimensions = MatrixSizeByOperation(a.Length, a[0].Length, a_op); var matrix_b_dimensions = MatrixSizeByOperation(b.Length, b[0].Length, b_op); if (matrix_a_dimensions.Columns != matrix_b_dimensions.Rows) { throw new ArgumentOutOfRangeException($"Matrices provided cannot be multipled. Columns in matrix A: {matrix_a_dimensions.Columns} vs rows in matrix B: {matrix_b_dimensions.Rows}"); } var result = DTM.MatrixMultiplyDouble( DeviceId, a_op, b_op, alpha, a, b, beta); return(new CudaResult <double[][]>(result.Error, result.Result)); }
internal static (CudaError Error, double[][] Result) MatrixMultiplyDouble( int device_id, CUBLAS_OP a_op, CUBLAS_OP b_op, double alpha, double[][] a, double[][] b, double beta) { // .NET does not support marshaling nested arrays between C++ and e.g. C#. // If you try, you will get the error message, "There is no marshaling support for nested arrays." // Further, the cuBLAS function cublasSgemm/cublasDgemm does not have pointer-to-pointers as arguments (e.g., float**), so we cannot // supply a multidimensional array anyway. // The solution: flatten arrays so that they can passed to CudaSharperLibrary, and then unflatten whatever it passes back. var d_a = FlattenArray(a.Length, a[0].Length, a); var d_b = FlattenArray(b.Length, b[0].Length, b); // C(m,n) = A(m,k) * B(k,n) // Despite the definition above, this will return the correct size for C. Go figure. var d_c = new double[a.Length * b.Length]; var transa_op = (int)a_op; var transb_op = (int)b_op; var error = SafeNativeMethods.MatrixMultiplyDouble( device_id, transa_op, transb_op, a.Length, b[0].Length, a[0].Length, alpha, d_a, d_b, beta, d_c); return(CudaErrorCodes(error), UnflattenArray(a.Length, b.Length, d_c)); }
private (int Rows, int Columns) MatrixSizeByOperation(int rows, int columns, CUBLAS_OP operation) { int matrix_rows = 0; int matric_columns = 0; switch (operation) { case CUBLAS_OP.DO_NOT_TRANSPOSE: matrix_rows = rows; matric_columns = columns; break; case CUBLAS_OP.TRANSPOSE: matrix_rows = columns; matric_columns = rows; break; } return(matrix_rows, matric_columns); }