/*
 * Copyright (c) 2009-2020, Peter Abeles. All Rights Reserved.
 *
 * This file is part of Efficient Java Matrix Library (EJML).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.ejml.dense.block;

import org.ejml.data.DMatrixRBlock;

/**
 * <p>
 * Matrix multiplication for the inner row major blocks, typically inside of a {@link DMatrixRBlock}.
 * </p>
 *
 * <p>
 * This code was auto generated by GeneratorBlockInnerMultiplication and should not be modified directly.
 * </p>
 *
 * @author Peter Abeles
 */
public class InnerMultiplication_DDRB {

    /**
     * <p>
     * Performs the follow operation on individual inner blocks:<br>
     * <br>
     * C = C + A * B
     * </p>
     */
    public static void blockMultPlus( final double[] dataA, final double[] dataB, final double[] dataC,
                                      int indexA, int indexB, int indexC,
                                      final int heightA, final int widthA, final int widthC ) {
//        for( int i = 0; i < heightA; i++ ) {
//            for( int k = 0; k < widthA; k++ ) {
//                for( int j = 0; j < widthC; j++ ) {
//                    dataC[ i*widthC + j + indexC ] += dataA[i*widthA + k + indexA] * dataB[k*widthC + j + indexB];
//                }
//            }
//        }

        int a = indexA;
        int rowC = indexC;
        for (int i = 0; i < heightA; i++, rowC += widthC) {
            int b = indexB;

            final int endC = rowC + widthC;
            final int endA = a + widthA;
            while (a != endA) {//for( int k = 0; k < widthA; k++ ) {
                double valA = dataA[a++];

                int c = rowC;

                while (c != endC) {//for( int j = 0; j < widthC; j++ ) {
                    dataC[c++] += valA*dataB[b++];
                }
            }
        }
    }

    /**
     * <p>
     * Performs the follow operation on individual inner blocks:<br>
     * <br>
     * C = C + A<sup>T</sup> * B
     * </p>
     */
    public static void blockMultPlusTransA( final double[] dataA, final double[] dataB, final double[] dataC,
                                            int indexA, int indexB, int indexC,
                                            final int heightA, final int widthA, final int widthC ) {
//        for( int i = 0; i < widthA; i++ ) {
//            for( int k = 0; k < heightA; k++ ) {
//                double valA = dataA[k*widthA + i + indexA];
//                for( int j = 0; j < widthC; j++ ) {
//                    dataC[ i*widthC + j + indexC ] += valA * dataB[k*widthC + j + indexB];
//                }
//            }
//        }

        int rowC = indexC;
        for (int i = 0; i < widthA; i++, rowC += widthC) {
            int colA = i + indexA;
            int endA = colA + widthA*heightA;
            int b = indexB;

            // for( int k = 0; k < heightA; k++ ) {
            while (colA != endA) {
                double valA = dataA[colA];

                int c = rowC;
                final int endB = b + widthC;

                //for( int j = 0; j < widthC; j++ ) {
                while (b != endB) {
                    dataC[c++] += valA*dataB[b++];
                }
                colA += widthA;
            }
        }
    }

    /**
     * <p>
     * Performs the follow operation on individual inner blocks:<br>
     * <br>
     * C = C + A * B<sup>T</sup>
     * </p>
     */
    public static void blockMultPlusTransB( final double[] dataA, final double[] dataB, final double[] dataC,
                                            int indexA, int indexB, int indexC,
                                            final int heightA, final int widthA, final int widthC ) {
        for (int i = 0; i < heightA; i++) {
            for (int j = 0; j < widthC; j++) {
                double val = 0;

                for (int k = 0; k < widthA; k++) {
                    val += dataA[i*widthA + k + indexA]*dataB[j*widthA + k + indexB];
                }

                dataC[i*widthC + j + indexC] += val;
            }
        }
    }

