Boost logo

Ublas :

Subject: Re: [ublas] axpy_prod Weirdness
From: Vardan Akopian (vakopian_at_[hidden])
Date: 2010-08-23 18:11:00


On Mon, Aug 23, 2010 at 2:32 PM, Jane Shevtsov <jane.eco_at_[hidden]> wrote:
> I have a little program that implements an ecological network analysis
> algorithm. (It looks at the importance of indirect energy or matter
> flows between species.)
>
> 01      //dea.cpp -- The fundamental DEA algorithm
> 02
> 03      #include <boost/numeric/ublas/matrix.hpp>
> 04      #include <boost/numeric/ublas/operation.hpp>
> 05      #include <boost/numeric/ublas/io.hpp> //for test
> 06      #include "storage_adaptors.hpp" //for test
> 07
> 08      using boost::numeric::ublas::matrix;
> 09
> 10      void dea(const matrix<double>[], int, int, matrix<double>[]);
> 11      matrix<double> indflow(const matrix<double> & Ndea, const
> matrix<double> & Gdea);
> 12
> 13      int main() {
> 14          using boost::numeric::ublas::make_matrix_from_pointer;
> 15          matrix<double> Garr[4];
> 16          matrix<double> Narr[2];
> 17          double G1[3][3] = {0, 0, 0, 0.33333, 0, 0, 0.66667, 1, 0};
> 18          double G2[3][3] = {0, 0, 0, 0.6, 0, 0, 0.4, 1, 0};
> 19          double G3[3][3] = {0, 0, 0, 0.55, 0, 0, 0.45, 1, 0};
> 20          double G4[3][3] = {0, 0, 0, 0.5, 0, 0, 0.5, 1, 0};
> 21          Garr[0] = make_matrix_from_pointer(G1);
> 22          Garr[1] = make_matrix_from_pointer(G2);
> 23          Garr[2] = make_matrix_from_pointer(G3);
> 24          Garr[3] = make_matrix_from_pointer(G4);
> 25          dea(Garr, 2, 4, Narr);
> 26          std::cout << Narr[0] << std::endl;
> 27          matrix<double> ratio = indflow(Narr[0], Garr[0]);
> 28          std::cout << ratio << std::endl;
> 29          return 0;
> 30      }
> 31
> 32      //The fundamental DEA algorithm
> 33      //Takes array of G matrices, window size, array length and empty
> array for N_DEA matrices as input
> 34      void dea(const matrix<double> Garr[], int win, int arrLen,
> matrix<double> Narr[]) {
> 35          using namespace boost::numeric::ublas;
> 36          int matSize = Garr[0].size1();
> 37          for (int i = 0; i < arrLen - win; i++) {
> 38              matrix<double> Gprod = identity_matrix<double>(matSize);
> 39              Narr[i] = identity_matrix<double>(matSize);
> 40              //the core loop
> 41              for (int j = 0; j < win; j++) {
> 42                  Gprod = prod(Gprod, Garr[i+j]);
> 43                  Narr[i] += Gprod;
> 44              }
> 45          }
> 46      }
> 47
> 48      //computes indirect flow fraction
> 49      matrix<double> indflow(const matrix<double> & Ndea, const
> matrix<double> & Gdea) {
> 50          using namespace boost::numeric::ublas;
> 51          int matSize = Ndea.size1();
> 52          matrix<double> iflow = Ndea - Gdea -
> identity_matrix<double>(matSize); //Ind = N-G-I
> 53          matrix<double> frac = zero_matrix<double>(matSize, matSize);
> //inialize indirect flow fraction matrix
> 54          //perform division for nonzero, off-diagonal elements
> 55          for (int i=0; i<matSize; i++) {
> 56              for (int j=0; j<matSize; j++) {
> 57                  if (i != j && Ndea(i,j) != 0)  //avoid division by zero
> 58                          frac(i, j) = iflow(i, j) / Ndea(i, j);
> 59              }
> 60          }
> 61          return frac;
> 62      }
>
> The correct output is below.
> [3,3]((1,0,0),(0.33333,1,0),(1.26667,1,1))
> [3,3]((0,0,0),(0,0,0),(0.473683,0,0))
>
> The code given above works, but to speed it up, I tried replacing the
> first line of the core loop in dea() with axpy_prod(Gprod, Garr[i+j],
> Gprod, true);. This gives the following wrong output:
> [3,3]((1,0,0),(0,1,0),(0,0,1))
> [3,3]((0,0,0),(0,0,0),(0,0,0))
>
> And if I use axpy_prod(Gprod, Garr[i+j], Gprod, false);, I get:
> [3,3]((3,0,0),(1.26666,3,0),(2.33334,3,3))
> [3,3]((0,0,0),(0.736843,0,0),(0.714285,0.666667,0))
>
> What gives? When should I avoid using axpy_prod?
>

You should not be passing the same matrix as the first and third
argument to axpy_prod, since axpy_prod uses the third argument as
output. For example with init = true, it will start by clearing your
Gprod matrix first, thus the result you're seeing.
One way to fix would be:
matrix<double> tmp(matSize, matSize);
axpy_prod(Gprod, Garr[i+j], tmp, true);
Gprod.swap(tmp);