web-dev-qa-db-ja.com

C ++マトリックスクラス

Cでは、マトリックス構造体を作成する場合、次を使用します。

struct matrix {
  int col, row;
  double data[1]; // I want the matrix entries stored
                  // right after this struct
}

その後、私はそれを割り当てることができます

matrix* allocate_matrix(int row, int col) {
  matrix* m = malloc(sizeof(matrix) + sizeof(double) * (row * col - 1));
  m->row = row; m->col = col;
  return m;
}

今、C++でequivを実行しますか?

編集:

C++で行列クラスを実装する標準的な方法を知りたいです。

25
anon

nota bene。

この回答には現在20の賛成票がありますが、それは_std::valarray_の支持を意図したものではありませんです。

私の経験では、 Eigen のような本格的な数学ライブラリのインストールと使用の学習に時間を費やした方が良いでしょう。 Valarrayの機能は競合製品よりも少ないですが、より効率的ではなく、特に使いやすいものでもありません。

ほんの少しの線形代数が必要なだけで、ツールチェーンに何かを追加することに対して行き詰まっているなら、おそらくvalarrayが適合するでしょう。しかし、あなたの問題に対する数学的に正しい解決策を表現できないまま立ち往生することは、非常に悪い立場にあります。数学は容赦なく容赦しません。ジョブに適したツールを使用します。


標準ライブラリは _std::valarray<double>_ を提供します。 _std::vector<>_は、ここで他のいくつかによって提案され、オブジェクトの汎用コンテナとして意図されています。 valarrayは、より専門化されているため(C++の用語として "specialized"を使用しない)、あまり知られていないが、いくつかの利点があります。

  • 余分なスペースは割り当てられません。 vectorは割り当て時に最も近い2のべき乗に切り上げられるため、毎回再割り当てすることなくサイズを変更できます。 (valarrayのサイズは変更できますが、realloc()と同じくらい高価です。)
  • 簡単に行と列にアクセスするためにスライスできます。
  • 算術演算子は期待どおりに機能します。

もちろん、Cを使用することの利点は、メモリを管理する必要がないことです。ディメンションは、スタックまたはスライスオブジェクトに配置できます。

_std::valarray<double> matrix( row * col ); // no more, no less, than a matrix
matrix[ std::slice( 2, col, row ) ] = pi; // set third column to pi
matrix[ std::slice( 3*row, row, 1 ) ] = e; // set fourth row to e
_
38
Potatoswatter

C++は、ほとんどがCのスーパーセットです。自分がやっていることを続けることができます。

とはいえ、C++では、独自のメモリを管理する適切なMatrixクラスを定義する必要があります。たとえば、内部の_std::vector_によって裏付けられ、_operator[]_またはoperator()をオーバーライドして、ベクトルに適切にインデックスを付けることができます(たとえば、以下を参照してください: How Matrixクラスに添え字演算子を作成しますか? )C++ FAQから。

開始するには:

_class Matrix
{
public:
    Matrix(size_t rows, size_t cols);
    double& operator()(size_t i, size_t j);
    double operator()(size_t i, size_t j) const;

private:
    size_t mRows;
    size_t mCols;
    std::vector<double> mData;
};

Matrix::Matrix(size_t rows, size_t cols)
: mRows(rows),
  mCols(cols),
  mData(rows * cols)
{
}

double& Matrix::operator()(size_t i, size_t j)
{
    return mData[i * mCols + j];
}

double Matrix::operator()(size_t i, size_t j) const
{
    return mData[i * mCols + j];
}
_

(上記は境界チェックを行わないことに注意してください。double以外の場合に機能するように、テンプレートの演習として残しておきます。)

20
jamesdlin

効率的で高品質のマトリックスクラスを設定するには、多くの微妙な点があります。ありがたいことに、いくつかの優れた実装が浮かんでいます。

固定サイズのマトリックスクラスと可変サイズのマトリックスクラスのどちらが必要かをよく考えてください。つまり、これを行うことができます:

// These tend to be fast and allocated on the stack.
matrix<3,3> M; 

またはあなたはこれを行うことができる必要がありますか

