Exemplo n.º 1
0
        /// <summary>Computes the sum of two specific <see cref="DenseMatrix"/> objects, i.e. A + \alpha * B.
        /// </summary>
        /// <param name="a">The first matrix, i.e. 'A'.</param>
        /// <param name="b">The second matrix, i.e. 'B'.</param>
        /// <param name="scalar">The scalar \alpha.</param>
        /// <returns>The sum A + \alpha * B in its <see cref="DenseMatrix"/> representation.</returns>
        private static DenseMatrix Add(DenseMatrix a, DenseMatrix b, double scalar)
        {
            MatrixSpecialFunction.TestAdditionInput(a, b);

            int n = a.RowCount * a.ColumnCount;
            var y = new double[n];

            int rowCount    = a.RowCount;
            int columnCount = a.ColumnCount;

            if (a.m_TransposeState == BLAS.MatrixTransposeState.NoTranspose)
            {
                switch (b.m_TransposeState)
                {
                case BLAS.MatrixTransposeState.NoTranspose:
                    BLAS.Level1.dcopy(n, a.Data, y);
                    BLAS.Level1.daxpy(n, scalar, b.Data, y);
                    break;

                case BLAS.MatrixTransposeState.Transpose:
                    BLAS.Level1.dcopy(n, a.Data, y);
                    for (int i = 0; i < rowCount; i++)
                    {
                        BLAS.Level1.daxpy(columnCount, scalar, b.Data, y, 1, rowCount, i * b.m_RowCount, i);
                    }
                    break;

                default: throw new InvalidOperationException();
                }
                return(new DenseMatrix(rowCount, columnCount, y));
            }
            else  // A^t
            {
                switch (b.m_TransposeState)
                {
                case BLAS.MatrixTransposeState.NoTranspose:
                    BLAS.Level1.dcopy(n, a.Data, y);
                    for (int i = 0; i < rowCount; i++)
                    {
                        BLAS.Level1.daxpy(columnCount, scalar, b.Data, y, 1, rowCount, i * b.m_RowCount, i);
                    }
                    break;

                case BLAS.MatrixTransposeState.Transpose:
                    BLAS.Level1.dcopy(n, a.Data, y);
                    BLAS.Level1.daxpy(n, scalar, b.Data, y);
                    break;

                default: throw new InvalidOperationException();
                }
                return(new DenseMatrix(rowCount, columnCount, y, BLAS.MatrixTransposeState.Transpose));
            }
        }
Exemplo n.º 2
0
        /// <summary>The multiplication of two <see cref="DenseMatrix"/> objects, i.e. A * B.
        /// </summary>
        /// <param name="a">The first dense matrix A.</param>
        /// <param name="b">The second dense matrix B.</param>
        /// <returns>The result of the operator, i.e. A * B.</returns>
        /// <exception cref="ArgumentNullException">Thrown, if <paramref name="a"/> or <paramref name="b"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">Thrown, if the matrix operation A * B can not be place because of unsuited arguments.</exception>
        public static DenseMatrix operator *(DenseMatrix a, DenseMatrix b)
        {
            MatrixSpecialFunction.TestMultiplicationInput(a, b);

            int m = a.RowCount;    // number of rows of op(A) and C
            int n = b.ColumnCount; // number of columns of op(B) and C
            int k = a.ColumnCount; // number of columns of op(A) = number of rows of op(B)

            var c = new double[n * m];

            BLAS.Level3.dgemm(m, n, k, 1.0, a.m_Data, b.m_Data, 0.0, c, a.m_TransposeState, b.m_TransposeState);

            return(new DenseMatrix(m, n, c));
        }
