1

based on the example here http://www.boost.org/doc/libs/release/libs/utility/operators.htm#example, I have implemented the following derived class of boost::numeric::ublas::vector:

namespace Chebyshev
{
  template<typename T>
  class function_data : public boost::numeric::ublas::vector<T>,
                               boost::addable<function_data<T> >,
                               boost::subtractable<function_data<T> >,
                               boost::multipliable2<function_data<T>, T>,
                               boost::dividable2<function_data<T>, T>
  {
    public:
      char dataflag;
      function_data() : boost::numeric::ublas::vector<T>() {dataflag=0;} ///< The default empty constructor
      function_data(const boost::numeric::ublas::vector<T>& vec) : boost::numeric::ublas::vector<T>(vec) {dataflag=0;} ///< The copy constructor without a flag.
      function_data(const boost::numeric::ublas::vector<T>& vec, char flag) : boost::numeric::ublas::vector<T>(vec), dataflag(flag) {} ///< The copy constructor with a flag.
      ~function_data() {} ///< The destructor.
      function_data<T>& operator= (const boost::numeric::ublas::vector<T>& in) {boost::numeric::ublas::vector<T>::operator=(in); return *this;} ///< The assignment operator from a boost::numeric::ublas::vector<T>.
      function_data<T>& operator= (const function_data<T>& in) {boost::numeric::ublas::vector<T>::operator=(in); dataflag=in.dataflag; return *this;} ///< The assignment operator.
      function_data<T>& operator+= (const function_data<T>& in) {this->boost::numeric::ublas::vector<T>::operator+=(in); this->dataflag=this->dataflag; return *this;}
      function_data<T>& operator-= (const function_data<T>& in) {this->boost::numeric::ublas::vector<T>::operator-=(in); this->dataflag=this->dataflag; return *this;}
      function_data<T>& operator*= (T in) {this->boost::numeric::ublas::vector<T>::operator*=(in); this->dataflag=this->dataflag; return *this;}
      function_data<T>& operator/= (T in) {this->boost::numeric::ublas::vector<T>::operator/=(in); this->dataflag=this->dataflag; return *this;}
      friend std::ostream& operator<< (std::ostream& os, const function_data<T>& fd) {os << "[type " << fd.dataflag << "] " << static_cast<boost::numeric::ublas::vector<T> >(fd); return os;} ///< The << operator.
  };
}

However, compiling the following snippet of code

int main( int argc, char ** argv)
{
  Chebyshev::function_data<std::complex<double> > u;
  /* some stuff putting values in u */
  std::cout << u*2 << std::endl;
  return 0;
}

gives a "ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second" warning and proceeds to give the ublas vector_expression version (with u cast as some kind of vector_expression) and my version (with 2 cast as a const std::complex<double>&).

I would like to be able to use mixed arithmetic in my class as in the above snippet of code, but the explanation on the boost::operators website isn't clear to me. What do I have to add or change in my class to allow this?

Also, in the example, the inheritance list has each class inside the last > of the previous class. I don't see any difference in the output of the compiler whether I write it that way or the way I have above. Which is the proper way to write it?

Best regards, Brett.

ildjarn
  • 62,044
  • 9
  • 127
  • 211
