自分用の 行列ライブラリ のメモです.
依存関係
AO.cc (Algebra Operations) に依存する … と思う (最近チェックしていない.ひょっとしたら違うかも)
型
要素の型を T として,Matrix<T> が,行列の型になる.
以下,要素の型を T とし,MyMat = Matrix<T> と定義されているものとする.
mat は MyMat 型とする.
使用法
using MyMat = Matrix<ll>;
MyMat mat1(n, m);
REP(i, 0, n) REP(j, 0, m) cin >> mat1.at(i, j);
MyMat cvec1(n, 1);
REP(i, 0, n) cin >> cvec1.at(i, 0);
auto cvec2 = mat1 * cvec1;
REP(i, 0, n) cout << cvec2.at(i, 0) << " ";
cout << endl;
構築子
MyMat(int dimI_, int dimJ_)… dimI_ 行 dimJ_ 列 の零行列MyMat(int dimI_, int dimJ_, T t)… dimI_ 行 dimJ_ 列 の,要素の値がすべてtである行列MyMat(int dimI_, int dimJ_, const vector<T>& vec)… dimI_ 行,dimJ_ 列で,内部表現が vec である行列.- 内部表現は,$a_{00}, a_{01}, \dots, a_{10}, a_{11}, \dots a_{mn}$ の順に並べた1次元 vector.
- dimI_ と dimJ_ のどちらかは負の数にすることができて,その場合には計算される.
MyMat(int dimI_, int dimJ_, vector<T>&& vec)… 同上MyMat(initializer_list<initializer_list<T>> il)… 自然にMyMat(const Part& cs)… 構造体 Part については後述
その他,行列を作る関数
MyMat::from_vvec(const vector<vector<T>>& vvec)… 2次元ベクトルからMyMat 型行列を作成する.mat.rowVec(i)… 第 i 行目を表す MyMat 型行列mat.colVec(i)… 第 i 列目を表す MyMat 型行列
要素へのアクセス
mat.at(i, j)… (i, j) 要素の値mat.rs(i, j)… (i, j) 要素への代入- rs は,実際,
MyMat&を返すので,値も取れる.mat.rs(i, j) += 1;のようなコードも書ける.
- rs は,実際,
ベクトルと $(n, 1)$ 行列
- 長さ n のベクトル vec を,MyMat オブジェクトに変換するときには,
- 縦長 (n, 1) 行列とみるときには,
MyMat m = MyMat(n, 1, vec)もしくはMyMat m = MyMat(-1, 1, vec)とすればよい. - 横花 (1, n) 行列とみるときには,
MyMat m = MyMat(1, n, vec)もしくはMyMat m = MyMat(1, -1, vec)とすればよい.
- 縦長 (n, 1) 行列とみるときには,
- (n, 1) 行列 もしくは (1, n) 行列を表す MyMat 型のオブジェクト
matをvector<T>に変換するときには,mat.memを取れば良い.
ただし,$(n, n)$ 行列と$(n, 1)$ 縦ベクトルの積を作るときには,
MyMat * vector<T> のオーバーライドを使う方が簡単である.下の「演算」を参照.
零行列,単位行列
型には行列のサイズが含まれないので,これらを static member function として定義することは難しい. そこで,何らかのオブジェクトを作って,「それと同じサイズの」零行列や単位行列が作れるようにしてある.
mat.zero()… mat と同じサイズの零行列mat.unit()… mat と同じサイズの単位行列.mat の行と列の大きさは一致していなければならない.
小行列を表す構造体 Part
- 構築子:
Part(const Mat& mat_, int i_size_ = -1, int j_size_ = -1, int i_0_ = 0, int j_0_ = 0); mat_ の小行列.左上は(i_0_, j_0_)で,サイズが(i_size_, j_size_). - Mat のメンバ関数
mat.part(i_size, j_size, i0, j0)…Part(mat, i_size, j_size, i0, j0)と同じ.mat.memcopy(part, i_1, j_1)…partが表す小行列を,行列matの中の,左上(i_1, j_1)の部分に埋め込む
演算
+,-,*,+=,-=,*=をサポートする.- 累乗:
mat.matpower(x)… mat の x 乗.正方行列に限る. *のオーバーライドで,MyMat と vectorのこの順の掛け算は,結果を vector にとれるようにしてある. - 例:
auto v = Matrix<ll>{{1, 2}, {3, 4}} * vector<ll>{1, 1};とすれば,vはvector<ll>{3, 7}に等しい.
- 例:
転置
mat.self_transpose()…mat自体を転置するmat.transpose()…matの転置行列を返す.
掃き出し,逆行列,一次方程式,….
- T が体になっていないときには,正しい結果にならなかったりコンパイルエラーになったりする.
[rank, det] = mat.self_sweepout();…matは,縦方向に掃き出したものに置き換えられる.rankはランク,detは行列式.[rank, det] = mat.sweepout();…matは変化しない.(掃き出した結果の行列は捨てられる).rankはランク,detは行列式.omat = mat.inv();… 逆行列.omatの型はoptional<MyMat>で,逆行列が存在しないときはnullopt.mat.determinant()… 行列式oo = mat.linSolution<flag>(bs);- 一次方程式
mat * X = bsを解く.bsの型はMyMat. - 返り値 oo の型は
optional<pair<MyMat, vector<MyMat>>>.- 解がない場合には,
ooは,nullopt. - 解がある場合には,
oo = [sol, kernel]として,solは (1つの) 解.flagが true の場合には,解空間を sol + V として,kernelは V の基底.flagが false (デフォルト) の場合には,kernelの値には意味が無い (計算が省略される)
- 解がない場合には,
- 注意: コンパイラが,linSolution の後ろに付ける “<” を不等号と誤認しないよう,次のように
.templateを書く必要があるかもしれない:auto opt1 = mat.template linSolution<true>(bs);
- 一次方程式
max-plus, min-pus 代数
行列と直接関係あるわけではないが,max-plus 代数は,次のように定義できる.(algOp ライブラリを使う)
struct MaxPlusLL {
using value_type = ll;
static value_type zero( const value_type& u) { return LLONG_MIN; }
static value_type one( const value_type& u) { return 0; }
static value_type add( const value_type& u, const value_type& v) { return max(u, v); }
static void subst_mult( value_type& u, const value_type& v) { u += v; }
};
using MMP = MyAlg<MaxPlusLL>;
こうしておけば,Matrix<MMP> によって,max-plus 代数の行列計算が実行できる.