I created a sudoku solver in c and so far it's working.
I'm reading a txt file in and parse it into a 9x9 int array: int sudoku[9][9]
I implemented a simple brute force backtracking algorithm where I check every position. If I need to assign a number I loop through the values 1 to 9 and check if they are valid. If they fit I move to the next index.
I need to parallelize the algorithm to work with multiple processors using MPI, but I don't really know where and how to start.
Now I tried to parallelize the execution with OpenMP tasks first. I want to parallelize the check for possible numbers, ideally creating a task for every number that needs to be checked.
My current approach:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <omp.h>
#include <time.h>
#include <unistd.h>
#define SIZE 9
#define UNASSIGNED 0
// compile with
// gcc -fopenmp <filename>.c -o <name>
//Optional set num of threads: export OMP_NUM_THREADS=4
// ./<name>
clock_t start, end;
void print_grid(int grid[SIZE][SIZE]) {
for (int row = 0; row < SIZE; row++) {
for (int col = 0; col < SIZE; col++) {
printf("%2d", grid[row][col]);
}
printf("\n");
}
}
//https://stackoverflow.com/questions/1726302/removing-spaces-from-a-string-in-c
void remove_spaces(char* s) {
const char* d = s;
do {
while (*d == ' ') {
++d;
}
} while (*s++ = *d++);
}
int is_exist_row(int grid[SIZE][SIZE], int row, int num){
for (int col = 0; col < 9; col++) {
if (grid[row][col] == num) {
return 1;
}
}
return 0;
}
int is_exist_col(int grid[SIZE][SIZE], int col, int num) {
for (int row = 0; row < 9; row++) {
if (grid[row][col] == num) {
return 1;
}
}
return 0;
}
int is_exist_box(int grid[SIZE][SIZE], int startRow, int startCol, int num) {
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
if (grid[row + startRow][col + startCol] == num) {
return 1;
}
}
}
return 0;
}
int is_safe_num(int grid[SIZE][SIZE], int row, int col, int num) {
return !is_exist_row(grid, row, num)
&& !is_exist_col(grid, col, num)
&& !is_exist_box(grid, row - (row % 3), col - (col %3), num);
}
int find_unassigned(int grid[SIZE][SIZE], int *row, int *col) {
for (*row = 0; *row < SIZE; (*row)++) {
for (*col = 0; *col < SIZE; (*col)++) {
if (grid[*row][*col] == 0) {
return 1;
}
}
}
return 0;
}
int solve(int grid[SIZE][SIZE]) {
int row = 0;
int col = 0;
if (!find_unassigned(grid, &row, &col)){
return 1;
}
for (int num = 1; num <= SIZE; num++ ) {
if (is_safe_num(grid, row, col, num)) {
int val = 0;
#pragma omp task firstprivate(grid, row, col,val,num)
{
int copy_grid[SIZE][SIZE];
for (int row = 0; row < SIZE; row++) {
for (int col = 0; col < SIZE; col++) {
copy_grid[row][col] = grid[row][col];
}
}
copy_grid[row][col] = num;
val = solve(copy_grid);
if(val) {
print_grid(copy_grid);
end = clock();
double time_spent = (double)(end - start) / CLOCKS_PER_SEC;
printf("\nGelöst in %f s\n",time_spent);
exit(0);
}
}
if (val) {
return 1;
}
grid[row][col] = UNASSIGNED;
#pragma omp taskwait
}
}
return 0;
}
int main(int argc, char** argv) {
int sudoku[SIZE][SIZE];
FILE *file;
char *line = NULL;
size_t len = 0;
ssize_t read;
int i,j;
i =0;
file = fopen("Test_Sudoku_VeryDifficult.txt","r");
if(file) {
while(read = getline(&line, &len,file) != -1) {
remove_spaces(line);
for(j = 0; j < SIZE; j++) {
sudoku[i][j] = (int)line[j] - '0'; //char to int
}
i++;
}
fclose(file);
if (line) free(line);
printf("Size: %d", SIZE);
printf("\n");
start = clock();
printf("Solving Sudoku: \n");
print_grid(sudoku);
printf("---------------------\n");
#pragma omp parallel sections
{
#pragma omp section
{
solve(sudoku);
}
}
exit(EXIT_SUCCESS);
} else {
exit(EXIT_FAILURE);
}
}
I took inspiration from this stackoverflow post
My Sudoku File looks like this
0 0 0 0 0 0 0 1 0
4 0 0 0 0 0 0 0 0
0 2 0 0 0 0 0 0 0
0 0 0 0 5 0 4 0 7
0 0 8 0 0 0 3 0 0
0 0 1 0 9 0 0 0 0
3 0 0 4 0 0 2 0 0
0 5 0 1 0 0 0 0 0
0 0 0 8 0 6 0 0 0
When I compile and execute this it works, but the Tasks do not get executed parallel. Every task waits for completion of his subtask before going to the next. If I remove the #pragma omp taskwait
the program doesn't work correctly and the output is wrong.
I added a exit(0)
when printing the result because otherwise the program continues to explore other paths.
I don't really know what I need to change in order to improve.
I also want to parallelize the algorithm with multiprocessing with MPI, But I don't know where to start. I'm grateful for any help or resources that point me in the right direction.
Thanks in advance for any help or suggestions on how to improve.