自前ライブラリの作り方

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
mikk

自前ライブラリの作り方

#1

投稿記事 by mikk » 12年前

C++にboostライブラリを使っており
以下のような使い方をしています。

コード:

 
using namespace boost::numeric::ublas;
using namespace boost;
#include <boost/numeric/ublas/matrix.hpp>

typedef boost::numeric::ublas::vector         <double>  dbVector;
typedef boost::numeric::ublas::matrix         <double>  dbMatrix;

void Sub(void){
	dbMatrix A(10,10);
	A(2,3)=5.0
return 0
}


すこし使い勝手を改良したいのですが、boostのソースが難しいので
手を出せない。

コード:

 
	MyMatrix A(10,10);


と宣言して使える様な自前のライブラリを作る技術がほしいのですが、
以下のようなものであれば、作れますが

コード:

 
//クラス内プライベート変数二次元配列生成
double MyArr[10][10]//←ちょっとあやしいが、
double getA(int i,int j){
	return MyArr[i][j];
}
void setArr(int i,int j,double Value){
	MyArr[i][j]=Value;
	return 0;
}

//これだと、配列風には使えなくて
	setArr(2,3,5.0);
	double d=getArr(2,3);
//のように不細工です。
boostの様な自然な配列ライブラリを作る簡単なアイデアを教えていただけないでしょうか?

よろしくおねがいします。

アバター
みけCAT
記事: 6734
登録日時: 15年前
住所: 千葉県
連絡を取る:

Re: 自前ライブラリの作り方

#2

投稿記事 by みけCAT » 12年前

私の前の投稿ですが、ここに「擬似的な二次元配列を動的に確保するためのクラス」があります。
http://dixq.net/forum/viewtopic.php?f=3&t=14608#p116118
A(2,3)=5.0のような書き方ができるようにする方法は自分にはわかりませんが、
「配列風」に

コード:

virtual_2d_array<double> A(10,10);
A[2][3]=5.0;
という書き方ができます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

mikk

Re: 自前ライブラリの作り方

#3

投稿記事 by mikk » 12年前

みけCATさん
ご返信ありがとうございます。

擬似的な二次元配列を動的に確保するためのクラス
ソース印刷させていただきました。
テンプレートがイマイチわかっていないので、
がんばって解読します。

目的は対称スカイライン疎行列の足し算と掛け算と修正コレスキー分解の開発で
boostは動的配列の作成が容易で気に入っていたのですが、
対称行列のものがあるのですが、密行列となり、mappedマトリックスでは対称性は考慮できず・・・

意味不明ですみません。ソースありがとうございます。

かずま

Re: 自前ライブラリの作り方

#4

投稿記事 by かずま » 12年前

mikk さんが書きました:boostの様な自然な配列ライブラリを作る簡単なアイデアを教えていただけないでしょうか?

コード:

#include <iostream>

class MyMatrix {
public:
    MyMatrix(int n, int m) : row(m) { data = new double[n * m]; } 
    ~MyMatrix() { delete[] data; }
    double *operator[](int i) { return data + i*row; }
private:
    int row;
    double *data;
};

int main()
{
    int n = 3, m = 4;
    MyMatrix a(n, m);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            a[i][j] = (i + 1.0) + (j + 1.0) / 100;
            std::cout << "  " << &a[i][j];
        }
        std::cout << std::endl;
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++)
            std::cout << "  " << a[i][j];
        std::cout << std::endl;
    }
}
こんなのはいかがでしょうか?
ちゃんとアドレスが連続しているし、a[j] でアクセスできます。

林_林檎

Re: 自前ライブラリの作り方

#5

投稿記事 by 林_林檎 » 12年前

ちょっと気になったので考えてみました。こんなのはどうでしょう。
行列クラスを作って、カスタマイズして転置の処理を加えました。

コード:

class IntMatrix2D
{
private:
	int* entity;		// 要素を用意するためだけに必要
	int** elements;		// 行列そのもの
	int nRows, nCols;	// 行/列数

	// 新しい行列作成
	void NewMatrix(int rows, int cols)
	{
		if( entity != nullptr )
		{
			delete[] elements;
			delete[] entity;
		}

		nRows = rows, nCols = cols; 

		entity = new int[nRows * nCols];
		elements = new int*[nRows];
		
		// elements の各行に entity の nCols * n 番目を割り当てて二次元配列を作る
		for(int i=0; i<nRows; i++)
		{
			elements[i] = entity + (nCols * i);
		}
	}

