Boost logo

Ublas :

From: Karl Meerbergen (Karl.Meerbergen_at_[hidden])
Date: 2006-12-15 08:59:24


Gunter,

I have a suggestion: instead of returning a bool you could return a
X::size_type to indicate how far the triangular solve is carried out.
So, if x is a vector and the return value is x.size(), then the solve is
fully carried out. Otherwise the return value tells you how many
elements of x have been solved for.

Karl

Gunter Winkler wrote:

>Hallo,
>
>I finally finished the new triangular solvers. A new header file and an
>example is attached. Some documentation is inside the header file. These
>solves are defined as a replacement of the solvers in triangular.hpp (which
>must be disabled in order to compile the example.)
>
>I found it to be convenient to gain a triangular type tag from a triangular
>layout type. So I added a few lines to functional.hpp (see patch file). Now
>you can use
>typedef lower TRI;
>typedef TRI::triangular_type TAG;
>where TAG is lower_tag (which can be used as an function argument of
>inplace_solve.)
>This is similar to orientation_category in row_major and column_major.
>
>The syntax of the solvers is the same:
>
>bool singular;
>singular = inplace_solve(L, x, lower_tag); // solves Lx=b
>singular = inplace_solve(L, x, unit_lower_tag); // solves (I+L)x=b
>singular = inplace_solve(U, x, upper_tag); // solves Ux=b
>singular = inplace_solve(U, x, unit_upper_tag); // solves (I+U)x=b
>
>(Most of) The solvers require the matrix to have the given structure and they
>may return wrong results if this condition is violated. The also return
>whether the matrix is singular. (Be careful: The solve was successful if the
>result is _false_.) "x" can be a dense vector or a dense matrix.
>
>
>Please have a look at the files and tell me if they work reliably.
>
>mfg
>Gunter
>
>
>
>------------------------------------------------------------------------
>
>/** \file ex_trisolve.cpp \brief main routines. -*- c++ -*- */
>/***************************************************************************
> - begin : 2006-11-03
> - copyright : (C) 2006 by Gunter Winkler
> - email : guwi17_at_[hidden]
> ***************************************************************************/
>
>// Distributed under the Boost Software License, Version 1.0. (See
>// accompanying file LICENSE_1_0.txt or copy at
>// http://www.boost.org/LICENSE_1_0.txt)
>
>// misc. boost includes
>#include <boost/timer.hpp>
>
>#include "trisolve.h"
>
>// boost ublas includes
>#include <boost/numeric/ublas/vector.hpp>
>#include <boost/numeric/ublas/matrix.hpp>
>#include <boost/numeric/ublas/matrix_sparse.hpp>
>#include <boost/numeric/ublas/matrix_proxy.hpp>
>#include <boost/numeric/ublas/triangular.hpp>
>#include <boost/numeric/ublas/io.hpp>
>
>// system includes
>#include <iostream>
>#include <limits>
>
>#ifndef NDEBUG
>const size_t default_size = 10;
>#else
>const size_t default_size = 100;
>#endif
>
>
>template<class M>
>void setup_L(M& A, bool unit=false)
>{
> using namespace boost::numeric::ublas;
> if (unit)
> A = triangular_adaptor<const scalar_matrix<double>,unit_lower>( scalar_matrix<double>(A.size1(), A.size2(), -0.2) );
> else
> A = triangular_adaptor<const scalar_matrix<double>,strict_lower>( scalar_matrix<double>(A.size1(), A.size2(), -0.2) );
>}
>
>template<class M>
>void setup_U(M& A, bool unit=false)
>{
> using namespace boost::numeric::ublas;
> if (unit)
> A = triangular_adaptor<const scalar_matrix<double>,unit_upper>( scalar_matrix<double>(A.size1(), A.size2(), 0.2) );
> else
> A = triangular_adaptor<const scalar_matrix<double>,strict_upper>( scalar_matrix<double>(A.size1(), A.size2(), 0.2) );
>}
>
>template<class V>
>void setup_x(boost::numeric::ublas::vector_expression<V>& x)
>{
> for (size_t i=0; i<x().size(); ++i) {
> x()(i) = 1.0 / sqrt(x().size());
> }
>}
>
>template<class V>
>void setup_x(boost::numeric::ublas::matrix_expression<V>& x)
>{
> double t = 1.0 / sqrt(x().size1());
> for (size_t i=0; i<x().size1(); ++i) {
> row(x(),i) = boost::numeric::ublas::scalar_vector<double>(x().size2(), t );
> }
>}
>
>
>// this is no real norm -> its only useful for this test
>template<class MATRIX>
>double
>norm_2(const boost::numeric::ublas::matrix_expression<MATRIX>& A)
>{
> double result=0.0;
> for (size_t k=0; k<A().size2(); ++k)
> result += norm_2(column( A(), k ));
> return result;
>}
>
>template<class MATRIX>
>double
>norm_inf_2(const boost::numeric::ublas::matrix_expression<MATRIX>& A)
>{
> double result=0.0;
> for (size_t k=0; k<A().size2(); ++k)
> result += norm_inf(column( A(), k ));
> return result;
>}
>
>template<class VECTOR>
>double
>norm_inf_2(const boost::numeric::ublas::vector_expression<VECTOR>& A)
>{
> return norm_inf(A());
>}
>
>template <class TRI, class MATRIX, class VECTOR>
>bool do_test(const boost::numeric::ublas::matrix_expression<MATRIX>& A,
> VECTOR& x, const VECTOR& rhs)
>{
> using namespace boost::numeric::ublas;
>
> double eps = std::numeric_limits<double>::epsilon();
>
> x=rhs;
> boost::timer t;
> t.restart();
> inplace_solve(A(), x, typename TRI::triangular_type());
> double time = t.elapsed();
>
> VECTOR resid = (rhs - prod(A(),x));
> if ( TRI::one(1,1) ) resid -= x;
> double error = norm_2(resid)/norm_2(rhs);
>
>#ifndef NDEBUG
> std::cerr << "||b-Ax|| = " << norm_2(resid) << ", " << norm_inf(resid) << std::endl;
> std::cerr << "||b|| = " << norm_2(rhs) << ", " << norm_inf(rhs) << std::endl;
> std::cerr << "||x|| = " << norm_2(x) << ", " << norm_inf(x) << std::endl;
>#endif
>
> double limit = (A().size1()*eps);
> if (error <= limit) {
> std::cout << " (" << time << " sec)"
> << " relative error " << error
> << std::endl;
> return true;
> } else {
> std::cout << " (" << time << " sec)"
> << " relative error " << error
> << " greater than threshold " << limit
> << std::endl;
>#ifndef NDEBUG
> std::cerr << " rhs = " << rhs << "\n";
> std::cerr << " x = " << x << "\n";
> std::cerr << " res = " << resid << "\n";
>#endif
> return false;
> }
>}
>
>
>template < class MATRIX >
>void run_solver_tests(size_t size, size_t nrhs=5)
>{
> using namespace boost::numeric::ublas;
>
> typedef MATRIX LMAT;
> typedef MATRIX UMAT;
>
> LMAT L(size,size);
> UMAT U(size,size);
>
> L.clear(); U.clear();
>
> vector<double> b(size);
> vector<double> x(size);
> vector<double> x2(size);
>
> matrix<double> X(size,nrhs);
> matrix<double> B(size,nrhs);
>
> setup_L(L,false);
> setup_U(U,false);
>
>
> setup_x(x);
> std::cout << "vec unit lower: ";
> b = x + prod(L, x);
> std::cerr << do_test<unit_lower>(L,x,b);
>
> setup_x(x);
> std::cout << "vec unit upper: ";
> b = x + prod(U, x);
> std::cerr << do_test<unit_upper>(U,x,b);
>
> setup_x(X);
> std::cout << "mat unit lower: ";
> B = X + prod(L, X);
> std::cerr << do_test<unit_lower>(L,X,B);
>
> setup_x(X);
> std::cout << "mat unit upper: ";
> B = X + prod(U, X);
> std::cerr << do_test<unit_upper>(U,X,B);
>
>
> L.clear(); U.clear();
> setup_L(L,true);
> setup_U(U,true);
>
> setup_x(x);
> std::cout << "vec lower: ";
> b = prod(L,x);
> std::cerr << do_test<lower>(L,x,b);
>
> setup_x(x);
> std::cout << "vec upper: ";
> b = prod(U,x);
> std::cerr << do_test<upper>(U,x,b);
>
> setup_x(X);
> std::cout << "mat lower: ";
> B = prod(L, X);
> std::cerr << do_test<lower>(L,X,B);
>
> setup_x(X);
> std::cout << "mat upper: ";
> B = prod(U, X);
> std::cerr << do_test<upper>(U,X,B);
>
>}
>
>
>int main(int argc, char *argv[])
>{
>
> typedef size_t size_type;
> size_type size = default_size;
> if (argc > 1)
> size = ::atoi (argv [1]);
> std::cout << "size " << size << std::endl;
>
> using namespace boost::numeric::ublas;
>
> std::cout << "dense column major\n";
> run_solver_tests< matrix<double, column_major> >(size);
> std::cout << "dense row major\n";
> run_solver_tests< matrix<double, row_major> >(size);
>
> std::cout << "compressed column_major major\n";
> run_solver_tests< compressed_matrix<double, column_major> >(size);
> std::cout << "compressed row major\n";
> run_solver_tests< compressed_matrix<double, row_major> >(size);
>
> std::cout << "mapped column_major major\n";
> run_solver_tests< mapped_matrix<double, column_major> >(size);
> std::cout << "mapped row major\n";
> run_solver_tests< mapped_matrix<double, row_major> >(size);
>
> return EXIT_SUCCESS;
>}
>
>
>------------------------------------------------------------------------
>
>/* trisolve.h - triangular solver */ // -*- c++ -*-
>/***************************************************************************
> begin : 2006-12-11
> copyright : (C) 2006 by Gunter Winkler
> email : guwi17_at_[hidden]
>***************************************************************************/
>
>// Distributed under the Boost Software License, Version 1.0. (See
>// accompanying file LICENSE_1_0.txt or copy at
>// http://www.boost.org/LICENSE_1_0.txt)
>
>#include <boost/numeric/ublas/matrix_sparse.hpp>
>#include <boost/numeric/ublas/matrix_proxy.hpp>
>#include <boost/numeric/ublas/vector_proxy.hpp>
>
>namespace boost { namespace numeric { namespace ublas {
>
> /*********************************
> * PART 0: general documentation *
> *********************************/
>
> /** \brief solve lower triangular system Lx=b or (I+L)x=b.
> * - \param unit controls whether L is strict lower triangular
> (\c true) or lower triangular (\c false)
> - \param MAT is the type of the matrix L
> - \param VEC is the type of the vector x
>
> On input \c x contains the right hand side, on output it
> contains the solution.
>
> The function returns \c true if the matrix is
> singular. Otherwise it returns \c false.
>
> In order to have an efficient implementation, the functions make
> no check whether L is really (strict) lower triangular. Thus the
> result is undefined if this requirement is not met.
>
> You can force the necessary structure by using the \c triangular_adaptor
> with \c lower or \c strict_lower.
>
> \note The solution of (triangular) systems of equations is
> numerically unstable. You should expect large absolute errors if
> the matrix has a large condition number. The main reason is that
> small errors introduced in the first computed components of the
> solution add up to large errors in the final components if a)
> the matrix has many rows/columns and b) the sum of the
> off-diagonal entries of a row is larger than the value at the
> diagonal. You will find a detailed error analysis in any good
> text book about numerics, see, e.g., Golub/van Loan, "Matrix
> Computations."
> */
> template <bool unit, class MAT, class VEC>
> bool inplace_solve_lower(const matrix_expression<MAT>& L, vector_expression<VEC>& x);
>
> /** \brief solve lower triangular system LX=B or (I+L)X=B.
> * - \param unit controls whether L is expected to be strict lower
> triangular (true) or lower triangular (false)
> - \param MAT is the type of the matrix L
> - \param MATX is the type of the rhs-matrix X
>
> On input \c X contains the right hand sides, on output it
> contains the solutions.
>
> \sa inplace_solve_lower(const matrix_expression<MAT>& L, vector_expression<VEC>& x)
> */
> template <bool unit, class MAT, class MATX>
> bool inplace_solve_lower(const matrix_expression<MAT>& L, matrix_expression<MATX>& X);
>
> /** \brief solve upper triangular system Ux=b or (I+U)x=b.
> * - \param unit controls whether U is expected to be strict upper
> triangular (true) or upper triangular (false)
> - \param MAT is the type of the matrix U
> - \param VEC is the type of the vector x
>
> On input \c x contains the right hand side, on output it
> contains the solution.
>
> The function returns \c true if the matrix is
> singular. Otherwise it returns \c false.
>
> In order to have an efficient implementation, the functions make
> no check whether L is really (strict) upper triangular. Thus the
> result is undefined if this requirement is not met.
>
> You can force the necessary structure by using the \c triangular_adaptor
> with \c upper or \c strict_upper.
> */
> template <bool unit, class MAT, class VEC>
> bool inplace_solve_upper(const matrix_expression<MAT>& U, vector_expression<VEC>& x);
>
> /** \brief solve upper triangular system UX=B or (I+U)X=B.
> * - \param unit controls whether U is expected to be strict upper
> triangular (true) or upper triangular (false)
> - \param MAT is the type of the matrix U
> - \param MATX is the type of the rhs-matrix X
>
> On input \c X contains the right hand sides, on output it
> contains the solutions.
>
> \sa inplace_solve_upper(const matrix_expression<MAT>& U, vector_expression<VEC>& x)
> */
> template <bool unit, class MAT, class MATX>
> bool inplace_solve_upper(const matrix_expression<MAT>& U, matrix_expression<MATX>& X);
>
> /*********************************************
> * PART 1: optimized lower and upper solvers *
> *********************************************/
>
> /* if (unit) assume L is strict lower triangular
> * if (!unit) assume L is lower triangular and invertible
> */
> template < bool unit, class T, class Z, class D, size_t IB, class IA, class TA, class VEC >
> bool
> inplace_solve_lower(const compressed_matrix<T, basic_row_major<Z,D>, IB, IA, TA>& L, vector_expression<VEC>& ve)
> {
> if ( (!unit) && L.filled1() <= L.size1() ) return true;
> typedef typename IA::value_type size_type;
> size_type imax = L.filled1()-1;
> for (size_type i = 0; i < imax; ++i ) {
> size_type iptr_a = L.index1_data()[i];
> size_type iptr_b = L.index1_data()[i+1];
> if (!unit) { -- iptr_b; }
> T value = ve()(i);
> for (size_type k = iptr_a; k < iptr_b; ++k) {
> BOOST_UBLAS_CHECK (L.index2_data()[k] <= i, bad_index ());
> value -= L.value_data()[k] * ve()( L.index2_data()[k] );
> }
> if (unit) {
> ve()(i) = value;
> } else {
> ve()(i) = value / L.value_data()[iptr_b];
> }
> }
> return false;
> }
>
> /* if (unit) assume U is strict upper triangular
> * if (!unit) assume U is upper triangular and invertible
> */
> template < bool unit, class T, class Z, class D, size_t IB, class IA, class TA, class VEC >
> bool
> inplace_solve_upper(const compressed_matrix<T, basic_row_major<Z,D>, IB, IA, TA>& U, vector_expression<VEC>& ve)
> {
> if ( (!unit) && U.filled1() <= U.size1() ) return true;
> typedef typename IA::value_type size_type;
> size_type imax = U.filled1()-1;
> for (size_type i = imax; i > 0; --i ) {
> size_type iptr_a = U.index1_data()[i-1];
> size_type iptr_b = U.index1_data()[i];
> if (!unit) { ++ iptr_a; }
> T value = ve()(i-1);
> for (size_type k = iptr_a; k < iptr_b; ++k) {
> BOOST_UBLAS_CHECK (U.index2_data()[k] >= (i-1), bad_index ());
> value -= U.value_data()[k] * ve()( U.index2_data()[k] );
> }
> if (unit) {
> ve()(i-1) = value;
> } else {
> ve()(i-1) = value / U.value_data()[iptr_a-1];
> }
> }
> return false;
> }
>
> /*******************************************
> * PART 2: general lower and upper solvers *
> *******************************************/
>
> /* only the lower left or upper right triangle of A is accessed,
> * the number of rows of A determines the (used) size of x,
> *
> * syntax 1:
> * inplace_solve_lower<unit>(A,x)
> * inplace_solve_upper<unit>(A,x)
> *
> * syntax 2:
> * inplace_solve_lower<unit>(A,x,ORI)
> * inplace_solve_upper<unit>(A,x,ORI)
> * where ORI is row_major_tag or column_major_tag
> * (here you can override the default choice of the orientation of the algorithm)
> */
>
> /** \brief Solve (column-by-column) Lx=b or (I+L)x=b where L is the (strict) lower triangle of A.
>
> This version uses the generic algorithm for dense matrices and
> thus only accesses the (strict) lower triangle of A. The result
> is even correct when the matrix A has non-zero value (at or)
> above the diagonal.
> */
> template <bool unit, class MAT, class VEC>
> bool inplace_solve_lower(const matrix_expression<MAT>& A, vector_expression<VEC>& x, column_major_tag)
> {
> typedef typename VEC::size_type size_type;
> typedef typename VEC::value_type value_type;
>
> BOOST_UBLAS_CHECK (A ().size2 () >= x ().size (), bad_size ());
> BOOST_UBLAS_CHECK (A ().size1 () <= x ().size (), bad_size ());
>
> size_type n = A().size1();
> if (n==0) return false;
>
> for (size_type j = 0; j < (n-1); ++j) {
> double t;
> if (!unit) {
> if (A()(j,j)==0.0) return true;
> t = ( x()(j) /= A()(j,j) );
> } else {
> t = x()(j);
> }
> if (t != value_type()) {
> noalias( project(x(), range(j+1,n)) ) -= t*project( column(A(), j), range(j+1,n) );
> }
> }
> if (!unit) {
> if (A()(n-1,n-1)==0.0) return true;
> x()(n-1) /= A()(n-1,n-1);
> }
> return false;
> }
>
> /** \brief Solve (row-by-row) Lx=b or (I+L)x=b where L is the (strict) lower triangle of A.
>
> This version uses the generic algorithm for dense matrices and
> thus only accesses the (strict) lower triangle of A. The result
> is even correct when the matrix A has non-zero value (at or)
> above the diagonal.
> */
> template <bool unit, class MAT, class VEC>
> bool inplace_solve_lower(const matrix_expression<MAT>& A, vector_expression<VEC>& x, row_major_tag)
> {
> typedef typename VEC::size_type size_type;
> typedef typename VEC::value_type value_type;
>
> BOOST_UBLAS_CHECK (A ().size2 () >= x ().size (), bad_size ());
> BOOST_UBLAS_CHECK (A ().size1 () <= x ().size (), bad_size ());
>
> size_type n = A().size1();
> if (n==0) return false;
> if (!unit) {
> if (A()(0,0)==0.0) return true;
> x()(0) /= A()(0,0);
> }
>
> for (size_type j = 1; j < n; ++j) {
> double t;
> t = inner_prod( project(x(), range(0,j)), project( row(A(), j), range(0,j) ) );
> if (!unit) {
> if (A()(j,j)==0.0) return true;
> x()(j) = (x()(j) - t)/A()(j,j);
> } else {
> x()(j) -= t;
> }
> }
> return false;
> }
>
> /** \brief Solve (column-by-column) Ux=b or (I+U)x=b where U is the (strict) upper triangle of A.
>
> This version uses the generic algorithm for dense matrices and
> thus only accesses the (strict) upper triangle of A. The result
> is even correct when the matrix A has non-zero value (at or)
> below the diagonal.
> */
> template <bool unit, class MAT, class VEC>
> bool inplace_solve_upper(const matrix_expression<MAT>& A, vector_expression<VEC>& x, column_major_tag)
> {
> typedef typename VEC::size_type size_type;
> typedef typename VEC::value_type value_type;
>
> BOOST_UBLAS_CHECK (A ().size2 () >= x ().size (), bad_size ());
> BOOST_UBLAS_CHECK (A ().size1 () <= x ().size (), bad_size ());
>
> size_type n = A().size1();
> if (n==0) return false;
>
> for (size_type j = n-1; j > 0; --j) {
> double t;
> if (!unit) {
> if (A()(j,j)==0.0) return true;
> t = ( x()(j) /= A()(j,j) );
> } else {
> t = x()(j);
> }
> if (t != value_type()) {
> noalias( project(x(), range(0,j)) ) -= t*project( column(A(), j), range(0,j) );
> }
> }
> if (!unit) {
> if (A()(0,0)==0.0) return true;
> x()(0) /= A()(0,0);
> }
> return false;
> }
>
> /** \brief Solve (row-by-row) Ux=b or (I+U)x=b where U is the (strict) upper triangle of A.
>
> This version uses the generic algorithm for dense matrices and
> thus only accesses the (strict) upper triangle of A. The result
> is even correct when the matrix A has non-zero value (at or)
> below the diagonal.
> */
> template <bool unit, class MAT, class VEC>
> bool inplace_solve_upper(const matrix_expression<MAT>& A, vector_expression<VEC>& x, row_major_tag)
> {
> typedef typename VEC::size_type size_type;
> typedef typename VEC::value_type value_type;
>
> BOOST_UBLAS_CHECK (A ().size2 () >= x ().size (), bad_size ());
> BOOST_UBLAS_CHECK (A ().size1 () <= x ().size (), bad_size ());
>
> size_type n = A().size1();
> if (n==0) return false;
> if (!unit) {
> x()(n-1) /= A()(n-1,n-1);
> }
>
> for (size_type j = n-2; /* at end */ ; --j) {
> double t;
> t = inner_prod( project(x(), range(j+1,n)), project( row(A(), j), range(j+1,n) ) );
> if (!unit) {
> if (A()(j,j)==0.0) return true;
> x()(j) = (x()(j) - t)/A()(j,j);
> } else {
> x()(j) -= t;
> }
> if (j==0) break;
> }
> return false;
> }
>
> /* only the lower left or upper right triangle of A is accessed,
> * the number of rows of A determines the (used) size of X,
> *
> * syntaX 1:
> * inplace_solve_lower<unit>(A,X)
> * inplace_solve_upper<unit>(A,X)
> *
> * syntaX 2:
> * inplace_solve_lower<unit>(A,X,ORI)
> * inplace_solve_upper<unit>(A,X,ORI)
> * where ORI is row_major_tag or column_major_tag
> * (here you can override the default choice of the orientation of the algorithm)
> */
>
> /** \brief Solve (column-by-column) LX=b or (I+L)X=b where L is the (strict) lower triangle of A.
>
> This version uses the generic algorithm for dense matrices and
> thus only accesses the (strict) lower triangle of A. The result
> is even correct when the matriX A has non-zero value (at or)
> above the diagonal.
> */
> template <bool unit, class MAT, class VEC>
> bool inplace_solve_lower(const matrix_expression<MAT>& A, matrix_expression<VEC>& X, column_major_tag)
> {
> typedef typename VEC::size_type size_type;
> typedef typename VEC::value_type value_type;
>
> BOOST_UBLAS_CHECK (A ().size2 () >= X ().size1 (), bad_size ());
> BOOST_UBLAS_CHECK (A ().size1 () <= X ().size1 (), bad_size ());
>
> size_type nrhs = X().size2();
>
> size_type n = A().size1();
> if (n==0) return false;
>
> for (size_type j = 0; j < (n-1); ++j) {
> if (!unit) {
> if (A()(j,j)==0.0) return true;
> row(X(),j) /= A()(j,j) ;
> }
> noalias( project(X(), range(j+1,n), range(0, nrhs) ) )
> -= outer_prod(project( column(A(), j), range(j+1,n) ), row(X(),j));
> }
> if (!unit) {
> if (A()(n-1,n-1)==0.0) return true;
> row(X(),n-1) /= A()(n-1,n-1);
> }
> return false;
> }
>
> /** \brief Solve (row-by-row) LX=b or (I+L)X=b where L is the (strict) lower triangle of A.
>
> This version uses the generic algorithm for dense matrices and
> thus only accesses the (strict) lower triangle of A. The result
> is even correct when the matriX A has non-zero value (at or)
> above the diagonal.
> */
> template <bool unit, class MAT, class VEC>
> bool inplace_solve_lower(const matrix_expression<MAT>& A, matrix_expression<VEC>& X, row_major_tag)
> {
> typedef typename VEC::size_type size_type;
> typedef typename VEC::value_type value_type;
>
> BOOST_UBLAS_CHECK (A ().size2 () >= X ().size1 (), bad_size ());
> BOOST_UBLAS_CHECK (A ().size1 () <= X ().size1 (), bad_size ());
>
> size_type nrhs = X().size2();
>
> size_type n = A().size1();
> if (n==0) return false;
> if (!unit) {
> if (A()(0,0)==0.0) return true;
> row(X(),0) /= A()(0,0);
> }
>
> for (size_type j = 1; j < n; ++j) {
> if (!unit) {
> if (A()(j,j)==0.0) return true;
> noalias( row(X(),j) )
> = ( row(X(),j) - prod( project( row(A(), j), range(0,j) ),
> project(X(), range(0,j), range(0,nrhs)) ) )
> / A()(j,j);
> } else {
> noalias( row(X(),j) )
> -= prod( project( row(A(), j), range(0,j) ),
> project(X(), range(0,j), range(0,nrhs)) );
> }
> }
> return false;
> }
>
> /** \brief Solve (column-by-column) UX=b or (I+U)X=b where U is the (strict) upper triangle of A.
>
> This version uses the generic algorithm for dense matrices and
> thus only accesses the (strict) upper triangle of A. The result
> is even correct when the matriX A has non-zero value (at or)
> below the diagonal.
> */
> template <bool unit, class MAT, class VEC>
> bool inplace_solve_upper(const matrix_expression<MAT>& A, matrix_expression<VEC>& X, column_major_tag)
> {
> typedef typename VEC::size_type size_type;
> typedef typename VEC::value_type value_type;
>
> BOOST_UBLAS_CHECK (A ().size2 () >= X ().size1 (), bad_size ());
> BOOST_UBLAS_CHECK (A ().size1 () <= X ().size1 (), bad_size ());
>
> size_type nrhs = X().size2();
>
> size_type n = A().size1();
> if (n==0) return false;
>
> for (size_type j = n-1; j > 0; --j) {
> if (!unit) {
> if (A()(j,j)==0.0) return true;
> row(X(),j) /= A()(j,j);
> }
> noalias( project(X(), range(0,j), range(0,nrhs) ) )
> -= outer_prod( project( column(A(), j), range(0,j) ),
> row(X(),j) );
> }
> if (!unit) {
> if (A()(0,0)==0.0) return true;
> row(X(),0) /= A()(0,0);
> }
> return false;
> }
>
> /** \brief Solve (row-by-row) UX=b or (I+U)X=b where U is the (strict) upper triangle of A.
>
> This version uses the generic algorithm for dense matrices and
> thus only accesses the (strict) upper triangle of A. The result
> is even correct when the matriX A has non-zero value (at or)
> below the diagonal.
> */
> template <bool unit, class MAT, class VEC>
> bool inplace_solve_upper(const matrix_expression<MAT>& A, matrix_expression<VEC>& X, row_major_tag)
> {
> typedef typename VEC::size_type size_type;
> typedef typename VEC::value_type value_type;
>
> BOOST_UBLAS_CHECK (A ().size2 () >= X ().size1 (), bad_size ());
> BOOST_UBLAS_CHECK (A ().size1 () <= X ().size1 (), bad_size ());
>
> size_type nrhs = X().size2();
>
> size_type n = A().size1();
> if (n==0) return false;
> if (!unit) {
> row(X(),n-1) /= A()(n-1,n-1);
> }
>
> for (size_type j = n-2; /* at end */ ; --j) {
> if (!unit) {
> if (A()(j,j)==0.0) return true;
> noalias( row(X(),j) )
> = ( row(X(),j) - prod( project( row(A(), j), range(j+1,n) ),
> project(X(), range(j+1,n), range(0,nrhs)) ) )
> / A()(j,j);
> } else {
> noalias( row(X(),j) )
> -= prod( project( row(A(), j), range(j+1,n) ),
> project(X(), range(j+1,n), range(0,nrhs)) );
> }
> if (j==0) break;
> }
> return false;
> }
>
> // Dispatcher for default orientation
>
> template <bool unit, class MAT, class VEC>
> bool inplace_solve_lower(const matrix_expression<MAT>& A, vector_expression<VEC>& x)
> {
> return inplace_solve_lower<unit>(A, x, typename MAT::orientation_category() );
> }
>
> template <bool unit, class MAT, class VEC>
> bool inplace_solve_upper(const matrix_expression<MAT>& A, vector_expression<VEC>& x)
> {
> return inplace_solve_upper<unit>(A, x, typename MAT::orientation_category() );
> }
>
> template <bool unit, class MAT, class MATX>
> bool inplace_solve_lower(const matrix_expression<MAT>& A, matrix_expression<MATX>& X)
> {
> return inplace_solve_lower<unit>(A, X, typename MAT::orientation_category() );
> }
>
> template <bool unit, class MAT, class MATX>
> bool inplace_solve_upper(const matrix_expression<MAT>& A, matrix_expression<MATX>& X)
> {
> return inplace_solve_upper<unit>(A, X, typename MAT::orientation_category() );
> }
>
> /***********************************
> * PART 3: upper/lower dispatchers *
> ***********************************/
>
> // note: the dispatcher even work when VEC is a matrix expression.
>
> template < class MAT, class VEC >
> bool
> inplace_solve( const MAT& L, VEC& x, unit_lower_tag )
> {
> return inplace_solve_lower<true>(L, x);
> }
>
> template < class MAT, class VEC >
> bool
> inplace_solve( const MAT& L, VEC& x, lower_tag )
> {
> return inplace_solve_lower<false>(L, x);
> }
>
> template < class MAT, class VEC >
> bool
> inplace_solve( const MAT& U, VEC& x, unit_upper_tag )
> {
> return inplace_solve_upper<true>(U, x);
> }
>
> template < class MAT, class VEC >
> bool
> inplace_solve( const MAT& U, VEC& x, upper_tag )
> {
> return inplace_solve_upper<false>(U, x);
> }
>
>}}}
>
>
>------------------------------------------------------------------------
>
>Index: functional.hpp
>===================================================================
>RCS file: /cvsroot/boost/boost/boost/numeric/ublas/functional.hpp,v
>retrieving revision 1.39
>diff -u -p -r1.39 functional.hpp
>--- functional.hpp 27 Jul 2006 10:27:37 -0000 1.39
>+++ functional.hpp 15 Dec 2006 13:30:57 -0000
>@@ -1774,6 +1786,7 @@ namespace boost { namespace numeric { na
> template <class Z>
> struct basic_lower {
> typedef Z size_type;
>+ typedef lower_tag triangular_type;
>
> template<class L>
> static
>@@ -1828,6 +1841,7 @@ namespace boost { namespace numeric { na
> template <class Z>
> struct basic_upper {
> typedef Z size_type;
>+ typedef upper_tag triangular_type;
>
> template<class L>
> static
>@@ -1882,6 +1896,7 @@ namespace boost { namespace numeric { na
> template <class Z>
> struct basic_unit_lower : public basic_lower<Z> {
> typedef Z size_type;
>+ typedef unit_lower_tag triangular_type;
>
> template<class L>
> static
>@@ -1925,6 +1940,7 @@ namespace boost { namespace numeric { na
> template <class Z>
> struct basic_unit_upper : public basic_upper<Z> {
> typedef Z size_type;
>+ typedef unit_upper_tag triangular_type;
>
> template<class L>
> static
>@@ -1968,6 +1984,7 @@ namespace boost { namespace numeric { na
> template <class Z>
> struct basic_strict_lower : public basic_lower<Z> {
> typedef Z size_type;
>+ typedef strict_lower_tag triangular_type;
>
> template<class L>
> static
>@@ -2026,6 +2043,7 @@ namespace boost { namespace numeric { na
> template <class Z>
> struct basic_strict_upper : public basic_upper<Z> {
> typedef Z size_type;
>+ typedef strict_upper_tag triangular_type;
>
> template<class L>
> static
>
>
>------------------------------------------------------------------------
>
>_______________________________________________
>ublas mailing list
>ublas_at_[hidden]
>http://lists.boost.org/mailman/listinfo.cgi/ublas
>
>

Disclaimer: http://www.kuleuven.be/cwis/email_disclaimer.htm