おいも貴婦人ブログ

生物系博士課程満期退学をしたAIエンジニアのブログ。

続:2次元イジングモデル

前回の2次元イジングモデルのコードをCで書きなおしてみました。unixの標準コマンドtimeを使って、openmpありとなしの実行時間を計算してみます。2次元の行列サイズは1024x1024、ループ回数は1000です。コード中のMT.hは乱数を生成するためにメルセンヌツイスターを使用しているからです。

環境
結果


openmptime
Yes(10cores)4.017s
No10.963s

コード
#include <stdio.h>
#include <stdlib.h>
#include "MT.h"
#include <omp.h>
#include <math.h>

float calcE(int *m,int row,int col){
    int i,j,nx,ny;
    float J = 1;
    float E = 0;
    #pragma omp parallel num_threads(10)
    {
    #pragma omp for private(i,j),reduction(+:E)
    for(i=0;i<col;i++){
        for(j=0;j<row;j++){
            nx = j;
            ny = (i+1)%col;
            E += -J * m[i*col+j]*m[ny*col+nx];

            nx = (j+1)%row;
            ny = i;
            E += -J * m[i*col+j]*m[ny*col+nx];
            
            nx = j;
            ny = ((i-1)%col != -1) ? i : col;
            E += -J * m[i*col+j]*m[ny*col+nx];

            nx = ((j-1)%row != -1) ? j : row;
            ny = i;
            E += -J * m[i*col+j]*m[ny*col+nx];
        }
    }
    #pragma omp barrier
    }
    return E;
}

int copy(int *dst,int *src,int size){
    int i;
    for(i=0;i<size;i++)
        dst[i]=src[i];
    return(0);
}

int init(int *m,int size){
    int i;
    int sign[] = {-1,1};

    for(i=0;i<size;i++)
        m[i] = sign[genrand_int32()%2];
    return(0);
}

void MC(int *m,int row,int col,int nstep){
    int i;
    int mp;
    int size = row*col;
    int *tmpm = (int *) malloc(sizeof(int)*size);
    float Epre,Eafter;
    float prob;
    float T = 0.5;
    float invT = 1/T;
    
    for(i=0;i<nstep;i++){
        mp = genrand_int32()%size;
        copy(tmpm,m,size);
        tmpm[mp] = -tmpm[mp];
        Epre = calcE(m,row,col);
        Eafter = calcE(tmpm,row,col);

        if (Eafter < Epre)
            copy(m,tmpm,size);
        else{
            prob = genrand_real1();
            if(prob < exp(-(Eafter-Epre)*invT))
                copy(m,tmpm,size);
        }
        printf("%lf\n",Eafter);
    }
}

int main(void){
    int bsize = 10;
    int row = 1<<bsize;
    int col = 1<<bsize;
    int size = row * col;
    int nstep = 1000;
    int seed = 1;
    int *mat;    

    init_genrand(seed);

    mat = (int *) malloc(sizeof(int)*size);
    init(mat,size);

    MC(mat,row,col,nstep);
    free(mat);
    return(0);
}
2015/11/12:追記
float calcE(int *m,int row,int col){
    int i,j,nx,ny;
    float J = 1;
    float E = 0;
    #pragma omp parallel num_threads(10)
    {
    #pragma omp for private(i,j),reduction(+:E)
    for(i=0;i<col;i++){
        for(j=0;j<row;j++){
            nx = j;
            ny = (i+1)%col;
            E += -J * m[i*col+j]*m[ny*col+nx];

            nx = (j+1)%row;
            ny = i;
            E += -J * m[i*col+j]*m[ny*col+nx];
            
            nx = j;
            ny = ((i-1)%col != -1) ? i : col;
            E += -J * m[i*col+j]*m[ny*col+nx];

            nx = ((j-1)%row != -1) ? j : row;
            ny = i;
            E += -J * m[i*col+j]*m[ny*col+nx];
        }
    }
    #pragma omp barrier
    }
    return E;
}

は正しくは

float calcE(int *m,int row,int col){
    int i,j,nx,ny;
    float J = 1;
    float E = 0;
    #pragma omp parallel num_threads(10)
    #pragma omp for private(i,j),reduction(+:E)
    for(i=0;i<row;i++){
        for(j=0;j<col;j++){
            nx = i;
            ny = (j+1)%col;
            E += -J * m[i*row+j]*m[nx*row+ny];

            nx = (i+1)%row;
            ny = j;
            E += -J * m[i*row+j]*m[nx*row+ny];

            nx = i;
            ny = ((j-1)%col != -1) ? j-1 : col-1;
            E += -J * m[i*row+j]*m[nx*row+ny];
            
            nx = ((i-1)%row != -1) ? i-1 : row-1;
            ny = j;
            E += -J * m[i*row+j]*m[nx*row+ny];
        }
    }
    #pragma omp barrier

    return E;
}