From 3bf0368a0b606b92eceeeea91e93751af9d27dd7 Mon Sep 17 00:00:00 2001 From: Akilan Date: Tue, 21 Jan 2025 16:35:46 +0000 Subject: [PATCH] added nqueens benchmark --- benchmarks/benchmarks/queens/Makefile | 22 +++ benchmarks/benchmarks/queens/README.md | 163 ++++++++++++++++++ benchmarks/benchmarks/queens/analysis.txt | 0 benchmarks/benchmarks/queens/nqueens | Bin 0 -> 33988 bytes benchmarks/benchmarks/queens/nqueens.c | 162 +++++++++++++++++ benchmarks/benchmarks/queens/nqueens.o | Bin 0 -> 3600 bytes benchmarks/benchmarks/queens/performance.csv | 29 ++++ benchmarks/benchmarks/queens/performance2.csv | 34 ++++ benchmarks/benchmarks/queens/test.dat | 1 + 9 files changed, 411 insertions(+) create mode 100644 benchmarks/benchmarks/queens/Makefile create mode 100644 benchmarks/benchmarks/queens/README.md create mode 100644 benchmarks/benchmarks/queens/analysis.txt create mode 100755 benchmarks/benchmarks/queens/nqueens create mode 100644 benchmarks/benchmarks/queens/nqueens.c create mode 100644 benchmarks/benchmarks/queens/nqueens.o create mode 100644 benchmarks/benchmarks/queens/performance.csv create mode 100644 benchmarks/benchmarks/queens/performance2.csv create mode 100644 benchmarks/benchmarks/queens/test.dat diff --git a/benchmarks/benchmarks/queens/Makefile b/benchmarks/benchmarks/queens/Makefile new file mode 100644 index 0000000..560ca38 --- /dev/null +++ b/benchmarks/benchmarks/queens/Makefile @@ -0,0 +1,22 @@ +CC = cc +BINARY = ./nqueens +CFLAGS += -Wall -mabi=purecap-benchmark + +all: clean compile clear run + +run: + # run and test input file + $(BINARY) + +clean: + rm *.o + +clear: + clear + +compile: nqueens.o + $(CC) $(CFLAGS) -pg -o $(BINARY) nqueens.o + +nqueens.o: + # Ultra fast compilation + $(CC) -c -pg -O3 ./nqueens.c diff --git a/benchmarks/benchmarks/queens/README.md b/benchmarks/benchmarks/queens/README.md new file mode 100644 index 0000000..5aaba9e --- /dev/null +++ b/benchmarks/benchmarks/queens/README.md @@ -0,0 +1,163 @@ +# The N-Queens 女王 Problem + +The n-queens puzzle is the problem of placing n chess queens on an n x n chessboard so that no two queens threaten each other. + +Thus, a solution requires that no two queens share the same **row, column, or diagonal**. + +## Usage + +```bash +make or make compile && ./nqueens < test.dat +``` + +Edit ```test.dat``` to the maximum board size you want to test. +The program will test every board from size 1 to n. + +Sample output with ```test.dat``` containing n = 5 + +     +     +     +     +     + + +### Profiling + +```shell +gprof -P -b ./nqueens gmon.out > analysis.txt +``` + +You can generate a call graph using [ gprof2dot](https://github.com/jrfonseca/gprof2dot) and [GraphViz](http://www.graphviz.org/). + +## Recursion + +Let's discuss a simple solution to the problem, without implementing any heuristics for optimization, only bruteforce +backtracking. + +Have we reached the end of the board (last line)? +* **YES**: Return *TRUE* +* **NO**: Continue + +Iterate through the current row. + +Place a queen at current position [row][i]. + +Is this queen possible? (See [**Validation**](https://github.com/felipecustodio/algorithms/new/master/backtracking/nqueens#validation)) + + * **YES**: Calls recursion to next row. + + * **NO**: Remove queen and continue loop. + +If the loop has ended and we couldn't place any queen, it means the previous queen is blocking us. + +We backtrack to her and continue the process. + +## Validation + +If there's a queen in: +* Same row +* Same column +* Same diagonals + +The function will return *FALSE*. + +## Performance + +The program asks for a maximum size of board. It'll try to solve every board with increasing size until n. + +It doesn't have any restrictions, so it could take hours for a big test case. Use it carefully. + + +![Board size x Time to solve](http://i.imgur.com/82BNHJ3.png) + +![Board size x Time to solve](http://i.imgur.com/b8yzF41.png) + + +We can observe that the number of attributions and the time needed to solve a board increases a lot with board size. +After the last case test, my computer kept running the program for almost an hour, still not producing the output for the 33 x 33 board. + +*Benchmark Machine:* + +> OS: Antergos + +> Kernel: x86_64 Linux 4.7.6-1-ARCH + +> Shell: zsh 5.2 + +> CPU: Intel Core i5-6200U CPU @ 2.7GHz + +> GPU: Mesa DRI Intel(R) HD Graphics 520 (Skylake GT2) + +> RAM: 2096MiB / 7854MiB + +### Run Results + +| board size | calls | time | +|------------|-------------|-------------| +| 0 | 0 | 0.000001s | +| 1 | 1 | 0.000000s | +| 4 | 26 | 0.000005s | +| 5 | 15 | 0.000004s | +| 6 | 171 | 0.000026s | +| 7 | 42 | 0.000009s | +| 8 | 876 | 0.000101s | +| 9 | 333 | 0.000046s | +| 10 | 975 | 0.000117s | +| 11 | 517 | 0.000064s | +| 12 | 3066 | 0.000374s | +| 13 | 1365 | 0.000181s | +| 14 | 26495 | 0.002876s | +| 15 | 20280 | 0.002252s | +| 16 | 160712 | 0.017150s | +| 17 | 91222 | 0.010383s | +| 18 | 743229 | 0.084488s | +| 19 | 48184 | 0.005725s | +| 20 | 3992510 | 0.490726s | +| 21 | 179592 | 0.023457s | +| 22 | 38217905 | 5.092550s | +| 23 | 584591 | 0.081210s | +| 24 | 9878316 | 1.410959s | +| 25 | 1216775 | 0.188140s | +| 26 | 10339849 | 1.599553s | +| 27 | 12263400 | 1.987257s | +| 28 | 84175966 | 14.078644s | +| 29 | 44434525 | 7.684626s | +| 30 | 1692888135 | 298.843353s | +| 31 | 408773285 | 74.617912s | +| 32 | -1495242192 | 526.441956s | +| 33 | 323601164 | 893.228821s | + +Number of calls has exceed *long int* on board 32 x 32. + +## Algorithm Complexity + +Backtracking algorithms have a worst case complexity of O(d^n). +* d = domain (possible values for a variable) +* n = number of variables + +For the n-queens problem, we have a domain of 2 (0 or 1) and n² variables. + +Consider the 34 * 34 board. + +![Board size x Time to solve](https://www5a.wolframalpha.com/Calculate/MSP/MSP3991f5h01dgcf77819100002275f3a04ecb8865?MSPStoreType=image/gif&s=37) + +How about it? Without heuristics and a very good implementation, it's insane how much this problem grows. + + +## Memory + +The program will allocate a structure named BOARD, that contains a double int pointer (matrix) and it's size. +After it attempts to solve the board, the heap memory allocated is destroyed. + +Tested with **Valgrind**, no memory leaks. + +## Flowchart + +To better understand the algorithm, here's a handy flowchart of the N-Queens problem without using heuristics: + + +![n-queens problem without heuristics](https://s17.postimg.org/nm73d06pb/nqueens.png) + + +>*Keep in mind this is not following proper flowchart rules, it was drawn just for quick reference before an exam* diff --git a/benchmarks/benchmarks/queens/analysis.txt b/benchmarks/benchmarks/queens/analysis.txt new file mode 100644 index 0000000..e69de29 diff --git a/benchmarks/benchmarks/queens/nqueens b/benchmarks/benchmarks/queens/nqueens new file mode 100755 index 0000000000000000000000000000000000000000..eb44c793a653dd9490a7e6910e0a02eb40a9c98a GIT binary patch literal 33988 zcmeI5e{fXQ701teZ?oBi@H-HKN;XgmLVArq)NeF@1zmfidyyOD(O zV--;pI=Vwjfj=M}J0n@eW;!?~R!dr`Q`=5y%1Eo7!G+OIV0DxU!iE~R-}ByE*rc^~ z+Wyf$&V{r0o_pUt@0`y)ck|c1d*;R`UuF;~grY*mLYy|DJ>*1-C>v4&(e*V2%Znc_ zE?v#NLyIwaXxBezY-cYX)b+CB^<_hcjrp#jePrn==w^XSM$z?vyE$MfsD|5{x6lmc zq}_amb&l(1u~G158x39e2bwncZ*~p0_u&JkJ)iXi>&f;UmOU^uimq4r1C5@#O*i$S z@vd2F+PmKxXFa(j+va{rnssjJpKbsOsqeW<u!f9^*WnOE*OwKP z73f8)A6jd!hRaF<)J7RrYv^R*wHgD_^-c9j%kY){}}y zT2;JkMIuLn!~BBI<+PO$?2nN@MlaEPq9FUntK5a^9!u|nj{gRmNvKO6H{*Ez36sYN z^sRv;msBV$$$ln}bGrod#|`gk6Tc%qxUuPH9Wh<$xVBF1xVl>F7;Lq53~EZq zL9Xtc6xy=NPG$WXg)=Gm$5-=dOpa4~_nM~WUDuSn_4zc9^+ox#hHIRy%5*8g(iatK zYqL|RMh$i!QytMf8Q)8y5@+ce;F@}XcNL8 zsFR~kJYQpX4LDl1#vCo%x^fiS;?xcu>5s>=c)mFn7&5kJn7t_M{RPiQ?lyfLY+Z&p zix6)i;x6d8vFTUGcPf;bh<6`+O@r;c?XCk+#OeKf=h+Mhj;CeL8cU&LN?O#ZP}wfj zLHIY)<{CKBvN?9bALe4%24Xi~e83W(MNfk9hXOCfn-yTfASD^#HodUr zfd3r(OR%+6QM})WjSaA8*PCDSDqs51H_jYk!wO@;Kydj>;>l3zoh2OB97WKl{h~@}0&oAm< z$C@ixdlfmLAs3MEttlOYMM`KA!LEk9=eVq#<$UPZ)bLfr^*Q#zMEH_#qp^o~x(+x} zT?4nhR~cK3_i`@pYF*HE4tej;g54h=@5AtY8~SQg*oA*JDh))mN#P4xX858uF2>`{Mk@*P5GV_kv;TIV5 zx@5z*y;zfp*sEFBcb=WxzvFBKjCbPs_RWi8P4K&Yb4!dlH=u9PGz#fjc9i!k&f&JP zjmT~aU3`H;3K&0zb#U5gehtPPG~u_TOgnnK?MSJkHr%KvGp5j_+$oOWlcjs-bQrqB zkvj$JYW!FdAwDIaAr&L1_Du@0NBTD(qyS2AOc!(`k9#w`Zphc0)2BZ7C|l!ww7RRmSc?`#99?2&z5yunpRYcH4IHhF2>)Y-m9w> ztQ~R8>9nD~va#Cf_iS^|uB!C;{Idg| zS~vfB=OeYZa|0#0<}C{rMLkj0RdkVhf7 z97A~w&+8kuxf|7yVLU7*#EnH;kxO2hK`FGlR9QR=uy7N9$zsu5TiK*Xj z>3rt{KVM?$?bbN27y5a~DC_Wu2MnL#C=x zxPG(TIG@pj$lK77V4sOT&iWv!*expl5mi9eL%0CR?s-ntz+v|M%THHgRH?IKc&f7} z` +#include +#include + +#define bool char +#define TRUE 1 +#define FALSE 0 + +typedef struct board { + int n; + int** matrix; +} BOARD; + +void printStep(BOARD* b, int x, int y) { + int i, j; + for (i = 0; i < b->n; i++) { + for (j = 0; j < b->n; j++) { + if (i == x && j == y) { + printf(" "); + } else { + if (b->matrix[i][j]) { + printf(" "); + } else { + printf(" "); + } + } + } + printf("\n"); + } + printf("\n\n"); +} + +bool isValid(BOARD* b, int x, int y) { + + int i, j; + // check horizontal + for (i = 0; i < b->n; i++) { + if (i != y && b->matrix[x][i] == 1) return FALSE; + } + + // check vertical + for (i = 0; i < b->n; i++) { + if (i != x && b->matrix[i][y] == 1) return FALSE; + } + // check diagonals + // check top left + i = x; + j = y; + while (i >= 0 && j >= 0) { + if (i != x && j != y && b->matrix[i][j] == 1) { + return FALSE; + } + i--; + j--; + } + // check top right + i = x; + j = y; + while (i >= 0 && j < b->n) { + if (i != x && j != y && b->matrix[i][j] == 1) { + return FALSE; + } + i--; + j++; + } + // check bottom left + i = x; + j = y; + while (i < b->n && j >= 0) { + if (i != x && j != y && b->matrix[i][j] == 1) { + return FALSE; + } + i++; + j--; + } + // check bottom right + i = x; + j = y; + while (i < b->n && j < b->n) { + if (i != x && j != y && b->matrix[i][j] == 1) { + return FALSE; + } + i++; + j++; + } + return TRUE; +} + +bool placeQueen(BOARD** b, int line, long int* calls) { + int i; + if (line >= (*b)->n) return TRUE; + for (i = 0; i < (*b)->n; i++) { + (*b)->matrix[line][i] = 1; + (*calls)++; + if (isValid((*b), line, i) && placeQueen(b, line+1, calls)) { + return TRUE; + } + (*b)->matrix[line][i] = 0; + } + return FALSE; +} + +void printBoard(BOARD* b) { + int i, j; + for (i = 0; i < b->n; i++) { + for (j = 0; j < b->n; j++) { + if (b->matrix[i][j]) { + printf(" "); + } else { + printf(" "); + } + } + printf("\n"); + } +} + +void queens(int n) { + // benchmarking + clock_t start_t, end_t; + float delta_t = 0.0; + long int calls = 0; + int i, j; + BOARD* b = (BOARD*)malloc(sizeof(BOARD)); + b->n = n; + b->matrix = (int**)malloc(sizeof(int*) * n); + for (i = 0; i < n; i++) { + b->matrix[i] = (int*)malloc(sizeof(int) * n); + for (j = 0; j < n; j++) { + b->matrix[i][j] = 0; + } + } + + start_t = clock(); + if (placeQueen(&b, 0, &calls)) { + end_t = clock(); + // human readable time + delta_t = ((float)(end_t - start_t) / 1000000000000.0F ) * CLOCKS_PER_SEC; + printBoard(b); + printf("%d,%ld,%lfs\n", n, calls, delta_t); + } + + for (i = 0; i < n; i++) { + free(b->matrix[i]); + b->matrix[i] = NULL; + } + free(b->matrix); + b->matrix = NULL; + free(b); +} + +int main(int argc, char const *argv[]) { + system("clear"); + int i; + int n = 0; + scanf("%d", &n); + printf("board size,calls,time\n"); + for (i = 0; i <= n; i++) { + queens(i); + } + + return 0; +} diff --git a/benchmarks/benchmarks/queens/nqueens.o b/benchmarks/benchmarks/queens/nqueens.o new file mode 100644 index 0000000000000000000000000000000000000000..92780a65eda706ad9d1350d6b791010ef829023c GIT binary patch literal 3600 zcmb7HZ){W76+iDi$9@T>KrtlH37ke~Ba0)}(S}r5IDgnEbyb>KTQyC3F^)-$?IgsG zz@&iH@u6y|lvmQNrBxHD{eWE|RT`C&tr~1>Q`c51lnPO`Qccwl22-_&6rLHW_dD<1 z*9NEk&@12fyXV|{fA^eo&%N*Y{aasr<0g^_g&#GjZ*#+oin0oIli6#E3m(%hOH~wO zY?;+u6){88($RfsApkTjwDs}Oce33&>9ktRC!;x4OSFMi4$3mvMbjdw^hj*5Unr{i zY#zVpe_6F>TFBh<3;2eT!{JC;8y(ym8|>4xVE6ofL)dj%C=1|Y-@J>6MAsdZ_o1%= z)e6gE3`Rw1MO})z1M{{4c@mF%0rG0#CJeg>gh)G3xp12+ud@slA^FkeR{!5}h9>21 z{7%lzKC0yA#vHjhMbcFY%&e`UJr6r6bX}pmhq526AR2#DCjEvYH{VpGX4p60ppcGS z7;gt+Up)aS+XEveCY+=X$k~}mSuHg?D8yVpuT(;la($^$rqF8e!EO(a{k_W?t0`)! z?wd-epsdJ$Dz7eiF@C@qD65&hhML(wy;h<j*DIBJo^SP~@93-MD}nE0jE8<4 zRi7K{hM!&Vw-bJMBI8R?T!ZOJQ9 z=nyaq`xZL_TYp;Vd4lWh; zv+u8iYl|esp9RNG@ChEaHNX7_xO&Sbm#$&{JK#&eKJcA`eb-8g+qCaz@Z08P8y^9G z9c+9Uv1~!bypt+yR5Jz){r|DBtr@ z*mw}@axNbldtmwk@?KT4GoK>w^RRtCbOSPYVc&pE<$}_XzodBbpD8P0CQV?^HgdjS zQtF{wp1)YB{CSG#{%M}W{F#h#1^Mg68n_d1Ua~!NV_RW&H|+0%AD!^0BX@h~KgZcW zLwgH)3H>ts!g)Red&F6OMp<~4SK?e;z?uG`vwH=3$}#4%TMyp{%=5@+Zm)SBPs`6A zV?S<+^In19eCED@&2wX2u%i?9bimGknf6t>8II3n4<0yb#>`1&L-90EI$;-L%=@wmwmpSCS&6e+fAiq^)z=T4 zFNhdV?QS!gj0Dy?{zq^4Jn zPaNw}llc)z`so^KXk4Ra5BEIPnloipZCrzWHt)gEja&c~K8}{bc*rQ)zueKu3x^tJC zx{}yK9b-I|GjwkDQ3-p8Ttn=j`*z*R5}GOglJug2y_~0?-!3i*%&3ylww$ter<}Bm z*F^sW>kr9lJPv!TeD8!E9XYJ0bB=%c^c!CK^03a2BVJn9*Rn3bbyup6B8g~t1S+bd zokQV~K5r_vKiU!rClaZabSxPK{~blei+BltMN}2mbK&m|lsn$xtoTZ33TUtWp803R z2hJ4wakdul4-3tEyuP%sf3x^_*oXNTvS9u=`j-;<_5qP!zBEuJ3JzQ7PXO_L_6-2B zez4C%e+Y>8wQmOyzhKZp|0dva=sf}reDJaS2@vmn-$fvP!4EC;9~b&G5P9w!0K(;9 zpN0NjAVL)UgN1%C@NSH20OC`|=MeHNJj46aR{-LS``!@vvcPU2ufG(?>o|bC4o3v& zzl{g4V_4{a0*G%Sp94YTxLig2Ff>@S(0>-ld|82f_?dSb5L3;MJD@)RnRz!`=-&VY zWw6CU|CEK!tiWD@0fAnD0G{V`$=%yr^5%d`ZrR|Hi_%reC1=&cs!KLpw_Psz^SWZ4 zOa7#;faiycE-rG(U%6-9(7TIxzUMxRk8v*VqTU5UyTBK^3x=M=zH#{{D$6rM{)>?R zE@b4o+5eG{UlZ~fA-^Q#vqFAO$at@r*EabO@Y_ETUWdzXvF3vzkev^Hk+JtQ9 zH-Cq7zkQyPLblJ(Iw1qhf?PJo+vi8@i|8eK46S+Lq5dlQ$twBrD)}c>GIP!6>#dR> zs**_?9!;l6+cO%C4yGuf;ok_Jtqj~18Nl_V4dWk5`Zww5FljsYM@NQ8ONL{E&?mx? z=wm#Uv{WXQjwVTqB!(h!F=ZFjk?