行列計算処理のプログラムのエラー
以下の行列計算処理のプログラムをコンパイルしました。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include "rc.h"
#include "memory_manager.h"
#include "math_utl.h"
/** このファイルの関数のプロトタイプ宣言をしたヘッダファイル **/
#include "ファイル名.h"
/** 可能な限り RC 型の関数を定義すること. **/
/** ここでは,全ての関数を RC 型としている. **/
static RC mul_matrix_omp_sub(int l, int m, int n, double **A, double **B, double **C,
int i, int j, int k);
/* ベクトル vect[n] を確保 */
RC allocate_vector(int n, double **vect)
{
int ii1;
/** 想定外の引数が与えられた場合は ARG_ERROR_RC を返却 **/
if(n <= 0) return(ARG_ERROR_RC);
/** NULL ポインタのチェックは RC_NULL_CHK() マクロを使用 **/
RC_NULL_CHK(vect);
/** メモリーの確保には mm_alloc() を使用 **/
/** azlib には無いかも.malloc() で代用可能 **/
*vect = mm_alloc(n*sizeof(double));
RC_NULL_CHK(vect);
for(ii1=0; ii1<n; ii1++) (*vect)[ii1] = 0.0;
return(NORMAL_RC);
}
/* ベクトル vect[n] を解放 */
RC free_vector(int n, double **vect)
{
int ii1;
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK(vect);
for(ii1=0; ii1<n; ii1++) (*vect)[ii1] = 0.0;
/** メモリーの解放には mm_free() を使用 **/
/** azlib には無いかも.free() で代用可能 **/
RC_TRY( mm_free(*vect) );
*vect = NULL;
return(NORMAL_RC);
}
/* 行列 matrix[m][n] を確保 */
RC allocate_matrix(int m, int n, double ***matrix)
{
int ii1;
if(m <= 0) return(ARG_ERROR_RC);
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( matrix );
*matrix = mm_alloc(m*sizeof(double *));
RC_NULL_CHK( *matrix );
for(ii1=0; ii1<m; ii1++){
RC_TRY( allocate_vector(n, &((*matrix)[ii1])) );
}
return(NORMAL_RC);
}
/* 行列 matrix[m][n] を解放 */
RC free_matrix(int m, int n, double ***matrix)
{
int ii1;
if(m <= 0) return(ARG_ERROR_RC);
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( matrix );
for(ii1=0; ii1<m; ii1++){
RC_TRY( free_vector(n, &((*matrix)[ii1])) );
}
RC_TRY( mm_free(*matrix) );
*matrix = NULL;
return(NORMAL_RC);
}
/* ベクトル vect[n] を fp に出力 */
RC print_vector(int n, const double vect[])
{
int ii1;
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( vect );
for(ii1=0; ii1<n; ii1++){
/** 出力は全て log_printf() を使用 **/
/** azlib には無いかも.その場合は fprintf() で代用 **/
if(ii1 > 0) RC_TRY( log_printf(1, ", ") );
RC_TRY( log_printf(1, "%15.7e", vect[ii1]) );
}
RC_TRY( log_printf(1, "\n") );
return(NORMAL_RC);
}
/* 行列 matrix[m][n] を fp に出力 */
RC my_print_matrix(int m, int n, double **matrix)
{
int ii1;
if(m <= 0) return(ARG_ERROR_RC);
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( matrix );
for(ii1=0; ii1<m; ii1++){
RC_TRY( print_vector(n, matrix[ii1]) );
}
return(NORMAL_RC);
}
/* u[n] と v[n] の内積を product に代入 */
/** OPTISHAPE-TS のライブラリ(TSlib)内に同じ名前の関数があったので,先頭に my_ を付けた **/
RC my_inner_product(int n, const double u[], const double v[], double *product)
{
int ii1;
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( u );
RC_NULL_CHK( v );
RC_NULL_CHK( product );
*product = 0.0;
for(ii1=0; ii1<n; ii1++) *product = u[ii1]*v[ii1];
return(NORMAL_RC);
}
/* u[m] と v[n] のテンソル積を matrix[m][n] に代入 */
RC my_tensor_product(int m, const double u[], int n, const double v[], double **matrix)
{
int ii1, ii2;
if(m <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( u );
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( v );
RC_NULL_CHK( matrix );
for(ii1=0; ii1<m; ii1++){
for(ii2=0; ii2<n; ii2++){
matrix[ii1][ii2] = u[ii1]*v[ii2];
}
}
return(NORMAL_RC);
}
/* matrix[m][n] と u[n] の積を v[m] に代入 */
RC mul_matrix_vector(int m, int n, double **matrix, const double u[], double v[])
{
int ii1, ii2;
if(m <= 0) return(ARG_ERROR_RC);
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( matrix );
RC_NULL_CHK( u );
RC_NULL_CHK( v );
for(ii1=0; ii1<m; ii1++){
v[ii1] = 0.0;
for(ii2=0; ii2<n; ii2++){
v[ii1] += matrix[ii1][ii2]*u[ii2];
}
}
return(NORMAL_RC);
}
/* a[l][m] * b[m][n] を c[l][n] に代入 */
RC mul_matrix1(int l, int m, int n, double **a, double **b, double **c)
{
int ii1, ii2, ii3;
double tmp;
if(l <= 0) return(ARG_ERROR_RC);
if(m <= 0) return(ARG_ERROR_RC);
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( a );
RC_NULL_CHK( b );
RC_NULL_CHK( c );
for(ii1=0; ii1<l; ii1++){
for(ii2=0; ii2<n; ii2++){
tmp = 0.0;
for(ii3=0; ii3<m; ii3++){
tmp += a[ii1][ii3]*b[ii3][ii2];
}
c[ii1][ii2] = tmp;
}
}
return(NORMAL_RC);
}
/* a[l][m] * b[m][n] を c[l][n] に代入 */
RC mul_matrix2(int l, int m, int n, double **a, double **b, double **c)
{
int ii1, ii2, ii3;
if(l <= 0) return(ARG_ERROR_RC);
if(m <= 0) return(ARG_ERROR_RC);
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( a );
RC_NULL_CHK( b );
RC_NULL_CHK( c );
for(ii1=0; ii1<l; ii1++){
for(ii2=0; ii2<n; ii2++) c[ii1][ii2] = 0.0;
for(ii2=0; ii2<m; ii2++){
for(ii3=0; ii3<n; ii3++){
c[ii1][ii3] += a[ii1][ii2]*b[ii2][ii3];
}
}
}
return(NORMAL_RC);
}
/* a[l][m] * b[m][n] を c[l][n] に代入 */
RC mul_matrix3(int l, int m, int n, double **a, double **b, double **c)
{
int ii1, ii2, ii3;
if(l <= 0) return(ARG_ERROR_RC);
if(m <= 0) return(ARG_ERROR_RC);
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( a );
RC_NULL_CHK( b );
RC_NULL_CHK( c );
for(ii1=0; ii1<n; ii1++){
for(ii2=0; ii2<l; ii2++) c[ii2][ii1] = 0.0;
for(ii2=0; ii2<m; ii2++){
for(ii3=0; ii3<l; ii3++){
c[ii3][ii1] += a[ii3][ii2]*b[ii2][ii1];
}
}
}
return(NORMAL_RC);
}
/* wa*a[n] + wb*b[n] を c[n] に代入 */
RC wadd_vector(int n, double wa, const double a[], double wb, const double b[], double c[])
{
int ii1;
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( a );
RC_NULL_CHK( b );
RC_NULL_CHK( c );
for(ii1=0; ii1<n; ii1++){
c[ii1] = wa*a[ii1] + wb*b[ii1];
}
return(NORMAL_RC);
}
/* wa*a[m][n] + wb*b[m][n] を c[m][n] に代入 */
RC wadd_matrix(int m, int n, double wa, double **a, double wb, double **b, double **c)
{
int ii1, ii2;
if(m <= 0) return(ARG_ERROR_RC);
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( a );
RC_NULL_CHK( b );
RC_NULL_CHK( c );
for(ii1=0; ii1<m; ii1++){
for(ii2=0; ii2<n; ii2++){
c[ii1][ii2] = wa*a[ii1][ii2] + wb*b[ii1][ii2];
}
}
return(NORMAL_RC);
}
/* src[m][n] を dest[m][n] にコピー */
RC my_copy_matrix(int m, int n, double **src, double **dest)
{
int ii1, ii2;
if(m <= 0) return(ARG_ERROR_RC);
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( src );
RC_NULL_CHK( dest );
for(ii1=0; ii1<m; ii1++){
for(ii2=0; ii2<n; ii2++){
dest[ii1][ii2] = src[ii1][ii2];
}
}
return(NORMAL_RC);
}
/* [A]{x} = {b} をガウスの消去法で解く */
/* [A] は上三角行列に変換されるので注意すること */
/* ピボット選択を省略しているので,対角優位の行列でなければ解けないか */
/* 精度が劣化する可能性がある. */
int gauss_solve(int n, double **A, const double b[], double x[])
{
int ii1, ii2, ii3;
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( A );
RC_NULL_CHK( b );
RC_NULL_CHK( x );
for(ii1=0; ii1<n; ii1++) x[ii1] = b[ii1];
/* 前進消去 */
for(ii1=0; ii1<n; ii1++){
double piv = A[ii1][ii1];
double inv_piv;
if(fabs(piv) < 1.0E20*DBL_MIN) return(CAL_ERROR_RC); /* 最低限のゼロ割回避 */
inv_piv = 1.0/piv;
for(ii2=ii1; ii2<n; ii2++) A[ii1][ii2] *= inv_piv;
x[ii1] *= inv_piv;
for(ii2=ii1+1; ii2<n; ii2++){
double tmp = A[ii2][ii1];
for(ii3=ii1; ii3<n; ii3++){
A[ii2][ii3] -= tmp*A[ii1][ii3];
}
x[ii2] -= tmp*x[ii1];
}
}
/* 後退代入 */
for(ii1=n-1; ii1>=0; ii1--){
for(ii2=ii1+1; ii2<n; ii2++){
x[ii1] -= A[ii1][ii2]*x[ii2];
}
}
return(NORMAL_RC);
}
/* [A]{x} = {b} をLU分解で解く */
/* [A] は下三角が[L],上三角が[U]に変換されるので注意すること */
/* 返還後の対角項は[L]が有し,[U]の対角項は 1 */
/* 解法の安定性は gauss_solve() と同じ */
int LU_solve(int n, double **A, const double b[], double x[])
{
int ii1, ii2, ii3;
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( A );
RC_NULL_CHK( b );
RC_NULL_CHK( x );
/* LU 分解 */
for(ii1=0; ii1<n; ii1++){
double piv = A[ii1][ii1];
double inv_piv;
if(fabs(piv) < 1.0E20*DBL_MIN) return(CAL_ERROR_RC); /* 最低限のゼロ割回避 */
inv_piv = 1.0/piv;
for(ii2=ii1+1; ii2<n; ii2++) A[ii1][ii2] *= inv_piv;
for(ii2=ii1+1; ii2<n; ii2++){
double tmp = A[ii2][ii1];
for(ii3=ii1+1; ii3<n; ii3++){
A[ii2][ii3] -= tmp*A[ii1][ii3];
}
}
}
for(ii1=0; ii1<n; ii1++) x[ii1] = b[ii1];
/* 前進,後退代入 */
for(ii1=0; ii1<n; ii1++){
double piv;
for(ii2=0; ii2<ii1; ii2++){
x[ii1] -= A[ii1][ii2]*x[ii2];
}
piv = A[ii1][ii1];
if(fabs(piv) < 1.0E20*DBL_MIN) return(CAL_ERROR_RC); /* 最低限のゼロ割回避 */
x[ii1] /= piv;
}
for(ii1=n-1; ii1>=0; ii1--){
for(ii2=ii1+1; ii2<n; ii2++){
x[ii1] -= A[ii1][ii2]*x[ii2];
}
}
return(NORMAL_RC);
}
/* 以下は課題16用 */
/** l, m, n をそれぞれブロック化して,独立して計算させることで,並列化とキャッシュの **/
/** ヒット率を上げて高速化を行う. **/
/** BL, BM,, BN は l, m, n それぞれのブロックサイズ **/
#define BL 32
#define BM 32
#define BN 32
RC mul_matrix_omp(int l, int m, int n, double **A, double **B, double **C)
{
int l_block, m_block, n_block;
int ii1;
if(l <= 0) return(ARG_ERROR_RC);
if(m <= 0) return(ARG_ERROR_RC);
if(n <= 0) return(ARG_ERROR_RC);
RC_NULL_CHK( A );
RC_NULL_CHK( B );
RC_NULL_CHK( C );
/** l, m, n より,ブロック数を計算,ブロックサイズに満たない部分も計算するので **/
/** それぞれ切り上げる. **/
l_block = (l + BL -1)/BL;
m_block = (m + BM -1)/BM;
n_block = (n + BN -1)/BN;
/** C[][] は最初に初期化しておき,順次加算するしていく. **/
for(ii1=0; ii1<l; ii1++){
int ii2;
for(ii2=0; ii2<n; ii2++){
C[ii1][ii2] = 0.0;
}
}
/** ここで,OpenMP の並列化を行う.**/
/** 各ブロックの計算時間はスレッド生成のオーバーヘッドより十分大きいと過程し, **/
/** さらに,ブロックサイズに満たないブロックの計算で,各スレッドの実行時間が **/
/** 不均一になると予想されるので,dynamic スケジューリングを使用 **/
/** ループ変数 ii1 はスレッド毎に持つ必要があるので private 変数に指定(念のため) **/
#pragma omp parallel for private(ii1) schedule(dynamic)
for(ii1=0; ii1<l_block*n_block; ii1++){
/** C[][] の各ブロックは行方向(l),列方向(n)問わず独立して処理できるので **/
/** l_block*n_block をまとめて並列処理する.比較的大きなスレッド数を同時実行できる.**/
int ii2;
for(ii2=0; ii2<m_block; ii2++){
/** m 方向のブロック化は,キャッシュのヒット率を向上させるため **/
mul_matrix_omp_sub(l, m, n, A, B, C, ii1/n_block, ii2, ii1%n_block);
}
}
return(NORMAL_RC);
}
/* i, j, k は,それぞれ l, m, n 方向のブロックのインデックス **/
/** A の i,j ブロックと B の j, k ブロックの積を C の i,k ブロックに加算する. **/
static RC mul_matrix_omp_sub(int l, int m, int n, double **A, double **B, double **C,
int i, int j, int k)
{
/** スレッド内で呼び出される関数のローカル変数は,スレッド毎に確保される. **/
int i_size, j_size, k_size;
double blockA[BL][BM];
double blockBt[BN][BM];
int ii1, ii2, ii3;
/** ブロックサイズは,基本的に BL, BM, BN だが,割り切れない場合に半端なサイズの **/
/** ブロックを処理する必要があることに注意 **/
i_size = MIN2(BL, l - i*BL);
j_size = MIN2(BM, m - j*BM);
k_size = MIN2(BN, n - k*BN);
/** A の i,j ブロックをコピー **/
/** この時,後の処理でのメモリーアクセスを考えて転置しておく **/
for(ii1=0; ii1<i_size; ii1++){
for(ii2=0; ii2<j_size; ii2++){
blockA[ii1][ii2] = A[i*BL + ii1][j*BM + ii2];
}
}
/** B の j,k ブロックをコピー **/
for(ii1=0; ii1<j_size; ii1++){
for(ii2=0; ii2<k_size; ii2++){
blockBt[ii2][ii1] = B[j*BM + ii1][k*BN + ii2];
}
}
if((i_size == BL)&&(j_size == BM)&&(k_size == BN)){
/** 典型的な場合,ブロックサイズはそれぞれ BL, BM, BN になるので, **/
/** この部分を特にチューニングする. **/
/** BL, BN は偶数とし,それぞれのループを2段アンローリング(展開)する. **/
/** つまり,1回のループ毎に2回分の処理を行って,ループ回数を1/2にする.**/
for(ii1=0; ii1<BL; ii1+=2){
for(ii2=0; ii2<BN; ii2+=2){
double tmp00 = 0.0;
double tmp01 = 0.0;
double tmp10 = 0.0;
double tmp11 = 0.0;
/** 最内側ループはシンプルに記述し,コンパイラにベクトル化させる.**/
for(ii3=0; ii3<BM; ii3++){
/** 外側のループをアンローリングすることで, **/
/** ロード命令4回,ストア命令0回,積演算4回,和演算4回 **/
/** となっている.(tmp00,01,10,11はレジスタを使うとして) **/
/** アンローリングしない場合は,ロード2回,ストア0回,積1回,和1回 **/
/** つまり,(演算回数/メモリーアクセス回数)の比率高めることができる. **/
/** アンローリングの段数を大きくするとさらに比率を改善できるが,**/
/** 最内側ループで使用するレジスターが不足して逆効果になる. **/
/** ここでは,使用するレジスタの総数は8個(tmp00,01,10,11とa0,1とb0,1 **/
double a0 = blockA[ii1 ][ii3];
double a1 = blockA[ii1 + 1][ii3];
double b0 = blockBt[ii2 ][ii3];
double b1 = blockBt[ii2 + 1][ii3];
tmp00 += a0*b0;
tmp01 += a0*b1;
tmp10 += a1*b0;
tmp11 += a1*b1;
}
C[i*BL + ii1 ][k*BN + ii2 ] += tmp00;
C[i*BL + ii1 ][k*BN + ii2 + 1] += tmp01;
C[i*BL + ii1 + 1][k*BN + ii2 ] += tmp10;
C[i*BL + ii1 + 1][k*BN + ii2 + 1] += tmp11;
}
}
}else{
/** 中途半端なブロックサイズの場合は,全てここで処理する. **/
for(ii1=0; ii1<i_size; ii1++){
for(ii2=0; ii2<k_size; ii2++){
double tmp = 0.0;
for(ii3=0; ii3<j_size; ii3++){
tmp += blockA[ii1][ii3]*blockBt[ii2][ii3];
}
C[i*BL + ii1][k*BN + ii2] += tmp;
}
}
}
return(NORMAL_RC);
}
以下にファイル名.hのコードを示します。
#ifndef ファイル名_H
#define ファイル名_H
RC allocate_vector(int n, double **vect);
RC free_vector(int n, double **vect);
RC allocate_matrix(int m, int n, double ***matrix);
RC free_matrix(int m, int n, double ***matrix);
RC print_vector(int n, const double vect[]);
RC my_print_matrix(int m, int n, double **matrix);
RC my_inner_product(int n, const double u[], const double v[], double *product);
RC my_tensor_product(int m, const double u[], int n, const double v[], double **matrix);
RC mul_matrix_vector(int m, int n, double **matrix, const double u[], double v[]);
RC mul_matrix1(int l, int m, int n, double **a, double **b, double **c);
RC mul_matrix2(int l, int m, int n, double **a, double **b, double **c);
RC mul_matrix3(int l, int m, int n, double **a, double **b, double **c);
RC wadd_vector(int n, double wa, const double a[], double wb, const double b[], double c[]);
RC wadd_matrix(int m, int n, double wa, double **a, double wb, double **b, double **c);
RC my_copy_matrix(int m, int n, double **src, double **dest);
RC gauss_solve(int n, double **A, const double b[], double x[]);
RC LU_solve(int n, double **A, const double b[], double x[]);
RC mul_matrix_omp(int l, int m, int n, double **A, double **B, double **C);
RC mul_matrix_omp2(int l, int m, int n, double **A, double **B, double **C);
#endif /* ファイル名_H */
コンパイルの結果、以下のようなエラーがでてしまいます。
ファイル名.c:337:5: error: conflicting types for ‘gauss_solve’
int gauss_solve(int n, double **A, const double b[], double x[])
^
In file included from ファイル名.c:8:0:
ファイル名.h:19:4: note: previous declaration of ‘gauss_solve’ was here
RC gauss_solve(int n, double **A, const double b[], double x[]);
^
ファイル名.c:383:5: error: conflicting types for ‘LU_solve’
int LU_solve(int n, double **A, const double b[], double x[])
^
In file included from ファイル名.c:8:0:
ファイル名.h:20:4: note: previous declaration of ‘LU_solve’ was here
RC LU_solve(int n, double **A, const double b[], double x[]);
^
どのように訂正すればよいのか分からず困っております。
よろしくお願いいたします。