// These are slower but more flexible and partially allocated on the heap 
matrix M(3,3); 

いずれかのスタイルをサポートする優れたライブラリと、両方をサポートするライブラリがあります。割り当てパターンとパフォーマンスが異なります。

自分でコーディングしたい場合、テンプレートバージョンにはテンプレートの知識が必要です(duh)。そして、動的なものは、タイトなループ内で使用される場合、多くの小さな割り当てを回避するためにいくつかのハックを必要とします。

4

次のようなテンプレートを使用できます。

#include <iostream>
using std::cerr;
using std::endl;

//qt4type
typedef unsigned int quint32;

template <typename T>
void deletep(T &) {}
template <typename T>
void deletep(T* & ptr) {
    delete ptr;
    ptr = 0;
}
template<typename T>
class Matrix {
    public:
        typedef T value_type;
        Matrix() : _cols(0), _rows(0), _data(new T[0]), auto_delete(true) {};
        Matrix(quint32 rows, quint32 cols, bool auto_del = true);

        bool exists(quint32 row, quint32 col) const;
        T & operator()(quint32 row, quint32 col);
        T operator()(quint32 row, quint32 col) const;
        virtual ~Matrix();

        int size() const { return _rows * _cols; }
        int rows() const { return _rows; }
        int cols() const { return _cols; }
    private:
        Matrix(const Matrix &);
        quint32 _rows, _cols;
        mutable T * _data;
        const bool auto_delete;
};
template<typename T>
Matrix<T>::Matrix(quint32 rows, quint32 cols, bool auto_del) : _rows(rows), _cols(cols), auto_delete(auto_del) {
    _data = new T[rows * cols];
}
template<typename T>
inline T & Matrix<T>::operator()(quint32 row, quint32 col) {
    return _data[_cols * row + col];
}
template<typename T>
inline T Matrix<T>::operator()(quint32 row, quint32 col) const {
    return _data[_cols * row + col];
}

template<typename T>
bool Matrix<T>::exists(quint32 row, quint32 col) const {
    return (row < _rows && col < _cols);
}

template<typename T>
Matrix<T>::~Matrix() {
    if(auto_delete){
        for(int i = 0, c = size(); i < c; ++i){
            //will do nothing if T isn't a pointer
            deletep(_data[i]);
        }
    }
    delete [] _data;
}

int main() {
    Matrix< int > m(10,10);
    quint32 i = 0;
    for(int x = 0; x < 10; ++x) {
        for(int y = 0; y < 10; ++y, ++i) {
            m(x, y) = i;
        }
    }
    for(int x = 0; x < 10; ++x) {
        for(int y = 0; y < 10; ++y) {
            cerr << "@(" << x << ", " << y << ") : " << m(x,y) << endl;
        }
    }
}

*編集、タイプミスを修正。

3
OneOfOne

あなたはcouldできました。唯一の違いは、mallocから結果をキャストする必要があることです。

むしろ、計算されたインデックス付きの1D配列または埋め込みベクトルとして、vectorを使用します。 (前者はあなたのコードによりよくマッチします。)

例えば:

template <typename T> // often, they are templates
struct matrix
{
    // should probably be hidden away, and the class would
    // provide `at` and `operator()` for access
    int col, row;
    std::vector<T> data;

    matrix(int columns, int rows) :
    col(columns), row(rows), 
    data(col * row)
    {}

}

matrix m(4, 4);
m.data[1 + 1 * 4] = /* ... */;

または:

template <typename T>
struct matrix
{
    int col, row;
    std::vector<std::vector<T> > data;

    matrix(int columns, int rows) :
    col(columns), row(rows), 
    data(col, std::vector(row))
    {}
}

matrix m(4, 4);
m.data[1][1] = /* ... */;

しかし、これらは単なる例です。本格的なクラスを作りたいと思うでしょう。さらにアドバイスが必要な場合は、質問を編集して、マトリックスクラスを実装する標準的な方法を知りたいことを明確にしてください。