Exemplo n.º 3
0
        /// <summary>Gets 'C = C + \alpha * A, where 'C' represents the matrix specified by the current instance. The current instance will be changed.
        /// </summary>
        /// <param name="a">The dense matrix 'A' to add.</param>
        /// <param name="alpha">The scalar factor \alpha.</param>
        /// <returns>The result of the operation, i.e. '\alpha * A + this', which is a reference to the current instance.</returns>
        /// <exception cref="ArgumentNullException">Thrown, if <paramref name="a"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">Thrown, if the number of rows/columns of <paramref name="a"/> does not coincide with the number of rows/columns of the matrix given by the current instance.</exception>
        /// <remarks>The current object will be changed and a reference to the current object will be returned.
        /// <para>
        ///    Use this method for some '+=' or '-=' operator which may performs better than some separate addition.
        /// </para></remarks>
        public DenseMatrix AddAssignment(DenseMatrix a, double alpha = 1.0)
        {
            MatrixSpecialFunction.TestAdditionInput(this, a);
            if (m_TransposeState == BLAS.MatrixTransposeState.NoTranspose)
            {
                switch (a.m_TransposeState)
                {
                case BLAS.MatrixTransposeState.NoTranspose:
                    BLAS.Level1.daxpy(m_RowCount * m_ColumnCount, alpha, a.m_Data, m_Data);
                    break;

                case BLAS.MatrixTransposeState.Transpose:     // c[i+j*m_RowCount] += \alpha * a[j+i*a.m_RowCount] for i=0,..,m_RowCount-1, j=0,..,m_ColumnCount-1
                    double[] aData = a.Data;
                    for (int i = 0; i < m_RowCount; i++)
                    {
                        BLAS.Level1.daxpy(m_ColumnCount, alpha, aData, m_Data, 1, m_RowCount, i * a.m_RowCount, i);
                    }
                    break;

                default: throw new InvalidOperationException();
                }
            }
            else if (m_TransposeState == BLAS.MatrixTransposeState.Transpose)
            {
                switch (a.m_TransposeState)
                {
                case BLAS.MatrixTransposeState.Transpose:
                    BLAS.Level1.daxpy(m_RowCount * m_ColumnCount, alpha, a.m_Data, m_Data);
                    break;

                case BLAS.MatrixTransposeState.NoTranspose:
                    for (int i = 0; i < m_RowCount; i++)
                    {
                        BLAS.Level1.daxpy(m_ColumnCount, alpha, a.m_Data, m_Data, a.m_RowCount, 1, i, i * m_RowCount);     //    m_Data[j + i * m_RowCount] += alpha * a.m_Data[i + j * a.m_RowCount] for j \in [0, m_ColumnCount),
                    }
                    break;

                default: throw new InvalidOperationException();
                }
            }
            else
            {
                throw new InvalidOperationException();
            }
            return(this);
        }
Exemplo n.º 4
0
        /// <summary>Gets C = \alpha * (A * B) + \beta * C, where C represents the matrix specified by the current instance. The current instance will be changed.
        /// </summary>
        /// <param name="a">The dense matrix A.</param>
        /// <param name="b">The dense matrix B.</param>
        /// <param name="alpha">The scalar factor \alpha.</param>
        /// <param name="beta">The scalar factor \beta.</param>
        /// <returns>The result of the operation, i.e. \alpha * (A * B) + \beta * this, which is a reference to the current instance.</returns>
        /// <exception cref="ArgumentNullException">Thrown, if <paramref name="a"/> or <paramref name="b"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">Thrown, if the number of row/columns of <paramref name="a"/> and <paramref name="b"/> is not allowed for the operation.</exception>
        /// <remarks>The current object will be changed.</remarks>
        public DenseMatrix AddAssignment(DenseMatrix a, DenseMatrix b, double alpha = 1.0, double beta = 1.0)
        {
            MatrixSpecialFunction.TestMultiplicationInput(a, b);

            if (m_TransposeState == BLAS.MatrixTransposeState.Transpose)
            {
                T_InPlace();  // re-sort the matrix represented by the current instance and swap #rows vs. #columns. This allows the application of BLAS level 3 routine in the next step
            }
            int m = a.RowCount;
            int n = b.ColumnCount;
            int k = a.ColumnCount;

            if (m != m_RowCount)
            {
                throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, ExceptionMessages.ArgumentCombinationInvalid, "RowCount, A.RowCount"));
            }
            if (n != m_ColumnCount)
            {
                throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, ExceptionMessages.ArgumentCombinationInvalid, "ColumnCount, B.ColumnCount"));
            }
            BLAS.Level3.dgemm(m, n, k, alpha, a.m_Data, b.m_Data, beta, m_Data, a.m_TransposeState, b.m_TransposeState);
            return(this);
        }
