Boost.uBLAS でLU分解

今回はLU分解を実装します.LU分解を計算する関数はもちろん lapack にもあるのですが,それは次回紹介するとして,今回は uBLAS に実装されている lu_factorize を用いてLU分解してみようと思います.uBLAS の lu_factorize の結果を三角行列に切り出すだけなので非常に簡単です.以下に私の実装例を示します.

math.hpp

#ifndef MATH_HPP_20081012
#define MATH_HPP_20081012

#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif


#include <boost/numeric/ublas/fwd.hpp>
#include <boost/numeric/ublas/matrix.hpp>


namespace math {
    void lu_factorize(boost::numeric::ublas::matrix<double> A, boost::numeric::ublas::triangular_matrix<double, boost::numeric::ublas::unit_lower>& L, boost::numeric::ublas::triangular_matrix<double, boost::numeric::ublas::upper>& U);
}


#endif

math.cpp

#include "math.hpp"
#include <boost/numeric/ublas/lu.hpp>
#include <boost/numeric/ublas/triangular.hpp>


void math::lu_factorize(boost::numeric::ublas::matrix<double> A, boost::numeric::ublas::triangular_matrix<double, boost::numeric::ublas::unit_lower>& L, boost::numeric::ublas::triangular_matrix<double, boost::numeric::ublas::upper>& U)
{
    namespace ublas = boost::numeric::ublas;

    BOOST_UBLAS_CHECK(A.size1() == A.size2(), ublas::external_logic());

    ublas::lu_factorize(A);

    ublas::triangular_matrix<double, ublas::unit_lower> CL = ublas::triangular_adaptor<ublas::matrix<double>, ublas::unit_lower>(A);
    ublas::triangular_matrix<double, ublas::upper> CU = ublas::triangular_adaptor<ublas::matrix<double>, ublas::upper>(A);

    L.assign_temporary(CL);
    U.assign_temporary(CU);
}

math.cpp にLU分解を計算する関数 lu_factorize を実装しました.
関数 lu_factorize は M 次正方行列 A を受け取り,これを M 次単位下三角行列 L と M 次上三角行列 U の積に因数分解します.M 次単位下三角行列が関数の引数 L に,M 次上三角行列が関数の引数 U に保存されます.
lu_factorize の第一引数が const 参照になっていないことに注意してください.こうすることでコンパイラはより効率的なコードを生成することができるかもしれません(しかし Meyers が指摘しているように,このコードは賢さを求めすぎ,明白さを失ってしまったかもしれません).しかし,BOOST_UBLAS_CHECK の前にコピーが発生するのを許容できない方は const 参照で受け取りましょう(私がそうです.今回は非参照で受け取れば効率のよいコードを生成できる可能性があるということを言いたかっただけです).
math.cpp をプロジェクトに加え(他のソースコードと一緒にコンパイル),math.hpp を include することにより lu_factorize が使用可能になります.


以下のテストコードで lu_factorize の動作を確認してみます.

test.cpp

#include "math.hpp"
#include <boost/numeric/ublas/io.hpp>
#include <boost/numeric/ublas/triangular.hpp>


int main()
{
    namespace ublas = boost::numeric::ublas;

    ublas::matrix<double> A(2, 2);

    A(0, 0) = 4; A(0, 1) = 3;
    A(1, 0) = 6; A(1, 1) = 3;

    ublas::triangular_matrix<double, ublas::unit_lower> L;
    ublas::triangular_matrix<double, ublas::upper>      U;

    math::lu_factorize(A, L, U);

    // 以下結果の表示
    // 計算結果を http://en.wikipedia.org/wiki/LU_decomposition#Small_Example と比較してみましょう
    std::cout << L << std::endl
              << U << std::endl
              << ublas::prod(L, U) << std::endl;

    return 0;
}
  • VC9
  • g++ (GCC) 3.4.4 (cygming special)

でのコンパイルを確認しています.
実行してみると,正しくLU分解できていることが分かります.


次回は lapack を用いたLU分解を実装する予定です.
それでは.