    /**
     * <p>
     * Performs the follow operation on individual inner blocks:<br>
     * <br>
     * C = C - A * B
     * </p>
     */
    public static void blockMultMinus( final double[] dataA, final double[] dataB, final double[] dataC,
                                       int indexA, int indexB, int indexC,
                                       final int heightA, final int widthA, final int widthC ) {
//        for( int i = 0; i < heightA; i++ ) {
//            for( int k = 0; k < widthA; k++ ) {
//                for( int j = 0; j < widthC; j++ ) {
//                    dataC[ i*widthC + j + indexC ] += dataA[i*widthA + k + indexA] * dataB[k*widthC + j + indexB];
//                }
//            }
//        }

        int a = indexA;
        int rowC = indexC;
        for (int i = 0; i < heightA; i++, rowC += widthC) {
            int b = indexB;

            final int endC = rowC + widthC;
            final int endA = a + widthA;
            while (a != endA) {//for( int k = 0; k < widthA; k++ ) {
                double valA = dataA[a++];

                int c = rowC;

                while (c != endC) {//for( int j = 0; j < widthC; j++ ) {
                    dataC[c++] -= valA*dataB[b++];
                }
            }
        }
    }

    /**
     * <p>
     * Performs the follow operation on individual inner blocks:<br>
     * <br>
     * C = C - A<sup>T</sup> * B
     * </p>
     */
    public static void blockMultMinusTransA( final double[] dataA, final double[] dataB, final double[] dataC,
                                             int indexA, int indexB, int indexC,
                                             final int heightA, final int widthA, final int widthC ) {
//        for( int i = 0; i < widthA; i++ ) {
//            for( int k = 0; k < heightA; k++ ) {
//                double valA = dataA[k*widthA + i + indexA];
//                for( int j = 0; j < widthC; j++ ) {
//                    dataC[ i*widthC + j + indexC ] += valA * dataB[k*widthC + j + indexB];
//                }
//            }
//        }

        int rowC = indexC;
        for (int i = 0; i < widthA; i++, rowC += widthC) {
            int colA = i + indexA;
            int endA = colA + widthA*heightA;
            int b = indexB;

            // for( int k = 0; k < heightA; k++ ) {
            while (colA != endA) {
                double valA = dataA[colA];

                int c = rowC;
                final int endB = b + widthC;

                //for( int j = 0; j < widthC; j++ ) {
                while (b != endB) {
                    dataC[c++] -= valA*dataB[b++];
                }
                colA += widthA;
            }
        }
    }

    /**
     * <p>
     * Performs the follow operation on individual inner blocks:<br>
     * <br>
     * C = C - A * B<sup>T</sup>
     * </p>
     */
    public static void blockMultMinusTransB( final double[] dataA, final double[] dataB, final double[] dataC,
                                             int indexA, int indexB, int indexC,
                                             final int heightA, final int widthA, final int widthC ) {
        for (int i = 0; i < heightA; i++) {
            for (int j = 0; j < widthC; j++) {
                double val = 0;

                for (int k = 0; k < widthA; k++) {
                    val += dataA[i*widthA + k + indexA]*dataB[j*widthA + k + indexB];
                }

                dataC[i*widthC + j + indexC] -= val;
            }
        }
    }

    /**
     * <p>
     * Performs the follow operation on individual inner blocks:<br>
     * <br>
     * C = A * B
     * </p>
     */
    public static void blockMultSet( final double[] dataA, final double[] dataB, final double[] dataC,
                                     int indexA, int indexB, int indexC,
                                     final int heightA, final int widthA, final int widthC ) {
//        for( int i = 0; i < heightA; i++ ) {
//            for( int k = 0; k < widthA; k++ ) {
//                for( int j = 0; j < widthC; j++ ) {
//                    dataC[ i*widthC + j + indexC ] += dataA[i*widthA + k + indexA] * dataB[k*widthC + j + indexB];
//                }
//            }
//        }

        int a = indexA;
        int rowC = indexC;
        for (int i = 0; i < heightA; i++, rowC += widthC) {
            int b = indexB;

            final int endC = rowC + widthC;
            final int endA = a + widthA;
            while (a != endA) {//for( int k = 0; k < widthA; k++ ) {
                double valA = dataA[a++];

                int c = rowC;

                if (b == indexB) {
                    while (c != endC) {//for( int j = 0; j < widthC; j++ ) {
                        dataC[c++] = valA*dataB[b++];
                    }
                } else {
                    while (c != endC) {//for( int j = 0; j < widthC; j++ ) {
                        dataC[c++] += valA*dataB[b++];
                    }
                }
            }
        }
    }

