I am building a library of matrix and vector operations. As my library has grown bigger, I have found that there are MANY by element operations which I need to program.

For example, if the user wants to multiply each element in the matrix by 2, or if the user wants to square each element in the matrix, then I must write a function for each of those operations.

All of these "by element operations" functions are extremely similar in layout, and I have provided one below. My question is, is there a shortcut I can use to make byElementOperation functions without typing up a new function every single time?

Or, is there a way I can make these functions one-liners?

#include <cmath>
using namespace std;

typedef vector<double> Vec;
typedef vector<Vec> Mat;

Vec log( Vec y ){
	for( short e=0; e<y.size(); ++e ) y[e] = log( y[e] );
return y;
}
Mat log( Mat a ){
	for( short r=0; r<a.size(); ++r ) a[r] = log( a[r] );
return a;
}

Recommended Answers

All 11 Replies

Your using the wrong structure, check out std::valarray

Okay, so if I want to switch everything over from my Vec and Mat to valarray, will I lose any functionality?

I use the .push_back() function sometimes, and I resize vectors on occasion.

Secondly, would this be the way to go about it?...

#include <valarray>
using namespace std;

typedef valarray<double> Vec;
typedef valarray<Vec> Mat;

If it is that simple then it seems I wouldn't have to edit my actual code much, except to simplify things of course.

But if you don't want to use that, then check out std::tranform

Here is an example of use :

#include <algorithm>
#include <iostream>
#include <vector>
#include <functional>
#include <iterator>
#include <cmath>
using namespace std;


template<typename ITR>
void print( ITR begin, ITR end){
	while(begin != end) cout << *begin++ << " ";
	cout << endl;
}
int main(){
	int data[] = {1,4,9,16,25};
	typedef std::vector<int> Array;
	Array src(data,data + sizeof(data)/sizeof(*data) );
	Array dest;	

	
	cout << "Before: ";
	print(src.begin(),src.end());

	std::transform( src.begin(), src.end(), //our source
					std::back_insert_iterator<Array>(dest), //our destination					
					std::bind2nd(std::multiplies<int>(),2) //multiply by 2 to each number
					);

	cout << "After: ";
	print(dest.begin(),dest.end());
}

Sounds pretty awesome. It also sounds like I've been doing a lot of unnecessary work :o

Thanks!

Okay, so if I want to switch everything over from my Vec and Mat to valarray, will I lose any functionality?

I use the .push_back() function sometimes, and I resize vectors on occasion.

Secondly, would this be the way to go about it?...

#include <valarray>
using namespace std;

typedef valarray<double> Vec;
typedef valarray<Vec> Mat;

If it is that simple then it seems I wouldn't have to edit my actual code much, except to simplify things of course.

unfortunately, valarray doesn't behave the same as vector or doesn't have the same interface. So maybe your better off using std::transform. Or create a push_back method for the valarray and the resize method as well

Transform looks kinda complicated with so many inputs. I think valarray will work well. Thank you.

Just a thought:

>>I am building a library of matrix and vector operations.

>>then I must write a function for each of those operations.

It seems odd to me that you are building a library for matrix and vector operations and you are complaining that you need to write all the operations. Isn't that what "building a library for matrix and vector operations" mean?

Furthermore, it seems odd that you want to perform all these element-wise operations... that doesn't really make sense in vector/matrix/tensor algebra. If someone takes the square root of a matrix, the normal semantics for a square root operation on a matrix is certainly not an element-wise operations (more like a Cholesky decomp or something more general).

Also, you have to watch out with the use of typedefs. Remember that typedefs are not new types, they are just an alias for a type name. So, if you define your own operator like log( Mat ), and Mat is a typedef for valarray<Vec>, it will be ambiguous with the std::log version for std::valarray. Additionally, you should not import the std namespace in a header, I mean, you really should NOT do that. And you should also create your own namespace for your library too.

Final thought, don't reinvent the wheel, use a matrix library off-the-shelf. Like Blitz++, Boost.uBLAS, or mine (ReaK.math).

Final thought, don't reinvent the wheel, use a matrix library off-the-shelf. Like Blitz++, Boost.uBLAS, or mine (ReaK.math).

One of these sounds great. I am looking for something I can easily #include into my code. The idea of software is a bit scary to me because I feel it may complicate things more than simplify.

Do all of these require downloading, or are any built into C++? In your opinion, which is the simplest?

Thanks very much for your advice. :X

None of them are built into C++. However, the Boost library is almost like the standard C++ library (Boost is often called the anti-chamber of the C++ standard libraries, for example, most of the new standard libraries in the upcoming C++ standard are taken directly from Boost, almost verbatim). This is you safest bet as a care-free add-on to your code. You do need to install it though. If you use Linux or Mac, this is very easy, just get the latest stable version from your package management system (e.g. Linux: $ sudo apt-get install libboost-all-dev), and that's it. If you use windows, then you have to download the latest distribution from Boost and install manually. To use the uBLAS library you will not need to build and link anything (it's a header-only library), so it's just a matter of adding the Boost install directory to your project's include paths, and you are good to go. At that point, all you need is to follow the instructions on how to use the various parts of the library and #include the headers that they say you need to include.

Blitz++ is not recommended unless you have very good knowledge of C++ (and it is not the most feature-rich library either, although it is very efficient).

My own library is somewhat experimental (and linear algebra is not the focus of it), and is also not recommended unless you have very good knowledge of C++ (and it does require a little bit of building and linking, because I implement special features that the other libraries don't).

But, these three that I cited are just the tip of the iceberg, there are innumerable linear algebra packages out there, but these are the main ones which are actual pure C++ code (most others are C or Fortran libraries that are wrapped in a thin coat of C++).

Additionally, you should not import the std namespace in a header, I mean, you really should NOT do that. And you should also create your own namespace for your library too.

Mike,

I have never really known the proper way to treat namespaces. Let me take a guess at what I should be doing.

In my header.h file:
using namespace MareoRaftsNamespace;

In my program.cpp file:
using namespace std;

And do I actually need to define this namespace somehow, or do I just need the name?

Thanks! :)

To create a namespace, you do as follows:
In your header file:

#ifndef MY_HEADER_HPP
#define MY_HEADER_HPP

#include ...

namespace my_name_space {

class my_class {
  //..
};

};

#endif

When you define functions in your cpp file, you also use the same namespace enclosure.

You have to understand the meaning of the statement "using namespace std;". What this statement means is that you "import" all the names that are in the std namespace into the scope where that statement appears. If you do this at the global scope, then you are basically putting all the implementation of the standard libraries into the global namespace. For small programs this is ok, but for library-code or any non-trivial piece of code, you are better leave standard functions in the std namespace, don't import them.

Now, even worse is importing the std namespace (or any other namespace) in a header file. Header files are meant to be included by other headers and source files. If you do a "using namespace .." statement in your header, you are silently importing a namespace into a scope where the "user" does not expect it (by "user" I mean the coder that includes your header file)­. The reason namespaces exist is to create a private naming-space where you can pick smaller, simpler, clearer names for things you program without fear that some other developer of some other library chose the same name for something else. Importing a namespace completely breaks this feature.

It is OK to do a "using namespace .." statement in two places:
1) In a source file (.cpp, or "translation unit" to be formal), after all headers have been included.
2) In a function's body (in any file).

The second case is useful if you have implementation code in a header file which frequently refers to elements to a particular namespace. Importing a namespace is limited to its enclosing scope, so doing a "using namespace .." in a function's body will not pollute the outside world, and it will make code clearer within the function body.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.