	// 中の行列をコピー
	void SubstituteMatrix(const IntMatrix2D& srcMat)
	{
		for(int i=0; i<nRows; i++)
		{
			for(int j=0; j<nCols; j++)
			{
				elements[i][j] = srcMat.elements[i][j];
			}
		}
	}

public:
	// コンストラクタ
	IntMatrix2D(int rows, int cols) :
		entity(nullptr)
	{
		NewMatrix(rows, cols);
	}

	// コピーコンストラクタ
	IntMatrix2D(const IntMatrix2D& mat) :
		entity(nullptr)
	{
		NewMatrix(mat.nRows, mat.nCols);
		SubstituteMatrix(mat);
	}

	// デストラクタ
	~IntMatrix2D()
	{
		delete[] elements;
		delete[] entity;
	}

	// 代入
	IntMatrix2D& operator=(const IntMatrix2D& mat)
	{
		SubstituteMatrix(mat);
		return *this;
	}

	// 要素をゲット
	int& at(int row, int col) { return elements[row][col]; }
	
	// ゼロセット
	void ZeroMatrix()
	{
		for(int i=0; i<nRows; i++)
		{
			for(int j=0; j<nCols; j++)
			{
				elements[i][j] = 0;
			}
		}
	}

	// 転置
	IntMatrix2D& Transpose()
	{
		IntMatrix2D OldMatrix(*this);

		NewMatrix(OldMatrix.nCols, OldMatrix.nRows);

		for(int i=0; i<nRows; i++)
		{
			for(int j=0; j<nCols; j++)
			{
				elements[i][j] = OldMatrix.elements[j][i];
			}
		}

		return *this;
	}

	// 表示
	void Show()
	{
		for(int i=0; i<nRows; i++)
		{
			for(int j=0; j<nCols; j++)
			{
				printf("%d ", elements[i][j] );
			}

			printf("\n");
		}
		printf("\n");
	}

	// 添え字演算子は使うことができない
//	int& operator[](int pos)
//	{
//		return *(*elements+pos);
//	}

};
ごちゃごちゃするけど、long int とか double で使うためにテンプレートで書くと下記のようになります。

コード:

template<class T>
class Matrix2D
{
private:
	T* entity;
	T** elements;
	int nRows, nCols;

	void NewMatrix(int rows, int cols);
	void SubstituteMatrix(const Matrix2D& srcMat);

public:
	Matrix2D(int rows, int cols);
	Matrix2D(const Matrix2D& mat);
	~Matrix2D();
	
	Matrix2D& operator=(const Matrix2D& mat);
	T& at(int row, int col);

	void ZeroMatrix();
	Matrix2D& Transpose();
	void Show();

};

template <class T>
void Matrix2D<T>::NewMatrix(int rows, int cols)
{
	if( entity != nullptr )
	{
		delete[] elements;
		delete[] entity;
	}

	nRows = rows, nCols = cols; 

	entity = new T[nRows * nCols];
	elements = new T*[nRows];
		
	for(int i=0; i<nRows; i++)
	{
		elements[i] = entity + (nCols * i);
	}
}

template <class T>
void Matrix2D<T>::SubstituteMatrix(const Matrix2D& srcMat)
{
	for(int i=0; i<nRows; i++)
	{
		for(int j=0; j<nCols; j++)
		{
			elements[i][j] = srcMat.elements[i][j];
		}
	}
}
	
template <class T>
Matrix2D<T>::Matrix2D(int rows, int cols) :
	entity(nullptr)
{
	NewMatrix(rows, cols);
}

template <class T>
Matrix2D<T>::Matrix2D(const Matrix2D& mat) :
	entity(nullptr)
{
	NewMatrix(mat.nRows, mat.nCols);
	SubstituteMatrix(mat);
}

template <class T>
Matrix2D<T>::~Matrix2D()
{
	delete[] elements;
	delete[] entity;
}

template <class T>
Matrix2D<T>& Matrix2D<T>::operator=(const Matrix2D& mat)
{
	SubstituteMatrix(mat);
	return *this;
}

template <class T>
T& Matrix2D<T>::at(int row, int col)
{
	return elements[row][col];
}

template <class T>
void Matrix2D<T>::ZeroMatrix()
{
	for(int i=0; i<nRows; i++)
	{
		for(int j=0; j<nCols; j++)
		{
			elements[i][j] = 0;
		}
	}
}

