ViennaCL - The Vienna Computing Library  1.6.0
Free open-source GPU-accelerated linear algebra and solver library.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Method of Least Squares

This tutorial shows how least Squares problems for matrices from ViennaCL or Boost.uBLAS can be solved solved.

We start with including the respective header files:

// activate ublas support in ViennaCL
#define VIENNACL_WITH_UBLAS
//
// include necessary system headers
//
#include <iostream>
// Boost headers
#include <boost/numeric/ublas/triangular.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/vector_proxy.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/matrix_proxy.hpp>
#include <boost/numeric/ublas/lu.hpp>
#include <boost/numeric/ublas/io.hpp>
// ViennaCL headers

The minimization problem of finding x such that $ \Vert Ax - b \Vert $ is solved as follows:

int main (int, const char **)
{
typedef float ScalarType; //feel free to change this to 'double' if supported by your hardware
typedef boost::numeric::ublas::matrix<ScalarType> MatrixType;
typedef boost::numeric::ublas::vector<ScalarType> VectorType;
typedef viennacl::vector<ScalarType> VCLVectorType;

Create vectors and matrices with data:

VectorType ublas_b(4);
ublas_b(0) = -4;
ublas_b(1) = 2;
ublas_b(2) = 5;
ublas_b(3) = -1;
MatrixType ublas_A(4, 3);
ublas_A(0, 0) = 2; ublas_A(0, 1) = -1; ublas_A(0, 2) = 1;
ublas_A(1, 0) = 1; ublas_A(1, 1) = -5; ublas_A(1, 2) = 2;
ublas_A(2, 0) = -3; ublas_A(2, 1) = 1; ublas_A(2, 2) = -4;
ublas_A(3, 0) = 1; ublas_A(3, 1) = -1; ublas_A(3, 2) = 1;

Setup the matrix and vector with ViennaCL objects and copy the data from the uBLAS objects:

VCLVectorType vcl_b(ublas_b.size());
VCLMatrixType vcl_A(ublas_A.size1(), ublas_A.size2());
viennacl::copy(ublas_A, vcl_A);

Option 1: Using Boost.uBLAS

The implementation in ViennaCL accepts both uBLAS and ViennaCL types. We start with a single-threaded implementation using Boost.uBLAS.

std::cout << "--- Boost.uBLAS ---" << std::endl;

The first (and computationally most expensive) step is to compute the QR factorization of A. Since we do not need A later, we directly overwrite A with the householder reflectors and the upper triangular matrix R. The returned vector holds the scalar coefficients (betas) for the Householder reflections $ I - \beta v v^{\mathrm{T}} $

std::vector<ScalarType> ublas_betas = viennacl::linalg::inplace_qr(ublas_A);

Compute the modified RHS of the minimization problem from the QR factorization, but do not form $ Q^{\mathrm{T}} $ explicitly: b' := Q^T b

viennacl::linalg::inplace_qr_apply_trans_Q(ublas_A, ublas_betas, ublas_b);

Final step: triangular solve: Rx = b'', where b'' are the first three entries in b' We only need the upper left square part of A, which defines the upper triangular matrix R

boost::numeric::ublas::range ublas_range(0, 3);
boost::numeric::ublas::matrix_range<MatrixType> ublas_R(ublas_A, ublas_range, ublas_range);
boost::numeric::ublas::vector_range<VectorType> ublas_b2(ublas_b, ublas_range);
boost::numeric::ublas::inplace_solve(ublas_R, ublas_b2, boost::numeric::ublas::upper_tag());
std::cout << "Result: " << ublas_b2 << std::endl;

Option 2: Use ViennaCL types

ViennaCL is used for the computationally intensive BLAS 3 computations. Boost.uBLAS is used for the panel factorization on the host (CPU).

of Least Squares