Exemplo n.º 5
0
        /// <summary>Multiplies a diagonal matrix with a dense matrix.
        /// </summary>
        /// <param name="denseMatrix">The dense matrix (left side).</param>
        /// <param name="diagonalMatrix">The diagonal matrix (right side).</param>
        /// <returns>The <see cref="DenseMatrix"/> object that represents the product of both specified matrices.</returns>
        public static DenseMatrix operator *(DenseMatrix denseMatrix, DiagonalMatrix diagonalMatrix)
        {
            MatrixSpecialFunction.TestMultiplicationInput(denseMatrix, diagonalMatrix);

            int rowCount    = denseMatrix.RowCount;
            int columnCount = denseMatrix.ColumnCount;

            var data = new double[rowCount * columnCount];

            switch (denseMatrix.DataTransposeState)
            {
            case BLAS.MatrixTransposeState.NoTranspose:      // here, we use BLAS functions to speed up operation
                BLAS.Level1.dcopy(rowCount * columnCount, denseMatrix.Data, data);

                for (int j = 0; j < columnCount; j++)
                {
                    BLAS.Level1.dscal(rowCount, diagonalMatrix[j, j], data, 1, rowCount * j);      // c[i + RowCount * j] *= diagonal[j,j]
                }
                break;

            case BLAS.MatrixTransposeState.Transpose:
                for (int j = 0; j < columnCount; j++)
                {
                    double diagonalFactor = diagonalMatrix[j, j];
                    for (int i = 0; i < rowCount; i++)
                    {
                        data[i + rowCount * j] = denseMatrix[i, j] * diagonalFactor;
                    }
                }
                break;

            default:
                throw new NotImplementedException();
            }
            return(new DenseMatrix(rowCount, columnCount, data));
        }
Exemplo n.º 6
0
        /// <summary>Gets C = C + \alpha * A, where C represents the matrix specified by the current instance. The current instance will be changed.
        /// </summary>
        /// <param name="a">The general band matrix A to add.</param>
        /// <param name="alpha">The scalar factor \alpha.</param>
        /// <returns>The result of the operation, i.e. \alpha * A + this, which is just a reference of the current instance.</returns>
        /// <exception cref="ArgumentNullException">Thrown, if <paramref name="a"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">Thrown, if the number of rows/columns of A does not coincide with the number of rows/columns of the matrix given by the current instance.</exception>
        /// <remarks>The current object will be changed and a reference to the current object will be returned.
        /// <para>
        ///    Use this method for some '+=' or '-=' operator which may performs better than some separate addition.
        /// </para></remarks>
        public DenseMatrix AddAssignment(GeneralBandMatrix a, double alpha = 1.0)
        {
            MatrixSpecialFunction.TestAdditionInput(this, a);

            int superPlusSubPlusMainDiagonalCount = a.SuperDiagonalCount + a.SubDiagonalCount + 1;

            if (m_TransposeState == BLAS.MatrixTransposeState.NoTranspose)
            {
                switch (a.DataTransposeState)
                {
                case BLAS.MatrixTransposeState.NoTranspose:
                    for (int j = 0; j < m_ColumnCount; j++)
                    {
                        int iMin = System.Math.Max(0, j - a.SuperDiagonalCount);
                        int iMax = System.Math.Min(m_RowCount - 1, j + a.SubDiagonalCount);

                        for (int i = iMin; i <= iMax; i++)
                        {
                            m_Data[i + m_RowCount * j] += alpha * a.Data[j * superPlusSubPlusMainDiagonalCount + (i - j + a.SuperDiagonalCount)];
                        }
                    }
                    break;

                case BLAS.MatrixTransposeState.Transpose:
                    for (int j = 0; j < m_ColumnCount; j++)
                    {
                        int iMin = System.Math.Max(0, j - a.SuperDiagonalCount);
                        int iMax = System.Math.Min(m_RowCount - 1, j + a.SubDiagonalCount);

                        for (int i = iMin; i <= iMax; i++)
                        {
                            m_Data[i + m_RowCount * j] += alpha * a.Data[i * superPlusSubPlusMainDiagonalCount + (j - i + a.SuperDiagonalCount)];
                        }
                    }
                    break;

                default: throw new InvalidOperationException();
                }
            }
            else if (m_TransposeState == BLAS.MatrixTransposeState.Transpose)
            {
                switch (a.DataTransposeState)
                {
                case BLAS.MatrixTransposeState.NoTranspose:
                    for (int j = 0; j < ColumnCount; j++)      // Property 'ColumnCount' returns the value of m_RowCount
                    {
                        int iMin = System.Math.Max(0, j - a.SuperDiagonalCount);
                        int iMax = System.Math.Min(RowCount - 1, j + a.SubDiagonalCount);

                        for (int i = iMin; i <= iMax; i++)
                        {
                            m_Data[j + m_RowCount * i] += alpha * a.Data[j * superPlusSubPlusMainDiagonalCount + (i - j + a.SuperDiagonalCount)];
                        }
                    }
                    break;

                case BLAS.MatrixTransposeState.Transpose:
                    for (int j = 0; j < ColumnCount; j++)      // Property 'ColumnCount' returns the value of m_RowCount
                    {
                        int iMin = System.Math.Max(0, j - a.SuperDiagonalCount);
                        int iMax = System.Math.Min(RowCount - 1, j + a.SubDiagonalCount);

                        for (int i = iMin; i <= iMax; i++)
                        {
                            m_Data[j + m_RowCount * i] += alpha * a.Data[i * superPlusSubPlusMainDiagonalCount + (j - i + a.SuperDiagonalCount)];
                        }
                    }
                    break;

                default: throw new InvalidOperationException();
                }
            }
            else
            {
                throw new InvalidOperationException();
            }
            return(this);
        }
