2016-12-25 2 views
2

J'ai un devoir qui nécessite de mettre en œuvre une version séquentielle et parallèle d'un solveur de sudoku en Java (en utilisant le Framework ForkJoin pour le parallèle).Solveur de Sudoku parallèle en Java

J'ai écrit le séquentiel et ça marche bien. L'idée algorithmique est un simple retour en arrière: pour chaque cellule (à partir du coin supérieur gauche de la table) non remplie, remplissez-la (séquentiellement, et une à la fois) avec tous les candidats légaux (entier de 1 à 9) jusqu'à la fin (rangée 9 col 9) de la matrice. Si vous avez atteint la fin, augmente le nombre de solutions.

Je pensais implémenter la version parallèle juste en engendrant un nouveau thread pour chaque candidat valide trouvé pour une cellule particulière, puis en les attendant .. Il semble ne pas fonctionner et je n'ai pas pu trouver la raison.

je poste la classe qui devrait faire tout le travail avec l'espoir de trouver un bon conseil:

class SolveSudoku extends RecursiveAction{ 
    private int i, j; 
    private int[][] cells; 

    SolveSudoku(int i, int j, int[][] cells){ 
     this.i = i; 
     this.j = j; 
     this.cells = cells; 
    } 

    @Override 
    protected void compute(){ 
     if (j == 9) { 
      j = 0; 
      if (++i == 9){ 
       solutions++; 
       System.out.println(solutions); 
       return; 
      } 
     } 

     if (cells[i][j] != 0){        // skip filled cells 
      SolveSudoku s = new SolveSudoku(i, j+1, cells); 
      s.compute(); 
      return; 
     } 


     ArrayList<Integer> vals = new ArrayList<Integer>(); 
     for (int val = 1; val <= 9; val++)     // try all the legal candidates for i, j 
      if (legal(i,j,val,cells)) 
       vals.add(val); 


     if(vals.size() == 1){       // only one, no new threads 
      cells[i][j] = vals.get(0); 
      new SolveSudoku(i, j+1, cells).compute(); 
     } 
     else{ 
      SolveSudoku threads[] = new SolveSudoku[vals.size()]; 
      int n = 0; 
      int first; 
      for(int k=0; k<vals.size(); k++){ 
       if(k == vals.size()-1){ 
        cells[i][j] = vals.get(k); 
        threads[n] = new SolveSudoku(i, j+1, cells); 
        threads[n].compute(); 
       } 
       else{ 
        cells[i][j] = vals.get(k); 
        threads[n] = new SolveSudoku(i, j+1, cells); 
        threads[n].fork(); 
       } 
       n++; 
      } 


      for(int k=0; k<threads.length-1; k++) 
       if(k != vals.size()-1) 
        threads[k].join(); 

     } 

     cells[i][j] = 0; 
     return; 
    }} 

new ForkJoinPool().invoke(new SolveSudoku(0, 0, M)); // where *M* is a sudoku instance to solve where all the unfilled cells contain '0' 
+0

Donc l'algorithme parallèle est censé résoudre le sudoku entier à la fois? – vatbub

+0

Oui, @vatbub! En fait, si vous définissez une méthode classique * main * (avec la ligne en dehors de la définition de classe), et si vous ajoutez la ligne * threads [n] .join(); * en dessous de la dernière ligne du bloc else (dans le boucle), tout fonctionne bien. Ne sait pas où est l'erreur mais semble que les threads font ce qu'ils veulent faire ... – Process0

Répondre

0

D'abord, vous devriez considérer ce qui se passe si un thread termine son travail. Vous devriez noter qu'il essaie de réinitialiser la cellule à 0, mais qu'en est-il s'il y a un autre sous-thread qui travaille avec la cellule?

De toute évidence, si un autre thread accédant à la même cellule essaie de vérifier si elle est légale, il se peut qu'elle doive mettre une valeur erronée car un autre thread y remet un zéro!

+0

Cette réponse apporte un bon point, mais ce serait mieux comme commentaire car ce n'est pas une solution au problème. – Aaron

+0

Malheureusement, je ne pense pas que vous avez raison. Puisque le thread "boss" attend chaque enfant qu'il a engendré, aucun sous-thread (de lui ou ses enfants) ne peut s'exécuter après que le "boss" soit terminé. Et comme je crée une nouvelle instance pour chaque nouveau candidat trouvé, les objets (le champ * cells *) ne sont pas partagés entre threads, nous n'avons donc pas besoin de synchronisation. – Process0

+0

Comment le b0ss se termine-t-il si l'enfant ne l'a pas encore? Le problème est, il y a d'autres sous-threads qui accèdent à la même grille en même temps, en la modifiant. Ce n'est pas un appel par valeur malheureusement, mais par référence. – ReadTheInitialLetters

0

Je pense que vous devriez passer le copier du tableau aux nouveaux threads. Dans votre code, vous passez le même tableau à tous les threads et ils essaient d'insérer la valeur correcte en même temps.