1 #include <iostream>
2 #include <fstream>
3 #include <string>
4 #include <stdlib.h>
5 #include <iomanip>
6 
7 #include <boost/numeric/ublas/vector.hpp>
8 #include <boost/numeric/ublas/vector_proxy.hpp>
9 #include <boost/numeric/ublas/matrix.hpp>
10 #include <boost/numeric/ublas/matrix_proxy.hpp>
11 #include <boost/numeric/ublas/io.hpp>
12 #include <boost/timer.hpp>
13 
14 namespace numerics = boost::numeric::ublas ;
15 
16 template < typename T >
eq(const T & a,const T & b,double abstol)17 bool eq (const T& a, const T& b, double abstol)
18 {
19    return std::abs(a-b)<abstol;
20 }
21 
22 template < typename T >
23 struct is_equal
24 {
is_equalis_equal25    is_equal (double tol) : abstol(tol) {}
operator ()is_equal26    bool operator()(const T& a, const T&b) { return eq(a,b,abstol);}
27    double abstol;
28 };
29 
30 template < typename T >
random_initialise(T & v)31 void random_initialise(T& v)
32 { v = 10.0 * rand()/(RAND_MAX+1.0) ; }
33 
34 template < typename T >
random_initialise_vector(numerics::vector<T> & v)35 void random_initialise_vector(numerics::vector< T >& v)
36 {
37   size_t size = v.size();
38   for(size_t i = 0 ; i < size ; ++i ) random_initialise( v[i] ) ;
39 }
40 
41 template < typename T, typename Orientation >
random_initialise_matrix(numerics::matrix<T,Orientation> & m)42 void random_initialise_matrix(numerics::matrix< T, Orientation >& m)
43 {
44   size_t size1 = m.size1();
45   size_t size2 = m.size2();
46   for(size_t i = 0 ; i < size1 ; ++i )
47     for(size_t j = 0 ; j < size2 ; ++j )
48       random_initialise( m(i,j) ) ;
49 }
50 
51 template < typename T >
52 struct assign_multiplier
53 {
operator ()assign_multiplier54    T operator()() const
55    { return 1.0000002 ; } // otherwise the accumulated result of the range will result in 0.0 or over/under-flow
56 };
57 
58 template < typename T >
59 struct assign_multiplier< std::complex< T > >
60 {
operator ()assign_multiplier61   std::complex< T > operator()() const
62   { return std::complex< T >( cos(0.5),sin(0.5) ) + ( assign_multiplier< T >().operator() - 1.0 ) ; }
63 };
64 
65 template<class T>
flops(int multiplies,int plus,int runs,double elapsed)66 double flops(int multiplies, int plus, int runs, double elapsed)
67 { return ( multiplies * boost::numeric::ublas::type_traits<T>::multiplies_complexity + plus * boost::numeric::ublas::type_traits<T>::plus_complexity ) * runs / (1024 * 1024 * elapsed) ; }
68 
69 template<class T>
70 struct peak_c_plus {
71   typedef T value_type;
72 
operator ()peak_c_plus73   void operator () (int runs) const {
74     try {
75       static T s (0);
76       boost::timer t;
77       for (int i = 0; i < runs; ++ i) {
78         s += T (0);
79       }
80       std::cerr << flops<value_type>(0, 1, runs, t.elapsed ()) << " Mflops\n";
81     }
82     catch (std::exception &e) {
83       std::cerr << e.what () << std::endl;
84     }
85     catch (...) {
86       std::cerr << "unknown exception" << std::endl;
87     }
88   }
89 };
90 
91 template<class T>
92 struct peak_c_multiplies {
93   typedef T value_type;
94 
operator ()peak_c_multiplies95   void operator () (int runs) const {
96     try {
97       static T s (1);
98       boost::timer t;
99       for (int i = 0; i < runs; ++ i) {
100         s *= T (1);
101       }
102       std::cerr << flops<value_type>(0, 1, runs, t.elapsed ()) << " Mflops\n";
103     }
104     catch (std::exception &e) {
105       std::cerr << e.what () << std::endl;
106     }
107     catch (...) {
108       std::cerr << "unknown exception" << std::endl;
109     }
110   }
111 };
112 
113 template<class T>
114 struct peak
115 {
operator ()peak116   void operator () (int runs)
117   {
118     std::cerr << "plus       :";
119     peak_c_plus<T> () (runs);
120     std::cerr << "multiplies :";
121     peak_c_multiplies<T> () (runs);
122   }
123 };
124 
125 template < typename value_type >
check(value_type a,value_type b)126 void check(value_type a, value_type b)
127 {
128   if ( ! eq< value_type >( a, b, 1e-5 ) ) {
129     std::cerr << "\n\nregression test failure : results are not identical" << std::endl;
130     std::cerr << a << " != " << b << std::endl;
131     exit( 1 );
132   }
133 }
134 
135 template < typename Iterator0, typename Iterator1 >
check(Iterator0 begin0,Iterator0 end0,Iterator1 begin1)136 void check(Iterator0 begin0, Iterator0 end0, Iterator1 begin1)
137 {
138   Iterator0 it0 = begin0 ;
139   Iterator1 end1 = begin1 + std::distance(begin0,end0);
140   for(bool fail = false ; it0 != end0 || fail ; ++it0 ) ; // fail = ! ( *it0 < std::numeric_limits< typename Iterator0::value_type >::max() );
141 
142   Iterator1 it1 = begin1 ;
143   for(bool fail = false ; it1 != end1 || fail ; ++it1 ) ; // fail = ! ( *it1 < std::numeric_limits< typename Iterator0::value_type >::max() ) ;
144 
145   if ( it0 != end0 || it1 != end1 ) {
146     std::cerr << "\n\nregression test failure : results overflowed" << std::endl;
147     std::copy( begin0, end0, std::ostream_iterator< typename Iterator0::value_type >( std::cerr, " " ) ); std::cerr << std::endl;
148     std::copy( begin1, end1, std::ostream_iterator< typename Iterator1::value_type >( std::cerr, " " ) ); std::cerr << std::endl;
149     exit(1);
150   }
151 
152   if ( ! std::equal( begin0, end0, begin1, is_equal< typename Iterator0::value_type >( std::abs( *begin0 ) * 1e-5 ) ) ) {
153     std::cerr << "\n\nregression test failure : results are not identical" << std::endl;
154     std::cerr << std::setprecision( 20 ) ;
155     std::copy( begin0, end0, std::ostream_iterator< typename Iterator0::value_type >( std::cerr, " " ) ); std::cerr << std::endl;
156     std::copy( begin1, end1, std::ostream_iterator< typename Iterator1::value_type >( std::cerr, " " ) ); std::cerr << std::endl;
157     exit( 1 );
158   }
159 }
160 
161 template < typename value_type >
check(numerics::matrix<value_type> & a,numerics::matrix<value_type> & b)162 void check(numerics::matrix< value_type > &a, numerics::matrix< value_type > &b)
163 {
164   bool ret = true ;
165   size_t num_rows = a.size1() ;
166   size_t num_cols = a.size2() ;
167 
168   for(size_t i = 0 ; i < num_rows && ret ; ++i )
169     for(size_t j = 0 ; j < num_cols && ret ; ++j )
170       ret = eq< value_type >( a(i,j), b(i,j), 1e-5 );
171 
172   if ( ! ret ) {
173     std::cerr << "\n\nregression test failure : matrices not identical" << std::endl;
174     exit( 1 );
175   }
176 }
177 
178 template < typename T >
report(std::ostream & os,int runs,int runs_i,int size_i,double time)179 void report(std::ostream& os, int runs, int runs_i, int size_i, double time)
180 {
181   double normed_time = runs * time / ( runs_i * size_i ) ;
182   double mflops = flops<T>(size_i,0,runs_i,time) ;
183   std::cerr << std::setw(12) << normed_time << std::setw(12) << mflops ;
184   os        << std::setw(12) << normed_time << std::setw(12) << mflops ;
185 }
186 
187 template < typename FunctorType >
loop(std::ostream & os,int start,int step,int stop,int runs,FunctorType functor)188 void loop(std::ostream& os, int start, int step, int stop, int runs, FunctorType functor)
189 {
190   for(int size_i = start ; size_i <= stop ; size_i = std::max( static_cast< int >( size_i * (1 + 1.0 / step ) ), size_i + 1 ) ) {
191     int runs_i = 10 * runs / size_i ;
192 
193     std::cerr << size_i << "\t";
194     os        << size_i << "\t";
195 
196     functor.operator()( os, stop, size_i, runs, runs_i ) ;
197 
198     std::cerr << std::endl;
199     os        << std::endl;
200   }
201 }
202 
203 template < typename FunctorType, typename CallFunctor >
loop(std::ostream & os,int start,int step,int stop,int runs,FunctorType functor,CallFunctor ublas_call)204 void loop(std::ostream& os, int start, int step, int stop, int runs, FunctorType functor, CallFunctor ublas_call)
205 {
206   for(int size_i = start ; size_i <= stop ; size_i = std::max( static_cast< int >( size_i * (1 + 1.0 / step ) ), size_i + 1 ) ) {
207     int runs_i = 10 * runs / size_i ;
208 
209     std::cerr << size_i << "\t";
210     os        << size_i << "\t";
211 
212     functor.operator()( os, stop, size_i, runs, runs_i, ublas_call ) ;
213 
214     std::cerr << std::endl;
215     os        << std::endl;
216   }
217 }
218