2 Copyright (c) 2005-2019 Intel Corporation
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
17 #include "../../common/utility/utility.h"
18 #include "../../common/utility/get_default_num_threads.h"
21 #pragma offload_attribute (push,target(mic))
22 #endif // __TBB_MIC_OFFLOAD
29 #include "tbb/tick_count.h"
30 #include "tbb/task_group.h"
31 #include "tbb/global_control.h"
33 #pragma warning(disable: 4996)
35 const unsigned BOARD_SIZE=81;
36 const unsigned BOARD_DIM=9;
41 std::atomic<unsigned> nSols;
42 bool find_one = false;
44 unsigned short init_values[BOARD_SIZE] = {1,0,0,9,0,0,0,8,0,0,8,0,2,0,0,0,0,0,0,0,5,0,0,0,7,0,0,0,5,2,1,0,0,4,0,0,0,0,0,0,0,5,0,0,7,4,0,0,7,0,0,0,3,0,0,3,0,0,0,2,0,0,5,0,0,0,0,0,0,1,0,0,5,0,0,0,1,0,0,0,0};
49 unsigned short solved_element;
50 unsigned potential_set;
53 void read_board(const char *filename) {
56 fp = fopen(filename, "r");
58 fprintf(stderr, "sudoku: Could not open input file '%s'.\n", filename);
61 for (unsigned i=0; i<BOARD_SIZE; ++i) {
62 if (fscanf(fp, "%d", &input))
63 init_values[i] = input;
65 fprintf(stderr, "sudoku: Error in input file at entry %d, assuming 0.\n", i);
72 void print_board(board_element *b) {
73 for (unsigned row=0; row<BOARD_DIM; ++row) {
74 for (unsigned col=0; col<BOARD_DIM; ++col) {
75 printf(" %d", b[row*BOARD_DIM+col].solved_element);
76 if (col==2 || col==5) printf(" |");
79 if (row==2 || row==5) printf(" ---------------------\n");
83 void print_potential_board(board_element *b) {
84 for (unsigned row=0; row<BOARD_DIM; ++row) {
85 for (unsigned col=0; col<BOARD_DIM; ++col) {
86 if (b[row*BOARD_DIM+col].solved_element)
87 printf(" %4d ", b[row*BOARD_DIM+col].solved_element);
89 printf(" [%4d]", b[row*BOARD_DIM+col].potential_set);
90 if (col==2 || col==5) printf(" |");
94 printf(" ------------------------------------------------------------------\n");
98 void init_board(board_element *b) {
99 for (unsigned i=0; i<BOARD_SIZE; ++i)
100 b[i].solved_element = b[i].potential_set = 0;
103 void init_board(board_element *b, unsigned short arr[81]) {
104 for (unsigned i=0; i<BOARD_SIZE; ++i) {
105 b[i].solved_element = arr[i];
106 b[i].potential_set = 0;
110 void init_potentials(board_element *b) {
111 for (unsigned i=0; i<BOARD_SIZE; ++i)
112 b[i].potential_set = 0;
115 void copy_board(board_element *src, board_element *dst) {
116 for (unsigned i=0; i<BOARD_SIZE; ++i)
117 dst[i].solved_element = src[i].solved_element;
120 bool fixed_board(board_element *b) {
121 for (int i=BOARD_SIZE-1; i>=0; --i)
122 if (b[i].solved_element==0) return false;
126 bool in_row(board_element *b, unsigned row, unsigned col, unsigned short p) {
127 for (unsigned c=0; c<BOARD_DIM; ++c)
128 if (c!=col && b[row*BOARD_DIM+c].solved_element==p) return true;
132 bool in_col(board_element *b, unsigned row, unsigned col, unsigned short p) {
133 for (unsigned r=0; r<BOARD_DIM; ++r)
134 if (r!=row && b[r*BOARD_DIM+col].solved_element==p) return true;
138 bool in_block(board_element *b, unsigned row, unsigned col, unsigned short p) {
139 unsigned b_row = row/3 * 3, b_col = col/3 * 3;
140 for (unsigned i=b_row; i<b_row+3; ++i)
141 for (unsigned j=b_col; j<b_col+3; ++j)
142 if (!(i==row && j==col) && b[i*BOARD_DIM+j].solved_element==p) return true;
146 void calculate_potentials(board_element *b) {
147 for (unsigned i=0; i<BOARD_SIZE; ++i) {
148 b[i].potential_set = 0;
149 if (!b[i].solved_element) { // element is not yet fixed
150 unsigned row = i/BOARD_DIM, col = i%BOARD_DIM;
151 for (unsigned potential=1; potential<=BOARD_DIM; ++potential) {
152 if (!in_row(b, row, col, potential) && !in_col(b, row, col, potential)
153 && !in_block(b, row, col, potential))
154 b[i].potential_set |= 1<<(potential-1);
160 bool valid_board(board_element *b) {
162 for (unsigned i=0; i<BOARD_SIZE; ++i) {
163 if (success && b[i].solved_element) { // element is fixed
164 unsigned row = i/BOARD_DIM, col = i%BOARD_DIM;
165 if (in_row(b, row, col, b[i].solved_element) || in_col(b, row, col, b[i].solved_element) || in_block(b, row, col, b[i].solved_element))
172 bool examine_potentials(board_element *b, bool *progress) {
173 bool singletons = false;
174 for (unsigned i=0; i<BOARD_SIZE; ++i) {
175 if (b[i].solved_element==0 && b[i].potential_set==0) // empty set
177 switch (b[i].potential_set) {
178 case 1: { b[i].solved_element = 1; singletons=true; break; }
179 case 2: { b[i].solved_element = 2; singletons=true; break; }
180 case 4: { b[i].solved_element = 3; singletons=true; break; }
181 case 8: { b[i].solved_element = 4; singletons=true; break; }
182 case 16: { b[i].solved_element = 5; singletons=true; break; }
183 case 32: { b[i].solved_element = 6; singletons=true; break; }
184 case 64: { b[i].solved_element = 7; singletons=true; break; }
185 case 128: { b[i].solved_element = 8; singletons=true; break; }
186 case 256: { b[i].solved_element = 9; singletons=true; break; }
189 *progress = singletons;
190 return valid_board(b);
193 #if !__TBB_CPP11_LAMBDAS_PRESENT
194 void partial_solve(board_element *b, unsigned first_potential_set);
196 class PartialSolveBoard {
198 unsigned first_potential_set;
200 PartialSolveBoard(board_element *_b, unsigned fps) :
201 b(_b), first_potential_set(fps) {}
202 void operator() () const {
203 partial_solve(b, first_potential_set);
208 void partial_solve(board_element *b, unsigned first_potential_set) {
209 if (fixed_board(b)) {
212 if (++nSols==1 && verbose) {
218 calculate_potentials(b);
220 bool success = examine_potentials(b, &progress);
221 if (success && progress) {
222 partial_solve(b, first_potential_set);
223 } else if (success && !progress) {
224 board_element *new_board;
225 while (b[first_potential_set].solved_element!=0) ++first_potential_set;
226 for (unsigned short potential=1; potential<=BOARD_DIM; ++potential) {
227 if (1<<(potential-1) & b[first_potential_set].potential_set) {
228 new_board = (board_element *)malloc(BOARD_SIZE*sizeof(board_element));
229 copy_board(b, new_board);
230 new_board[first_potential_set].solved_element = potential;
231 #if __TBB_CPP11_LAMBDAS_PRESENT
232 g->run( [=]{ partial_solve(new_board, first_potential_set); } );
234 g->run(PartialSolveBoard(new_board, first_potential_set));
245 unsigned solve(int p) {
246 tbb::global_control c(tbb::global_control::max_allowed_parallelism, p);
248 board_element *start_board = (board_element *)malloc(BOARD_SIZE*sizeof(board_element));
249 init_board(start_board, init_values);
251 tick_count t0 = tick_count::now();
252 partial_solve(start_board, 0);
254 solve_time = (tick_count::now() - t0).seconds();
259 #if __TBB_MIC_OFFLOAD
260 #pragma offload_attribute (pop)
261 #endif // __TBB_MIC_OFFLOAD
263 int main(int argc, char *argv[]) {
265 tbb::tick_count mainStartTime = tbb::tick_count::now();
267 utility::thread_number_range threads(utility::get_default_num_threads);
268 string filename = "";
271 utility::parse_cli_arguments(argc,argv,
272 utility::cli_argument_pack()
273 //"-h" option for displaying help is present implicitly
274 .positional_arg(threads,"n-of-threads",utility::thread_number_range_desc)
275 .positional_arg(filename,"filename","input filename")
277 .arg(verbose,"verbose","prints the first solution")
278 .arg(silent,"silent","no output except elapsed time")
279 .arg(find_one,"find-one","stops after finding first solution\n")
282 if ( silent ) verbose = false;
284 if ( !filename.empty() )
285 read_board( filename.c_str() );
286 // otherwise (if file name not specified), the default statically initialized board will be used.
287 for(int p = threads.first; p <= threads.last; p = threads.step(p) ) {
289 #if __TBB_MIC_OFFLOAD
290 #pragma offload target(mic) in(init_values, p, verbose, find_one) out(number, solve_time)
292 #endif // __TBB_MIC_OFFLOAD
294 #if __TBB_MIC_OFFLOAD
296 #endif // __TBB_MIC_OFFLOAD
300 printf("Sudoku: Time to find first solution on %d threads: %6.6f seconds.\n", p, solve_time);
303 printf("Sudoku: Time to find all %u solutions on %d threads: %6.6f seconds.\n", number, p, solve_time);
308 utility::report_elapsed_time((tbb::tick_count::now() - mainStartTime).seconds());
311 } catch(std::exception& e) {
312 std::cerr<<"error occurred. error text is :\"" <<e.what()<<"\"\n";