Exemplo n.º 7
0
        /// <summary>The addition of two <see cref="GeneralBandMatrix"/> objects, i.e. A + \alpha * B.
        /// </summary>
        /// <param name="a">The first general band matrix A.</param>
        /// <param name="b">The second general band matrix B.</param>
        /// <param name="scalar">The scalar \alpha.</param>
        /// <returns>The result of the operator, i.e. A + \alpha * B.</returns>
        /// <exception cref="ArgumentNullException">Thrown, if <paramref name="a"/> or <paramref name="b"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">Thrown, if the number of columns of <paramref name="a"/> does not coincide with the number of rows of <paramref name="b"/>.</exception>
        private static GeneralBandMatrix Add(GeneralBandMatrix a, GeneralBandMatrix b, double scalar)
        {
            MatrixSpecialFunction.TestAdditionInput(a, b);
            int subDiagonalCount = Math.Max(a.SubDiagonalCount, b.SubDiagonalCount);
            int superDiagonalCount = Math.Max(a.SuperDiagonalCount, b.SuperDiagonalCount);

            int rowCount = a.RowCount;
            int columnCount = a.ColumnCount;

            int length = rowCount * (subDiagonalCount + superDiagonalCount + 1);
            var c = new double[length];

            switch (a.m_TransposeState)
            {
                case BLAS.MatrixTransposeState.NoTranspose:
                    if (b.m_TransposeState == BLAS.MatrixTransposeState.NoTranspose)
                    {
                        for (int j = 0; j < columnCount; j++)
                        {
                            int offSetMatrixA = j * (a.m_SubDiagonalCount + a.m_SuperDiagonalCount + 1);
                            int offSetMatrixB = j * (b.m_SubDiagonalCount + b.m_SuperDiagonalCount + 1);
                            int offsetMatrixC = j * (subDiagonalCount + superDiagonalCount + 1);

                            for (int i = Math.Max(0, j - superDiagonalCount); i <= Math.Min(rowCount - 1, j + subDiagonalCount); i++)
                            {
                                double value = 0.0;
                                if ((i - j <= a.m_SubDiagonalCount) && (j - i <= a.m_SuperDiagonalCount))
                                {
                                    value += a.m_Data[i - j + a.m_SuperDiagonalCount + offSetMatrixA];
                                }
                                if ((i - j <= b.m_SubDiagonalCount) && (j - i <= b.m_SuperDiagonalCount))
                                {
                                    value += scalar * b.m_Data[i - j + b.m_SuperDiagonalCount + offSetMatrixB];
                                }
                                c[i - j + superDiagonalCount + offsetMatrixC] = value;
                            }
                        }
                    }
                    else
                    {
                        int k = b.m_SubDiagonalCount + b.m_SuperDiagonalCount + 1;
                        for (int j = 0; j < columnCount; j++)
                        {
                            int offSetMatrixA = j * (a.m_SubDiagonalCount + a.m_SuperDiagonalCount + 1);
                            int offsetMatrixC = j * (subDiagonalCount + superDiagonalCount + 1);

                            for (int i = Math.Max(0, j - superDiagonalCount); i <= Math.Min(rowCount - 1, j + subDiagonalCount); i++)
                            {
                                double value = 0.0;
                                if ((i - j <= a.m_SubDiagonalCount) && (j - i <= a.m_SuperDiagonalCount))
                                {
                                    value += a.m_Data[i - j + a.m_SuperDiagonalCount + offSetMatrixA];
                                }
                                if ((i - j <= b.m_SubDiagonalCount) && (j - i <= b.m_SuperDiagonalCount))
                                {
                                    value += scalar * b.m_Data[j - i + b.m_SuperDiagonalCount + i * k];
                                }
                                c[i - j + superDiagonalCount + offsetMatrixC] = value;
                            }
                        }
                    }
                    break;

                case BLAS.MatrixTransposeState.Transpose:
                    if (b.m_TransposeState == BLAS.MatrixTransposeState.NoTranspose)
                    {
                        int k = a.m_SubDiagonalCount + a.m_SuperDiagonalCount + 1;

                        for (int j = 0; j < columnCount; j++)
                        {
                            int offSetMatrixB = j * (b.m_SubDiagonalCount + b.m_SuperDiagonalCount + 1);
                            int offsetMatrixC = j * (subDiagonalCount + superDiagonalCount + 1);

                            for (int i = Math.Max(0, j - superDiagonalCount); i <= Math.Min(rowCount - 1, j + subDiagonalCount); i++)
                            {
                                double value = 0.0;
                                if ((i - j <= a.m_SubDiagonalCount) && (j - i <= a.m_SuperDiagonalCount))
                                {
                                    value += a.m_Data[j - i + a.m_SuperDiagonalCount + i * k];
                                }
                                if ((i - j <= b.m_SubDiagonalCount) && (j - i <= b.m_SuperDiagonalCount))
                                {
                                    value += scalar * b.m_Data[i - j + b.m_SuperDiagonalCount + offSetMatrixB];
                                }
                                c[i - j + superDiagonalCount + offsetMatrixC] = value;
                            }
                        }
                    }
                    else
                    {
                        int ka = a.m_SubDiagonalCount + a.m_SuperDiagonalCount + 1;
                        int kb = b.m_SubDiagonalCount + b.m_SuperDiagonalCount + 1;
                        for (int j = 0; j < columnCount; j++)
                        {
                            int offsetMatrixC = j * (subDiagonalCount + superDiagonalCount + 1);

                            for (int i = Math.Max(0, j - superDiagonalCount); i <= Math.Min(rowCount - 1, j + subDiagonalCount); i++)
                            {
                                double value = 0.0;
                                if ((i - j <= a.m_SubDiagonalCount) && (j - i <= a.m_SuperDiagonalCount))
                                {
                                    value += a.m_Data[j - i + a.m_SuperDiagonalCount + i * ka];
                                }
                                if ((i - j <= b.m_SubDiagonalCount) && (j - i <= b.m_SuperDiagonalCount))
                                {
                                    value += scalar * b.m_Data[j - i + b.m_SuperDiagonalCount + i * kb];
                                }
                                c[i - j + superDiagonalCount + offsetMatrixC] = value;
                            }
                        }
                    }
                    break;

                default: throw new InvalidOperationException();
            }
            return new GeneralBandMatrix(rowCount, columnCount, subDiagonalCount, superDiagonalCount, c);
        }
