ページ 1 / 1
自前ライブラリの作り方
Posted: 2014年3月01日(土) 17:21
by mikk
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のソースが難しいので
手を出せない。
と宣言して使える様な自前のライブラリを作る技術がほしいのですが、
以下のようなものであれば、作れますが
コード:
//クラス内プライベート変数二次元配列生成
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の様な自然な配列ライブラリを作る簡単なアイデアを教えていただけないでしょうか?
よろしくおねがいします。
Re: 自前ライブラリの作り方
Posted: 2014年3月01日(土) 17:39
by みけCAT
私の前の投稿ですが、ここに「擬似的な二次元配列を動的に確保するためのクラス」があります。
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;
という書き方ができます。
Re: 自前ライブラリの作り方
Posted: 2014年3月01日(土) 18:00
by mikk
みけCATさん
ご返信ありがとうございます。
擬似的な二次元配列を動的に確保するためのクラス
ソース印刷させていただきました。
テンプレートがイマイチわかっていないので、
がんばって解読します。
目的は対称スカイライン疎行列の足し算と掛け算と修正コレスキー分解の開発で
boostは動的配列の作成が容易で気に入っていたのですが、
対称行列のものがあるのですが、密行列となり、mappedマトリックスでは対称性は考慮できず・・・
意味不明ですみません。ソースありがとうございます。
Re: 自前ライブラリの作り方
Posted: 2014年3月01日(土) 21:16
by かずま
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: 自前ライブラリの作り方
Posted: 2014年3月02日(日) 02:34
by 林_林檎
ちょっと気になったので考えてみました。こんなのはどうでしょう。
行列クラスを作って、カスタマイズして転置の処理を加えました。
コード:
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
と出ます。あんまりよくないかもしれないですが、参考になれば嬉しいです:)
Re: 自前ライブラリの作り方
Posted: 2014年3月09日(日) 13:40
by mikk
お世話になります。
本業が忙しくて。返信送れました。
ソース宝にします。
Re: 自前ライブラリの作り方
Posted: 2014年3月09日(日) 21:25
by かずま
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);
}