template <class T>
Matrix2D<T>& Matrix2D<T>::Transpose()
{
	Matrix2D OldMatrix(*this);

	NewMatrix(OldMatrix.nCols, OldMatrix.nRows);

	for(int i=0; i<nRows; i++)
	{
		for(int j=0; j<nCols; j++)
		{
			elements[i][j] = OldMatrix.elements[j][i];
		}
	}
	
	return *this;
}

template <class T>
void Matrix2D<T>::Show()
{
	for(int i=0; i<nRows; i++)
	{
		for(int j=0; j<nCols; j++)
		{
			printf("%d ", elements[i][j] );
		}

		printf("\n");
	}
	printf("\n");
}
イカのように使います。

コード:

int main()
{
	IntMatrix2D Mat1(3, 4);
	IntMatrix2D Mat2(4, 3);

	Mat1.ZeroMatrix();
	Mat1.at(0, 0) = 1;
	Mat1.at(0, 1) = 2;
	Mat1.at(0, 2) = 3;
	Mat1.at(1, 2) = 4;

	Mat1.Show();

	Mat2 = Mat1.Transpose();

	Mat2.Show();



	Matrix2D<int> Mat3(3, 4);
	Matrix2D<int> Mat4(4, 3);
	
	Mat3.ZeroMatrix();
	Mat3.at(0, 0) = 1;
	Mat3.at(0, 1) = 2;
	Mat3.at(0, 2) = 3;
	Mat3.at(1, 2) = 4;

	Mat3.Show();

	Mat4 = Mat3.Transpose();
	
	for(int i=0; i<4; i++)
	{
		for(int j=0; j<3; j++)
		{
			printf("%d ", Mat4.at(i, j) );
		}

		printf("\n");
	}
	printf("\n");



	int a;
	scanf("%d", &a);

	return 0;
}
すると出力は

1 2 3 0
0 0 4 0
0 0 0 0

1 0 0
2 0 0
3 4 0
0 0 0

1 2 3 0
0 0 4 0
0 0 0 0

1 0 0
2 0 0
3 4 0
0 0 0

と出ます。あんまりよくないかもしれないですが、参考になれば嬉しいです:)

mikk

Re: 自前ライブラリの作り方

#6

投稿記事 by mikk » 12年前

お世話になります。

本業が忙しくて。返信送れました。

ソース宝にします。

かずま

Re: 自前ライブラリの作り方

#7

投稿記事 by かずま » 12年前

mikk さんが書きました:ソース宝にします。
できそこないのソースで申し訳ありません。

コード:

MyMatrix(int n, int m) : row(m) { data = new double[n * m]; }
行列(matrix) の行(row) と列(column) を逆にしていました。
m と n も逆だったので、ちゃんと動きますが、直しておきます。
また、data はポインタですが、ポインタをメンバに持つクラスでは
コピーコンストラクタと代入演算子を定義しないと、不具合が出る
場合があるので、それも追加しておきます。
さらに、要素の型を double に限定したくないのでテンプレートにします。

コード:

#include <iostream>
#include <algorithm>  // copy

template<typename T>
class MyMatrix {
public:
    MyMatrix(int m, int n) : row(m), col(n), data(new T[m * n]) {} 
    MyMatrix(const MyMatrix& x)
        : row(x.row), col(x.col), data(new T[row * col]) {
        std::copy(x.data, x.data + row * col, data);
    }
    ~MyMatrix() { delete[] data; }
    MyMatrix& operator=(const MyMatrix& x) {
        if (&x != this) {
            if (row != x.row || col != x.col) {
                col = x.row, col = x.col;
                delete[] data;
                data = new T[row * col];
            }
            std::copy(x.data, x.data + row * col, data);
        }
        return *this;
    }
    T *operator[](int i) { return data + i * col; }
    void print(std::ostream& o) {
        for (int i = 0; i < row; i++) {
            T *p = data + i * col;
            for (int j = 0; j < col; j++)
                o << "  " << p[j];
            o << std::endl;
        }
        o << std::endl;
    }
private:
    int col, row;
    T *data;
};

int main()
{
    int m = 3, n = 4;
    MyMatrix<double> a(m, n);
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            a[i][j] = (i + 1.0) + (j + 1.0) / 100;
            std::cout << "  " << &a[i][j];
        }
        std::cout << std::endl;
    }
    std::cout << std::endl;
    a.print(std::cout);
    MyMatrix<double> b = a;
    b.print(std::cout);
}

閉鎖

“C言語何でも質問掲示板” へ戻る