    /**
     * <p>
     * Performs the follow operation on individual inner blocks:<br>
     * <br>
     * C = A<sup>T</sup> * B
     * </p>
     */
    public static void blockMultSetTransA( final double[] dataA, final double[] dataB, final double[] dataC,
                                           int indexA, int indexB, int indexC,
                                           final int heightA, final int widthA, final int widthC ) {
//        for( int i = 0; i < widthA; i++ ) {
//            for( int k = 0; k < heightA; k++ ) {
//                double valA = dataA[k*widthA + i + indexA];
//                for( int j = 0; j < widthC; j++ ) {
//                    dataC[ i*widthC + j + indexC ] += valA * dataB[k*widthC + j + indexB];
//                }
//            }
//        }

        int rowC = indexC;
        for (int i = 0; i < widthA; i++, rowC += widthC) {
            int colA = i + indexA;
            int endA = colA + widthA*heightA;
            int b = indexB;

            // for( int k = 0; k < heightA; k++ ) {
            while (colA != endA) {
                double valA = dataA[colA];

                int c = rowC;
                final int endB = b + widthC;

                //for( int j = 0; j < widthC; j++ ) {
                if (b == indexB) {
                    while (b != endB) {
                        dataC[c++] = valA*dataB[b++];
                    }
                } else {
                    while (b != endB) {
                        dataC[c++] += valA*dataB[b++];
                    }
                }
                colA += widthA;
            }
        }
    }

    /**
     * <p>
     * Performs the follow operation on individual inner blocks:<br>
     * <br>
     * C = A * B<sup>T</sup>
     * </p>
     */
    public static void blockMultSetTransB( final double[] dataA, final double[] dataB, final double[] dataC,
                                           int indexA, int indexB, int indexC,
                                           final int heightA, final int widthA, final int widthC ) {
        for (int i = 0; i < heightA; i++) {
            for (int j = 0; j < widthC; j++) {
                double val = 0;

                for (int k = 0; k < widthA; k++) {
                    val += dataA[i*widthA + k + indexA]*dataB[j*widthA + k + indexB];
                }

                dataC[i*widthC + j + indexC] = val;
            }
        }
    }

    /**
     * <p>
     * Performs the follow operation on individual inner blocks:<br>
     * <br>
     * C = C +  &alpha; A * B
     * </p>
     */
    public static void blockMultPlus( double alpha, final double[] dataA, final double[] dataB, final double[] dataC,
                                      int indexA, int indexB, int indexC,
                                      final int heightA, final int widthA, final int widthC ) {
//        for( int i = 0; i < heightA; i++ ) {
//            for( int k = 0; k < widthA; k++ ) {
//                for( int j = 0; j < widthC; j++ ) {
//                    dataC[ i*widthC + j + indexC ] += dataA[i*widthA + k + indexA] * dataB[k*widthC + j + indexB];
//                }
//            }
//        }

        int a = indexA;
        int rowC = indexC;
        for (int i = 0; i < heightA; i++, rowC += widthC) {
            int b = indexB;

            final int endC = rowC + widthC;
            final int endA = a + widthA;
            while (a != endA) {//for( int k = 0; k < widthA; k++ ) {
                double valA = alpha*dataA[a++];

                int c = rowC;

                while (c != endC) {//for( int j = 0; j < widthC; j++ ) {
                    dataC[c++] += valA*dataB[b++];
                }
            }
        }
    }

    /**
     * <p>
     * Performs the follow operation on individual inner blocks:<br>
     * <br>
     * C = C +  &alpha; A<sup>T</sup> * B
     * </p>
     */
    public static void blockMultPlusTransA( double alpha, final double[] dataA, final double[] dataB, final double[] dataC,
                                            int indexA, int indexB, int indexC,
                                            final int heightA, final int widthA, final int widthC ) {
//        for( int i = 0; i < widthA; i++ ) {
//            for( int k = 0; k < heightA; k++ ) {
//                double valA = dataA[k*widthA + i + indexA];
//                for( int j = 0; j < widthC; j++ ) {
//                    dataC[ i*widthC + j + indexC ] += valA * dataB[k*widthC + j + indexB];
//                }
//            }
//        }

        int rowC = indexC;
        for (int i = 0; i < widthA; i++, rowC += widthC) {
            int colA = i + indexA;
            int endA = colA + widthA*heightA;
            int b = indexB;

            // for( int k = 0; k < heightA; k++ ) {
            while (colA != endA) {
                double valA = alpha*dataA[colA];

                int c = rowC;
                final int endB = b + widthC;

                //for( int j = 0; j < widthC; j++ ) {
                while (b != endB) {
                    dataC[c++] += valA*dataB[b++];
                }
                colA += widthA;
            }
        }
    }

