/**
 * Parallel Matrix Multiplication. 
 * Using specified number of threads.
 * @author Heinz Kredel.
 */

public class ParMultProc implements MMInf {

    int anzahl = 1;

    public ParMultProc(int threads) {
         anzahl = threads;	
    }


/**
 * Performs the multiplication of two matrices.
 * C = A * B.
 * @param C result matrix.
 * @param A matrix.
 * @param B matrix.
 */
    public void multiply(double[][] C, double[][] A, double[][] B) {
      Thread[] t = new Thread[anzahl];
      System.out.print("Starting " + anzahl + " threads ...");
      for (int i=0; i < anzahl; i++) {
          t[i] = new RowMultProc(C,A,B,i,anzahl);
          t[i].start();
      }
      System.out.print(" started ...");
      for (int i=0; i < anzahl; i++) {
          try { t[i].join(); }
          catch (InterruptedException e) { }
      }
      System.out.println(" done ParMultProc");
    }

}


/**
 * This class is derived from the class Thread.
 * It performs a row multiplication.
 */
class RowMultProc extends Thread {

    double[][] A;
    double[][] B;
    double[][] C;
    int i;  
    int anzahl;

/**
 * Constructor.
 * @param Cp Two dimensional matrices.
 * @param Ap Two dimensional matrices.
 * @param Bp Two dimensional matrices.
 */
  RowMultProc(double[][] Cp, double[][] Ap, double[][] Bp, int ip, int a) {
    A = Ap; B = Bp; C = Cp; i = ip; anzahl = a;
  }

/**
 * Runs the multiplication.
 */
  public void run() {
    int schritte = A.length / anzahl; 
    if ( (A.length % anzahl) != 0 ) {
        schritte++; // ceiling
    }
    for (int ii = i*schritte; ii < Math.min((i+1)*schritte,A.length); ii++ ) {
        double[] Ai = A[i];
        for (int j=0; j < B[0].length; j++) {
            double c = 0.0;
            for (int k=0; k < B.length; k++) {
                 c += A[ii][k] * B[k][j];
            }
            C[ii][j] = c;
        }
    }
  }

}
