エイト・クイーンのプログラムアーカイブ
Bash、Lua、C、Java、Python、CUDAまで!
https://github.com/suzukiiichiro/N-Queens
initChain() buildChain() carryChain_symmetry() をcarryChain()に統合して変数のパラメータ渡しを極力減らす
せっかく分割されている関数を一つの関数にまとめるメリットってなんでしょう。
しいてあげれば、関数間における変数のやり取りによる負荷、さらにいえば、統合することによって、渡すことすら必要がなくなります。
C言語による並列処理は pthread
というライブラリを使うのですが、スレッド実行時に渡せるパラメータは、構造体一つです。
その他には何も渡すことができません。
渡すことができないということは、実行している関数から変数を参照することも、値を変更することもできないということです。
そうした実情を踏まえて、しかたなく関数をまとめ、変数を減らし、さらにはグローバル変数も整理し、曲直構造化に統合してpthread
に備えていきます。
以下の関数の中身を
void initChain(unsigned const int size,unsigned int* pres_a,unsigned int* pres_b)
{
// チェーンの初期化
unsigned int idx=0;
for(unsigned int a=0;a<(unsigned)size;++a){
for(unsigned int b=0;b<(unsigned)size;++b){
if(((a>=b)&&(a-b)<=1)||((b>a)&&(b-a)<=1)){ continue; }
pres_a[idx]=a;
pres_b[idx]=b;
++idx;
}
}
}
以下のように追加します。
↓
// キャリーチェーン
void carryChain(unsigned const int size)
{
// カウンターの初期化
COUNTER[0]=COUNTER[1]=COUNTER[2]=0;
//
// チェーンの初期化
unsigned int pres_a[930];
unsigned int pres_b[930];
unsigned int idx=0;
for(unsigned int a=0;a<(unsigned)size;++a){
for(unsigned int b=0;b<(unsigned)size;++b){
if(((a>=b)&&(a-b)<=1)||((b>a)&&(b-a)<=1)){ continue; }
pres_a[idx]=a;
pres_b[idx]=b;
++idx;
}
}
こちらも同様ですが、carryChain_symmetry()で呼び出している箇所に
carryChain_symmetry()の中身で置き換えます。
02GCC_carryChain.c
+245
for(unsigned s=w;s<(size-2)*(size-1)-w;++s){
// B=sB;
memcpy(&B,&sB,sizeof(Board));
if(!placement(size,size-1-pres_a[s],0,&B)){ continue; }
if(!placement(size,size-1-pres_b[s],1,&B)){ continue; }
//
carryChain_symmetry(size,n,w,s,e,&B);// 対称解除法
03GCC_carryChain.c
+232
for(unsigned s=w;s<(size-2)*(size-1)-w;++s){
// B=sB;
memcpy(&B,&sB,sizeof(Board));
if(!placement(size,size-1-pres_a[s],0,&B)){ continue; }
if(!placement(size,size-1-pres_b[s],1,&B)){ continue; }
//
// 対称解除法
unsigned const int ww=(size-2)*(size-1)-1-w;
unsigned const int w2=(size-2)*(size-1)-1;
// # 対角線上の反転が小さいかどうか確認する
if((s==ww)&&(n<(w2-e))){ continue ; }
同様に、buildChain()の中身を carryChain()のbuildchain()呼び出し部分と置き換えます。
要するに carryChain()へひとまとめにしたということになります。
ソースコード
/**
*
* bash版キャリーチェーンのC言語版
* 最終的に 08Bash_carryChain_parallel.sh のように
* 並列処理 pthread版の作成が目的
*
* 今回のテーマ
* initChain() buildChain() carryChain_symmetry() を
* carryChain()に統合して変数のパラメータ渡しを極力減らす
*
* これにより、pthread導入時の 構造体1つしか渡せない問題に対応
困ったときには以下のURLがとても参考になります。
C++ 値渡し、ポインタ渡し、参照渡しを使い分けよう
https://qiita.com/agate-pris/items/05948b7d33f3e88b8967
値渡しとポインタ渡し
https://tmytokai.github.io/open-ed/activity/c-pointer/text06/page01.html
C言語 値渡しとアドレス渡し
https://skpme.com/199/
アドレスとポインタ
https://yu-nix.com/archives/c-struct-pointer/
実行方法
bash-3.2$ gcc 03GCC_carryChain.c -o 03GCC && ./03GCC
Usage: ./03GCC [-c|-g]
-c: CPU Without recursion
-r: CPUR Recursion
7.キャリーチェーン
N: Total Unique hh:mm:ss.ms
4: 2 1 0.00
5: 10 2 0.00
6: 4 1 0.00
7: 40 6 0.00
8: 92 12 0.00
9: 352 46 0.00
10: 724 92 0.00
11: 2680 341 0.02
12: 14200 1788 0.05
13: 73712 9237 0.15
14: 365596 45771 0.50
15: 2279184 285095 2.10
bash-3.2$
最適化オプション含め以下を参考に
bash$ gcc -Wall -W -O3 -mtune=native -march=native 07GCC_carryChain.c -o nq27 && ./nq27 -r
7.キャリーチェーン
7.キャリーチェーン
N: Total Unique hh:mm:ss.ms
4: 2 1 0.00
5: 10 2 0.00
6: 4 1 0.00
7: 40 6 0.00
8: 92 12 0.00
9: 352 46 0.00
10: 724 92 0.00
11: 2680 341 0.00
12: 14200 1788 0.01
13: 73712 9237 0.05
14: 365596 45771 0.19
15: 2279184 285095 1.01
16: 14772512 1847425 6.10
17: 95815104 11979381 40.53
bash-3.2$ gcc -Wall -W -O3 GCC12.c && ./a.out -r
12.CPUR 再帰 対称解除法の最適化
N: Total Unique hh:mm:ss.ms
4: 2 1 0.00
5: 10 2 0.00
6: 4 1 0.00
7: 40 6 0.00
8: 92 12 0.00
9: 352 46 0.00
10: 724 92 0.00
11: 2680 341 0.00
12: 14200 1787 0.00
13: 73712 9233 0.01
14: 365596 45752 0.07
15: 2279184 285053 0.41
16: 14772512 1846955 2.66
17: 95815104 11977939 18.41
18: 666090624 83263591 2:14.44
19: 4968057848 621012754 17:06.46
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/time.h>
#define MAX 27
// グローバル変数
typedef unsigned long long uint64_t;
uint64_t TOTAL=0;
uint64_t UNIQUE=0;
uint64_t COUNTER[3]; //カウンター配列
// 構造体
typedef struct{
uint64_t row;
uint64_t down;
uint64_t left;
uint64_t right;
uint64_t x[MAX];
}Board ;
//
//hh:mm:ss.ms形式に処理時間を出力
void TimeFormat(clock_t utime,char* form)
{
int dd,hh,mm;
float ftime,ss;
ftime=(float)utime/CLOCKS_PER_SEC;
mm=(int)ftime/60;
ss=ftime-(int)(mm*60);
dd=mm/(24*60);
mm=mm%(24*60);
hh=mm/60;
mm=mm%60;
if(dd)
sprintf(form,"%4d %02d:%02d:%05.2f",dd,hh,mm,ss);
else if(hh)
sprintf(form," %2d:%02d:%05.2f",hh,mm,ss);
else if(mm)
sprintf(form," %2d:%05.2f",mm,ss);
else
sprintf(form," %5.2f",ss);
}
// ボード外側2列を除く内側のクイーン配置処理
uint64_t solve(uint64_t row,uint64_t left,uint64_t down,uint64_t right)
{
if(down+1==0){ return 1; }
while((row&1)!=0) {
row>>=1;
left<<=1;
right>>=1;
}
row>>=1;
uint64_t total=0;
for(uint64_t bitmap=~(left|down|right);bitmap!=0;){
uint64_t const bit=bitmap&-bitmap;
total+=solve(row,(left|bit)<<1,down|bit,(right|bit)>>1);
bitmap^=bit;
}
return total;
}
//
void process(unsigned const int size,unsigned const int sym,Board* B)
{
COUNTER[sym]+=solve(B->row>>2,
B->left>>4,((((B->down>>2)|(~0<<(size-4)))+1)<<(size-5))-1,(B->right>>4)<<(size-5));
}
// クイーンの効きをチェック
bool placement(unsigned const int size,uint64_t dimx,uint64_t dimy,Board* B)
{
if(B->x[dimx]==dimy){ return true; }
if (B->x[0]==0){
if (B->x[1]!=(uint64_t)-1){
if((B->x[1]>=dimx)&&(dimy==1)){ return false; }
}
}else{
if( (B->x[0]!=(uint64_t)-1) ){
if(( (dimx<B->x[0]||dimx>=size-B->x[0])
&& (dimy==0 || dimy==size-1)
)){ return 0; }
if (( (dimx==size-1)&&((dimy<=B->x[0])||
dimy>=size-B->x[0]))){
return 0;
}
}
}
B->x[dimx]=dimy; //xは行 yは列
uint64_t row=UINT64_C(1)<<dimx;
uint64_t down=UINT64_C(1)<<dimy;
uint64_t left=UINT64_C(1)<<(size-1-dimx+dimy); //右上から左下
uint64_t right=UINT64_C(1)<<(dimx+dimy); // 左上から右下
if((B->row&row)||(B->down&down)||(B->left&left)||(B->right&right)){ return false; }
B->row|=row; B->down|=down; B->left|=left; B->right|=right;
return true;
}
// キャリーチェーン
void carryChain(unsigned const int size)
{
// カウンターの初期化
COUNTER[0]=COUNTER[1]=COUNTER[2]=0;
//
// チェーンの初期化
unsigned int pres_a[930];
unsigned int pres_b[930];
unsigned int idx=0;
for(unsigned int a=0;a<(unsigned)size;++a){
for(unsigned int b=0;b<(unsigned)size;++b){
if(((a>=b)&&(a-b)<=1)||((b>a)&&(b-a)<=1)){ continue; }
pres_a[idx]=a;
pres_b[idx]=b;
++idx;
}
}
// チェーンのビルド
Board B;
// Board の初期化 nB,eB,sB,wB;
B.row=0; B.down=0; B.left=0; B.right=0;
// Board x[]の初期化
for(unsigned int i=0;i<size;++i){ B.x[i]=-1; }
// wB=B;//1 上2行に置く
Board wB;
memcpy(&wB,&B,sizeof(Board));
for(unsigned w=0;w<=(unsigned)(size/2)*(size-3);++w){
// B=wB;
memcpy(&B,&wB,sizeof(Board));
if(!placement(size,0,pres_a[w],&B)){ continue; }
if(!placement(size,1,pres_b[w],&B)){ continue; }
// nB=B;//2 左2行に置く
Board nB;
memcpy(&nB,&B,sizeof(Board));
for(unsigned n=w;n<(size-2)*(size-1)-w;++n){
// B=nB;
memcpy(&B,&nB,sizeof(Board));
if(!placement(size,pres_a[n],size-1,&B)){ continue; }
if(!placement(size,pres_b[n],size-2,&B)){ continue; }
// eB=B;// 3 下2行に置く
Board eB;
memcpy(&eB,&B,sizeof(Board));
for(unsigned e=w;e<(size-2)*(size-1)-w;++e){
// B=eB;
memcpy(&B,&eB,sizeof(Board));
if(!placement(size,size-1,size-1-pres_a[e],&B)){ continue; }
if(!placement(size,size-2,size-1-pres_b[e],&B)){ continue; }
// sB=B;// 4 右2列に置く
Board sB;
memcpy(&sB,&B,sizeof(Board));
for(unsigned s=w;s<(size-2)*(size-1)-w;++s){
// B=sB;
memcpy(&B,&sB,sizeof(Board));
if(!placement(size,size-1-pres_a[s],0,&B)){ continue; }
if(!placement(size,size-1-pres_b[s],1,&B)){ continue; }
//
// 対称解除法
unsigned const int ww=(size-2)*(size-1)-1-w;
unsigned const int w2=(size-2)*(size-1)-1;
// # 対角線上の反転が小さいかどうか確認する
if((s==ww)&&(n<(w2-e))){ continue ; }
// # 垂直方向の中心に対する反転が小さいかを確認
if((e==ww)&&(n>(w2-n))){ continue; }
// # 斜め下方向への反転が小さいかをチェックする
if((n==ww)&&(e>(w2-s))){ continue; }
// 枝刈り 1行目が角の場合回転対称チェックせずCOUNT8にする
if(B.x[0]==0){
process(size,2,&B); continue ; //COUNT8
}
// n,e,s==w の場合は最小値を確認する。右回転で同じ場合は、
// w=n=e=sでなければ値が小さいのでskip w=n=e=sであれば90度回転で同じ可能性
if(s==w){ if((n!=w)||(e!=w)){ continue; }
process(size,0,&B); continue; //COUNT2
}
// e==wは180度回転して同じ 180度回転して同じ時n>=sの時はsmaller?
if((e==w)&&(n>=s)){ if(n>s){ continue; }
process(size,1,&B); continue; //COUNT4
}
process(size,2,&B); continue; //COUNT8
//
}
}
}
}
// 集計
UNIQUE=COUNTER[0]+COUNTER[1]+COUNTER[2];
TOTAL=COUNTER[0]*2+COUNTER[1]*4+COUNTER[2]*8;
}
//メインメソッド
int main(int argc,char** argv)
{
bool cpu=false,cpur=false;
int argstart=2;
if(argc>=2&&argv[1][0]=='-'){
if(argv[1][1]=='c'||argv[1][1]=='C'){cpu=true;}
else if(argv[1][1]=='r'||argv[1][1]=='R'){cpur=true;}
else{ cpur=true;}
}
if(argc<argstart){
printf("Usage: %s [-c|-g]\n",argv[0]);
printf(" -c: CPU Without recursion\n");
printf(" -r: CPUR Recursion\n");
}
printf("\n\n7.キャリーチェーン\n");
printf("%s\n"," N: Total Unique hh:mm:ss.ms");
clock_t st; //速度計測用
char t[20]; //hh:mm:ss.msを格納
unsigned int min=4;
unsigned int targetN=21;
// sizeはグローバル
for(unsigned int size=min;size<=targetN;++size){
TOTAL=UNIQUE;
st=clock();
if(cpu){
carryChain(size);
}else{
carryChain(size);
}
TimeFormat(clock()-st,t);
printf("%2d:%13lld%16lld%s\n",size,TOTAL,UNIQUE,t);
}
return 0;
}
実行方法
bash-3.2$ gcc 03GCC_carryChain.c -o 03GCC && ./03GCC
Usage: ./03GCC [-c|-g]
-c: CPU Without recursion
-r: CPUR Recursion
7.キャリーチェーン
N: Total Unique hh:mm:ss.ms
4: 2 1 0.00
5: 10 2 0.00
6: 4 1 0.00
7: 40 6 0.00
8: 92 12 0.00
9: 352 46 0.00
10: 724 92 0.00
11: 2680 341 0.02
12: 14200 1788 0.05
13: 73712 9237 0.15
14: 365596 45771 0.50
15: 2279184 285095 2.10
bash-3.2$
参考リンク
以下の詳細説明を参考にしてください。
【参考リンク】Nクイーン問題 過去記事一覧
【Github】エイト・クイーンのソース置き場 BashもJavaもPythonも!
Nクイーン問題(50)第七章 マルチプロセス Python編
https://suzukiiichiro.github.io/posts/2023-06-21-04-n-queens-suzuki/
Nクイーン問題(49)第七章 マルチスレッド Python編
https://suzukiiichiro.github.io/posts/2023-06-21-03-n-queens-suzuki/
Nクイーン問題(48)第七章 シングルスレッド Python編
https://suzukiiichiro.github.io/posts/2023-06-21-02-n-queens-suzuki/
Nクイーン問題(47)第七章 クラス Python編
https://suzukiiichiro.github.io/posts/2023-06-21-01-n-queens-suzuki/
Nクイーン問題(46)第七章 ステップNの実装 Python編
https://suzukiiichiro.github.io/posts/2023-06-16-02-n-queens-suzuki/
Nクイーン問題(45)第七章 キャリーチェーン Python編
https://suzukiiichiro.github.io/posts/2023-06-16-01-n-queens-suzuki/
Nクイーン問題(44)第七章 対象解除法 Python編
https://suzukiiichiro.github.io/posts/2023-06-14-02-n-queens-suzuki/
Nクイーン問題(43)第七章 ミラー Python編
https://suzukiiichiro.github.io/posts/2023-06-14-01-n-queens-suzuki/
Nクイーン問題(42)第七章 ビットマップ Python編
https://suzukiiichiro.github.io/posts/2023-06-13-05-n-queens-suzuki/
Nクイーン問題(41)第七章 配置フラグ Python編
https://suzukiiichiro.github.io/posts/2023-06-13-04-n-queens-suzuki/
Nクイーン問題(40)第七章 バックトラック Python編
https://suzukiiichiro.github.io/posts/2023-06-13-03-n-queens-suzuki/
Nクイーン問題(39)第七章 バックトラック準備編 Python編
https://suzukiiichiro.github.io/posts/2023-06-13-02-n-queens-suzuki/
Nクイーン問題(38)第七章 ブルートフォース Python編
https://suzukiiichiro.github.io/posts/2023-06-13-01-n-queens-suzuki/
Nクイーン問題(37)第六章 C言語移植 その17 pthread並列処理完成
https://suzukiiichiro.github.io/posts/2023-05-30-17-n-queens-suzuki/
Nクイーン問題(36)第六章 C言語移植 その16 pthreadの実装
https://suzukiiichiro.github.io/posts/2023-05-30-16-n-queens-suzuki/
Nクイーン問題(35)第六章 C言語移植 その15 pthread実装直前版完成
https://suzukiiichiro.github.io/posts/2023-05-30-15-n-queens-suzuki/
Nクイーン問題(34)第六章 C言語移植 その14
https://suzukiiichiro.github.io/posts/2023-05-30-14-n-queens-suzuki/
Nクイーン問題(33)第六章 C言語移植 その13
https://suzukiiichiro.github.io/posts/2023-05-30-13-n-queens-suzuki/
Nクイーン問題(32)第六章 C言語移植 その12
https://suzukiiichiro.github.io/posts/2023-05-30-12-n-queens-suzuki/
Nクイーン問題(31)第六章 C言語移植 その11
https://suzukiiichiro.github.io/posts/2023-05-30-11-n-queens-suzuki/
Nクイーン問題(30)第六章 C言語移植 その10
https://suzukiiichiro.github.io/posts/2023-05-30-10-n-queens-suzuki/
Nクイーン問題(29)第六章 C言語移植 その9
https://suzukiiichiro.github.io/posts/2023-05-30-09-n-queens-suzuki/
Nクイーン問題(28)第六章 C言語移植 その8
https://suzukiiichiro.github.io/posts/2023-05-30-08-n-queens-suzuki/
Nクイーン問題(27)第六章 C言語移植 その7
https://suzukiiichiro.github.io/posts/2023-05-30-07-n-queens-suzuki/
Nクイーン問題(26)第六章 C言語移植 その6
https://suzukiiichiro.github.io/posts/2023-05-30-06-n-queens-suzuki/
Nクイーン問題(25)第六章 C言語移植 その5
https://suzukiiichiro.github.io/posts/2023-05-30-05-n-queens-suzuki/
Nクイーン問題(24)第六章 C言語移植 その4
https://suzukiiichiro.github.io/posts/2023-05-30-04-n-queens-suzuki/
Nクイーン問題(23)第六章 C言語移植 その3
https://suzukiiichiro.github.io/posts/2023-05-30-03-n-queens-suzuki/
Nクイーン問題(22)第六章 C言語移植 その2
https://suzukiiichiro.github.io/posts/2023-05-30-02-n-queens-suzuki/
Nクイーン問題(21)第六章 C言語移植 その1
N-Queens問://suzukiiichiro.github.io/posts/2023-05-30-01-n-queens-suzuki/
Nクイーン問題(20)第五章 並列処理
https://suzukiiichiro.github.io/posts/2023-05-23-02-n-queens-suzuki/
Nクイーン問題(19)第五章 キャリーチェーン
https://suzukiiichiro.github.io/posts/2023-05-23-01-n-queens-suzuki/
Nクイーン問題(18)第四章 エイト・クイーンノスタルジー
https://suzukiiichiro.github.io/posts/2023-04-25-01-n-queens-suzuki/
Nクイーン問題(17)第四章 偉人のソースを読む「N24を発見 Jeff Somers」
https://suzukiiichiro.github.io/posts/2023-04-21-01-n-queens-suzuki/
Nクイーン問題(16)第三章 対象解除法 ソース解説
https://suzukiiichiro.github.io/posts/2023-04-18-01-n-queens-suzuki/
Nクイーン問題(15)第三章 対象解除法 ロジック解説
https://suzukiiichiro.github.io/posts/2023-04-13-02-nqueens-suzuki/
Nクイーン問題(14)第三章 ミラー
https://suzukiiichiro.github.io/posts/2023-04-13-01-nqueens-suzuki/
Nクイーン問題(13)第三章 ビットマップ
https://suzukiiichiro.github.io/posts/2023-04-05-01-nqueens-suzuki/
Nクイーン問題(12)第二章 まとめ
https://suzukiiichiro.github.io/posts/2023-03-17-02-n-queens-suzuki/
Nクイーン問題(11)第二章 配置フラグの再帰・非再帰
https://suzukiiichiro.github.io/posts/2023-03-17-01-n-queens-suzuki/
Nクイーン問題(10)第二章 バックトラックの再帰・非再帰
https://suzukiiichiro.github.io/posts/2023-03-16-01-n-queens-suzuki/
Nクイーン問題(9)第二章 ブルートフォースの再帰・非再帰
https://suzukiiichiro.github.io/posts/2023-03-14-01-n-queens-suzuki/
Nクイーン問題(8)第一章 まとめ
https://suzukiiichiro.github.io/posts/2023-03-09-01-n-queens-suzuki/
Nクイーン問題(7)第一章 ブルートフォース再び
https://suzukiiichiro.github.io/posts/2023-03-08-01-n-queens-suzuki/
Nクイーン問題(6)第一章 配置フラグ
https://suzukiiichiro.github.io/posts/2023-03-07-01-n-queens-suzuki/
Nクイーン問題(5)第一章 進捗表示テーブルの作成
https://suzukiiichiro.github.io/posts/2023-03-06-01-n-queens-suzuki/
Nクイーン問題(4)第一章 バックトラック
https://suzukiiichiro.github.io/posts/2023-02-21-01-n-queens-suzuki/
Nクイーン問題(3)第一章 バックトラック準備編
https://suzukiiichiro.github.io/posts/2023-02-14-03-n-queens-suzuki/
Nクイーン問題(2)第一章 ブルートフォース
https://suzukiiichiro.github.io/posts/2023-02-14-02-n-queens-suzuki/
Nクイーン問題(1)第一章 エイトクイーンについて
https://suzukiiichiro.github.io/posts/2023-02-14-01-n-queens-suzuki/