    /**
     * <p>
     * Performs the follow operation on individual inner blocks:<br>
     * <br>
     * C = C +  &alpha; A * B<sup>T</sup>
     * </p>
     */
    public static void blockMultPlusTransB( double alpha, final double[] dataA, final double[] dataB, final double[] dataC,
                                            int indexA, int indexB, int indexC,
                                            final int heightA, final int widthA, final int widthC ) {
        for (int i = 0; i < heightA; i++) {
            for (int j = 0; j < widthC; j++) {
                double val = 0;

                for (int k = 0; k < widthA; k++) {
                    val += dataA[i*widthA + k + indexA]*dataB[j*widthA + k + indexB];
                }

                dataC[i*widthC + j + indexC] += alpha*val;
            }
        }
    }

    /**
     * <p>
     * Performs the follow operation on individual inner blocks:<br>
     * <br>
     * C =  &alpha; A * B
     * </p>
     */
    public static void blockMultSet( double alpha, final double[] dataA, final double[] dataB, final double[] dataC,
                                     int indexA, int indexB, int indexC,
                                     final int heightA, final int widthA, final int widthC ) {
//        for( int i = 0; i < heightA; i++ ) {
//            for( int k = 0; k < widthA; k++ ) {
//                for( int j = 0; j < widthC; j++ ) {
//                    dataC[ i*widthC + j + indexC ] += dataA[i*widthA + k + indexA] * dataB[k*widthC + j + indexB];
//                }
//            }
//        }

        int a = indexA;
        int rowC = indexC;
        for (int i = 0; i < heightA; i++, rowC += widthC) {
            int b = indexB;

            final int endC = rowC + widthC;
            final int endA = a + widthA;
            while (a != endA) {//for( int k = 0; k < widthA; k++ ) {
                double valA = alpha*dataA[a++];

                int c = rowC;

                if (b == indexB) {
                    while (c != endC) {//for( int j = 0; j < widthC; j++ ) {
                        dataC[c++] = valA*dataB[b++];
                    }
                } else {
                    while (c != endC) {//for( int j = 0; j < widthC; j++ ) {
                        dataC[c++] += valA*dataB[b++];
                    }
                }
            }
        }
    }

    /**
     * <p>
     * Performs the follow operation on individual inner blocks:<br>
     * <br>
     * C =  &alpha; A<sup>T</sup> * B
     * </p>
     */
    public static void blockMultSetTransA( double alpha, final double[] dataA, final double[] dataB, final double[] dataC,
                                           int indexA, int indexB, int indexC,
                                           final int heightA, final int widthA, final int widthC ) {
//        for( int i = 0; i < widthA; i++ ) {
//            for( int k = 0; k < heightA; k++ ) {
//                double valA = dataA[k*widthA + i + indexA];
//                for( int j = 0; j < widthC; j++ ) {
//                    dataC[ i*widthC + j + indexC ] += valA * dataB[k*widthC + j + indexB];
//                }
//            }
//        }

        int rowC = indexC;
        for (int i = 0; i < widthA; i++, rowC += widthC) {
            int colA = i + indexA;
            int endA = colA + widthA*heightA;
            int b = indexB;

            // for( int k = 0; k < heightA; k++ ) {
            while (colA != endA) {
                double valA = alpha*dataA[colA];

                int c = rowC;
                final int endB = b + widthC;

                //for( int j = 0; j < widthC; j++ ) {
                if (b == indexB) {
                    while (b != endB) {
                        dataC[c++] = valA*dataB[b++];
                    }
                } else {
                    while (b != endB) {
                        dataC[c++] += valA*dataB[b++];
                    }
                }
                colA += widthA;
            }
        }
    }

    /**
     * <p>
     * Performs the follow operation on individual inner blocks:<br>
     * <br>
     * C =  &alpha; A * B<sup>T</sup>
     * </p>
     */
    public static void blockMultSetTransB( double alpha, final double[] dataA, final double[] dataB, final double[] dataC,
                                           int indexA, int indexB, int indexC,
                                           final int heightA, final int widthA, final int widthC ) {
        for (int i = 0; i < heightA; i++) {
            for (int j = 0; j < widthC; j++) {
                double val = 0;

                for (int k = 0; k < widthA; k++) {
                    val += dataA[i*widthA + k + indexA]*dataB[j*widthA + k + indexB];
                }

                dataC[i*widthC + j + indexC] = alpha*val;
            }
        }
    }
}