既存のマトリックスクラスがあります。私のお気に入りは、ブーストからのものです [〜#〜] ublas [〜#〜]

3
GManNickG

マトリックスクラスの場合、[]演算子のオーバーロードを避けてください。
を参照してください C++ FAQ 13.1

また、いくつかのフリーウェアのMatrixクラスをWebで検索してください。最悪の場合、彼らはあなたにガイダンスを与えることができます。最適なケースは、記述する必要のあるソフトウェアが少ないおよびdebugです。

2
Thomas Matthews

コンパイル時に行列サイズがわかっている場合は、テンプレートを使用してそれを行うことができます。

template <int width, int height>
class Matrix{
    double data[height][width];
    //...member functions
};
2
J.Colmsee

非常に多くの機能をサポートする Matrix library を作成しました。

そのドキュメントから:

このライブラリは、乗算、行列式、マイナー、コファクターなどの数学演算子をサポートしています。

使用法

その使用法はc ++配列に似ています。

Matrix<int> A(1, 2);
Matrix<int> B(2, 3);
Matrix<int> result(1, 3);

A[0][0] = 7;
A[0][1] = 10;

B[0][0] = 1;
B[0][1] = 4;
B[0][2] = 2;
B[1][0] = 1;
B[1][1] = 2;
B[1][2] = 100;

result = A * B;

result.dump.matrix();

結果:

Matrix view:
-            -
| 17 48 1014 |
-            -

ドキュメント

1
Amir Forsati

Githubリンク

//
//  iBS_Matrix.h
//
//
//  Created by nash on 11/29/15.
//  Copyright 2015 iBean Software.
//  All rights reserved.
//  current copy on Github:
//
#ifndef iBS_Matrix_h
#define iBS_Matrix_h

const int Matrix_MAJOR_VERSION = 1;
const int Matrix_MINOR_VERSION = 0;

#include <iostream>
#include <vector>
namespace iBS
{
struct Matrix 
{
    std::vector<std::vector<int> > a; 

    Matrix& operator =(Matrix& o)
    {
        a.resize(o.a.size());
        for(int i=0;i<a.size();i++)
            a[i].resize(o.a[i].size());
        for(int i=0;i<a.size();i++) 
            for(int j=0;j<a[i].size();j++) 
            {
                a[i][j] = o.a[i][j];
            }
        return *this;
    }

    Matrix& operator +(Matrix& o)
    {
        for(int i=0;i<a.size();i++) 
            for(int j=0;j<a[i].size();j++) 
            {
                a[i][j] = a[i][j] + o.a[i][j];
            }
        return *this;
    }
    Matrix& operator -(Matrix& o)
    {
        for(int i=0;i<a.size();i++) 
            for(int j=0;j<a[i].size();j++) 
            {
                a[i][j] = a[i][j] - o.a[i][j];
            }
        return *this;
    }
    Matrix& operator *(Matrix& o)
    {
        if(a[0].size() != o.a.size()) return *this;

        Matrix tm;
        tm.a.resize(a.size());
        for(int i=0;i<tm.a.size();i++)
            tm.a[i].resize(o.a[0].size());

        for(int i=0;i<tm.a.size();i++) 
            for(int j=0;j<tm.a[i].size();j++) 
            {
                tm.a[i][j] = 0;
                for (int c=0; c<a[i].size(); c++) 
                {
                    tm.a[i][j] += a[i][c] * o.a[c][j];
                }

            }
        *this = tm;
        return *this;
    }
    Matrix& operator ^(int power)
    {
        Matrix  tM2;
        tM2 = *this;

    //   not <= below \/ because first time counts as 2
        for(int i=1; i<power; ++i)
            *this = (*this) * (tM2);

        return *this;
    }

    void print()
    {
        for(int i=0;i<a.size();i++) 
        {
            for(int j=0;j<a[i].size();j++) 
            {
                std::cout << a[i][j] << ' ';
            }
            std::cout << std::endl;
        }
        std::cout << std::endl;
    }
};

}; // end of namespace iBS

#endif // iBS_Matrix_h
0
Nash Bean

C++でマトリックスを実行する「標準的な」方法はありません。STLは「マトリックス」のようなクラスを提供しません。ただし、サードパーティ製のライブラリがいくつかあります。それらを使用するか、独自の実装を作成することをお勧めします。

0
ivan.ukr