Exemplo n.º 8
0
        /// <summary>The multiplication of two <see cref="GeneralBandMatrix"/> objects, i.e. A * B.
        /// </summary>
        /// <param name="a">The first general band matrix A.</param>
        /// <param name="b">The second general band matrix B.</param>
        /// <returns>The result of the operator, i.e. 'A * B'.</returns>
        /// <exception cref="ArgumentNullException">Thrown, if <paramref name="a"/> or <paramref name="b"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">Thrown, if the number of columns of <paramref name="a"/> does not coincide with the number of rows of <paramref name="b"/>.</exception>
        public static GeneralBandMatrix operator *(GeneralBandMatrix a, GeneralBandMatrix b)
        {
            MatrixSpecialFunction.TestMultiplicationInput(a, b);

            int n = b.ColumnCount;  // number of columns of op(B) and C
            int m = a.RowCount; // number of rows of op(A) and C
            int k = a.ColumnCount; // number of columns of op(A) = number of rows of op(B)

            int subDiagonalCountOpA = a.SubDiagonalCount;
            int superDiagonalCountOpA = a.SuperDiagonalCount;
            int subDiagonalCountOpB = b.SubDiagonalCount;
            int superDiagonalCountOpB = b.SuperDiagonalCount;

            if (b.RowCount != k)
            {
                throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, ExceptionMessages.ArgumentCombinationInvalid, "A.ColumnCount, B.RowCount"));
            }

            // determind the parameters for the result object and allocate memory
            int subDiagonalCount = Math.Max(0, subDiagonalCountOpA - superDiagonalCountOpB);
            int superDiagonalCount = Math.Max(0, superDiagonalCountOpA - subDiagonalCountOpB);

            int length = m * (subDiagonalCount + superDiagonalCount + 1);
            double[] c = new double[length];

            double[] aData = a.m_Data;
            double[] bData = b.m_Data;

            // do a second switch and calculate the result for each case:
            if ((a.m_TransposeState == BLAS.MatrixTransposeState.Transpose) && (b.m_TransposeState == BLAS.MatrixTransposeState.Transpose))
            {
                for (int j = 0; j < n; j++)
                {
                    int offsetMatrixA = j * (subDiagonalCountOpA + superDiagonalCountOpA + 1);
                    int offsetMatrixC = j * (subDiagonalCount + superDiagonalCount + 1);

                    for (int i = j - superDiagonalCount; i <= j + subDiagonalCount; i++)
                    {
                        double value = 0.0;
                        for (int s = Math.Max(i - subDiagonalCountOpA, j - superDiagonalCountOpB); s <= Math.Min(k, Math.Min(i + superDiagonalCountOpA, j + subDiagonalCountOpB)); s++)
                        {
                            value += aData[s - i + superDiagonalCountOpA + offsetMatrixA] * bData[j - s + superDiagonalCountOpB + s * (subDiagonalCountOpB + superDiagonalCountOpB + 1)];
                        }
                        c[i - j + superDiagonalCount + offsetMatrixC] = value;
                    }
                }
            }
            else if (a.m_TransposeState == BLAS.MatrixTransposeState.Transpose)
            {
                for (int j = 0; j < n; j++)
                {
                    int offsetMatrixA = j * (subDiagonalCountOpA + superDiagonalCountOpA + 1);
                    int offsetMatrixB = j * (subDiagonalCountOpB + superDiagonalCountOpB + 1);
                    int offsetMatrixC = j * (subDiagonalCount + superDiagonalCount + 1);

                    for (int i = j - superDiagonalCount; i <= j + subDiagonalCount; i++)
                    {
                        double value = 0.0;
                        for (int s = Math.Max(i - subDiagonalCountOpA, j - superDiagonalCountOpB); s <= Math.Min(k, Math.Min(i + superDiagonalCountOpA, j + subDiagonalCountOpB)); s++)
                        {
                            value += aData[s - i + superDiagonalCountOpA + offsetMatrixA] * bData[s - j + superDiagonalCountOpB + offsetMatrixB];
                        }
                        c[i - j + superDiagonalCount + offsetMatrixC] = value;
                    }
                }
            }
            else if (b.m_TransposeState == BLAS.MatrixTransposeState.Transpose)
            {
                for (int j = 0; j < n; j++)
                {
                    int offsetMatrixC = j * (subDiagonalCount + superDiagonalCount + 1);

                    for (int i = j - superDiagonalCount; i <= j + subDiagonalCount; i++)
                    {
                        double value = 0.0;
                        for (int s = Math.Max(i - subDiagonalCountOpA, j - superDiagonalCountOpB); s <= Math.Min(k, Math.Min(i + superDiagonalCountOpA, j + subDiagonalCountOpB)); s++)
                        {
                            value += aData[i - s + superDiagonalCountOpA + s * (subDiagonalCountOpA + superDiagonalCountOpA + 1)] * bData[j - s + superDiagonalCountOpB + s * (subDiagonalCountOpB + superDiagonalCountOpB + 1)];
                        }
                        c[i - j + superDiagonalCount + offsetMatrixC] = value;
                    }
                }
            }
            else  // op(A) = A, op(B) = B
            {
                for (int j = 0; j < n; j++)
                {
                    int offsetMatrixC = j * (subDiagonalCount + superDiagonalCount + 1);
                    int offsetMatrixB = j * (subDiagonalCountOpB + superDiagonalCountOpB + 1);

                    for (int i = j - superDiagonalCount; i <= j + subDiagonalCount; i++)
                    {
                        double value = 0.0;
                        for (int s = Math.Max(i - subDiagonalCountOpA, j - superDiagonalCountOpB); s <= Math.Min(k, Math.Min(i + superDiagonalCountOpA, j + subDiagonalCountOpB)); s++)
                        {
                            value += aData[i - s + superDiagonalCountOpA + s * (subDiagonalCountOpA + superDiagonalCountOpA + 1)] * bData[s - j + superDiagonalCountOpB + offsetMatrixB];
                        }
                        c[i - j + superDiagonalCount + offsetMatrixC] = value;
                    }
                }
            }
            return new GeneralBandMatrix(m, n, subDiagonalCount, superDiagonalCount, c);
        }