Sto cercando di calcolare il determinante di una matrice (di qualsiasi dimensione), per la pratica di codifica/intervista. Il mio primo tentativo sta usando la ricorsione e che mi porta alla seguente applicazione:Determinante della matrice di calcolo
import java.util.Scanner.*;
public class Determinant {
double A[][];
double m[][];
int N;
int start;
int last;
public Determinant (double A[][], int N, int start, int last){
this.A = A;
this.N = N;
this.start = start;
this.last = last;
}
public double[][] generateSubArray (double A[][], int N, int j1){
m = new double[N-1][];
for (int k=0; k<(N-1); k++)
m[k] = new double[N-1];
for (int i=1; i<N; i++)
{
int j2=0;
for (int j=0; j<N; j++)
{
if(j == j1)
continue;
m[i-1][j2] = A[i][j];
j2++;
}
}
return m;
}
/*
* Calculate determinant recursively
*/
public double determinant(double A[][], int N)
{
double res;
// Trivial 1x1 matrix
if (N == 1)
res = A[0][0];
// Trivial 2x2 matrix
else if (N == 2)
res = A[0][0]*A[1][1] - A[1][0]*A[0][1];
// NxN matrix
else
{
res=0;
for (int j1=0; j1<N; j1++)
{
m = generateSubArray (A, N, j1);
res += Math.pow(-1.0, 1.0+j1+1.0) * A[0][j1] * determinant(m, N-1);
}
}
return res;
}
}
Finora è tutto buono e mi dà un risultato corretto. Ora vorrei ottimizzare il mio codice facendo uso di più thread per calcolare questo valore determinante. Ho provato a farlo parallelizzare usando il modello Java Fork/Join. Questo è il mio approccio:
@Override
protected Double compute() {
if (N < THRESHOLD) {
result = computeDeterminant(A, N);
return result;
}
for (int j1 = 0; j1 < N; j1++){
m = generateSubArray (A, N, j1);
ParallelDeterminants d = new ParallelDeterminants (m, N-1);
d.fork();
result += Math.pow(-1.0, 1.0+j1+1.0) * A[0][j1] * d.join();
}
return result;
}
public double computeDeterminant(double A[][], int N)
{
double res;
// Trivial 1x1 matrix
if (N == 1)
res = A[0][0];
// Trivial 2x2 matrix
else if (N == 2)
res = A[0][0]*A[1][1] - A[1][0]*A[0][1];
// NxN matrix
else
{
res=0;
for (int j1=0; j1<N; j1++)
{
m = generateSubArray (A, N, j1);
res += Math.pow(-1.0, 1.0+j1+1.0) * A[0][j1] * computeDeterminant(m, N-1);
}
}
return res;
}
/*
* Main function
*/
public static void main(String args[])
{
double res;
ForkJoinPool pool = new ForkJoinPool();
ParallelDeterminants d = new ParallelDeterminants();
d.inputData();
long starttime=System.nanoTime();
res = pool.invoke (d);
long EndTime=System.nanoTime();
System.out.println("Seq Run = "+ (EndTime-starttime)/100000);
System.out.println("the determinant valaue is " + res);
}
Tuttavia dopo aver confrontato le prestazioni, ho trovato che le prestazioni della forcella/Join approccio è molto cattivo, e maggiore è la dimensione della matrice, più lenta diventa (come rispetto al primo approccio). Dov'è il sovraccarico? Qualcuno può far luce su come migliorare questo?
Prima di inserire i thread, interrompo l'allocazione nel ciclo. Un'opzione potrebbe essere quella di avere due parametri dell'array che determinano quali colonne e righe calcolare invece di N. –
Ti suggerirei di guardare alcuni algoritmi progettati per essere paralleli. Non ho seguito il tuo algoritmo ma nella mia esperienza si possono trovare molte intelligenti ottimizzazioni per problemi comuni cercando in giro. –