Brett Ryland
  • 1,045
  • 1
  • 9
  • 17
  • Does `class function_data` have to inherit `boost::numeric::ublas::vector`? Can it not just have a member of type `boost::numeric::ublas::vector`? – yasouser Jun 01 '11 at 16:57
  • I could rewrite the code that way, but I'd prefer to work with `function_data` as if it were a `boost::numeric::ublas::vector` with an extra flag to indicate the type (not datatype ;-)) of data it holds. – Brett Ryland Jun 01 '11 at 17:08
  • @Brett: You might want to checkout these questions in SO: 1) http://stackoverflow.com/questions/4353203/thou-shalt-not-inherit-from-stdvector 2) http://stackoverflow.com/questions/2034916/is-it-okay-to-inherit-implementation-from-stl-containers-rather-than-delegate and 3) http://stackoverflow.com/questions/679520/advice-on-a-better-way-to-extend-c-stl-container-with-user-defined-methods – yasouser Jun 01 '11 at 17:13
  • @yasouser: Fair enough. If I make the `...vector` a member of function_data and implement the operators required for the addable, subtractable, multipliable2 and dividable2, will this automatically allow for mixed arithmetic in my function_data class? – Brett Ryland Jun 01 '11 at 17:29
  • @Brett: Your example code should compile fine, assuming your implementation of all the operators are correct. The `class function_data` acts as a wrapper to `...ublas::vector`. – yasouser Jun 01 '11 at 17:40
  • @yasouser: Thanks. Any idea about the `>`s in the example? Is it simply a choice of formatting style or does it have some noticeable implementation difference? – Brett Ryland Jun 01 '11 at 19:48
  • @Brett: Are you trying to do vector arithmetic operations using boost ublas? – yasouser Jun 02 '11 at 19:15
  • @yasouser: Yes. I'm implementing a toolbox for doing spectrally accurate approximations of functions, their gradients and their integrals on simplicial domains using multivariate Chebyshev polynomials. Functions can be represented either by their values or by the coefficients of the approximating polynomials (using FFTW to switch between the two), but are indistinguishable by just looking at the values in the vector, thus I need the extra dataflag. I would like to implement a few arithmetic operators that take into account the dataflag variable and call the appropriate ublas rountine. – Brett Ryland Jun 03 '11 at 10:06
  • @Brett: Have you looked at the vector_expressions<> in boost ublas (http://www.boost.org/doc/libs/1_46_1/libs/numeric/ublas/doc/expression_concept.htm#2VectorExpression)? – yasouser Jun 03 '11 at 17:35
  • @yasouser: I've had a look at them, but I don't see how they help here (I'm not sure I understand how vector_expressions differ from vectors well enough). I'm basically using the dataflag variable to simplify the interface to the various functions in the toolbox and to reduce the possibilities of a user to write nonsensical code with it. – Brett Ryland Jun 03 '11 at 23:25

1 Answers1

0

Boost uBLAS has all the operators that you need to vector arithmetic. Here is a sample program to highlight it:

#include <iostream>

#include "boost/numeric/ublas/vector.hpp"
#include "boost/numeric/ublas/io.hpp"

using namespace boost::numeric::ublas;

int main()
{
  vector<int> v1(4);
  vector<int> v2(4);
  vector<int> v3(4);
  vector< std::complex<double> > v4(4);

  for (size_t i = 0; i < v1.size(); i++)
    v1(i) = (i + 1) * 3;
  for (size_t i = 0; i < v1.size(); i++)
    v2(i) = (i + 1) * 10;
  for (size_t i = 0; i < v4.size(); i++)
    v4(i) = std::complex<double>(v1(i), v2(i));

  std::cout << "v1: " << v1 << std::endl;
  std::cout << "v2: " << v2 << std::endl;
  std::cout << "v3 = v2 * 3: " << (v3 = v2 * 3) << std::endl;
  std::cout << "v4: " << v4 << std::endl;
  std::cout << "v1 + v2: " << v1 + v2 << std::endl;
  std::cout << "v1 - v2: " << v1 - v2 << std::endl;
  std::cout << "v1 * 3: " << v1 * 3 << std::endl;
  std::cout << "(v2 * 2) / 3: " << (v2 * 2) / 3 << std::endl;
  std::cout << "v4 * 3: " << v4 * 3 << std::endl;
  std::cout << "v4 + v4" << v4 + v4 << std::endl;

  std::cout << "element_prod(v1, v2)" << element_prod(v1, v2) << std::endl;
  std::cout << "element_div(v2, v1)" << element_div(v2, v1) << std::endl;

  return 0;
}

Here is the output I got when I compiled and ran using g++ v4.1.2:

[ublas]$ g++ -o vector vector.cpp 
[ublas]$ ./vector 
v1: [4](3,6,9,12)
v2: [4](10,20,30,40)
v3 = v2 * 3: [4](30,60,90,120)
v4: [4]((3,10),(6,20),(9,30),(12,40))
v1 + v2: [4](13,26,39,52)
v1 - v2: [4](-7,-14,-21,-28)
v1 * 3: [4](9,18,27,36)
(v2 * 2) / 3: [4](6,13,20,26)
v4 * 3: [4]((9,30),(18,60),(27,90),(36,120))
v4 + v4[4]((6,20),(12,40),(18,60),(24,80))
element_prod(v1, v2)[4](30,120,270,480)
element_div(v2, v1)[4](3,3,3,3)
yasouser
  • 5,113
  • 2
  • 27
  • 41
  • I am familiar with ublas vectors (not vector_expressions) and it is those operators (plus element_prod and element_div) that I wish to use for the underlying operations. An example: let `ublas::vector u` and `char flag` be members of `function_data` and let `a` and `b` be instances of `function_data` with `a.flag=v` and `b.flag=c` (two functions, represented as function values and coefficients resp.). Suppose I write `a*=b`. The `*=` must detect that `a` and `b` have different flags, convert `b` to have `b.flag=v` through applying an FFT to `b.u`, then call `a.u=element_prod(a.u,b.u)`. – Brett Ryland Jun 04 '11 at 10:05
  • Looks like you want `operator *=` to do more than just multiply. UBLAS `operator *=` only allows multiplying a vector with a scalar. I think that your requirement to do FFT on one of your operands before doing `element_prod()` violates the semantics of `operator *=`. Moreover, what is the purpose for member `flag` in `function_data`? – yasouser Jun 04 '11 at 19:37
  • ublas vectors internally use vector_expressions. The operator methods of ublas vector uses vector_expression. Also I think the following link will be useful for you: http://www.boost.org/doc/libs/1_45_0/libs/numeric/ublas/doc/operations_overview.htm – yasouser Jun 04 '11 at 19:43
  • You seem to be missing the point of what I'm trying to do. The operators in the `function_data` class are for operating on mathematical functions, e.g. f(x), g(x). These are represented as ublas vectors containing either sample values or coefficients, indicated by `flag`. To perform some operation such as (f*g)(x), f(x) and g(x) need to be represented in the same way, thus the `function_data` operators must make some decisions/sanity checks based on `flag` and call the appropriate ublas operations. – Brett Ryland Jun 05 '11 at 09:55
  • Your comment near the top with the links to the 3 SO questions persuaded me to have the vector as a member of `function_data` instead of using inheritence, so my question is then about the `> > > >` in the heritence chain in the boost::operators example. I.e. should it be `class point : boost::addable, boost::subtractable, ... > >` or `class point : boost::addable >, boost::subtractable >, ...`? Both seem to compile, but is there a difference in functionality between these two cases? – Brett Ryland Jun 05 '11 at 10:06