[C++-sig] Numpy array boost ublas conversion

John Reid j.reid at mail.cryst.bbk.ac.uk
Fri Dec 8 16:41:26 CET 2006


Hi,

I recently had some problems using the boost python numeric class to 
convert between numpy arrays and boost ublas matrices. I ended solving 
this in the ad-hoc method below. Perhaps someone else will find this 
useful or someone will point out how I could/should be doing this...

John.


#include <boost/numeric/ublas/matrix.hpp>
#include <boost/python.hpp>
using namespace boost::python;

/** Converts between numpy arrays and boost ublas matrices. */
struct numpy_converter
{
	typedef object object;
	typedef tuple tuple;

	object numpy;
	object array_type;
	object array_function;
	object dtype;

	/** Constructor. dtype_name determines type of matrices created. */
	numpy_converter( const char * dtype_name = "float64" )
	{
		PyObject* module = ::PyImport_Import( object( "numpy" ).ptr() );
		if( ! module  )
		{
			throw std::logic_error( "Could not import numpy" );
		}
		numpy = object( handle<>( module ) );
		array_type = numpy.attr( "ndarray" );
		array_function = numpy.attr( "array" );
		set_dtype( dtype_name );
	}

	/** Set which dtype the created numpy matrices have. */
	void set_dtype( const char * dtype_name = "float64" )
	{
		dtype = numpy.attr( dtype_name );
	}

	/** Convert a numpy matrix to a ublas one. */
	template< typename T >
	matrix &
	numpy_to_ublas(
		object a,
		boost::numeric::ublas::matrix< T > & m )
	{
		tuple shape( a.attr("shape") );
		if( boost::python::len( shape ) != 2 )
		{
			throw std::logic_error( "numeric::array must have 2 dimensions" );
		}
		m.resize(
			extract< unsigned >( shape[0] ),
			extract< unsigned >( shape[1] ) );
		for( unsigned i = 0; i < m.size1(); ++i )
		{
			for( unsigned j = 0; j < m.size2(); ++j )
			{
				m( i, j ) = boost::python::extract< T >( a[ 
boost::python::make_tuple( i, j ) ] );
			}
		}
		return m;
	}

	/** Convert a ublas matrix to a numpy matrix. */
	template< typename T >
	object
	ublas_to_numpy(
		const boost::numeric::ublas::matrix< T > & m )
	{
		//create a numpy array to put it in
		object result(
			array_type(
				boost::python::make_tuple( m.size1(), m.size2() ),
				dtype ) );

		//copy the elements
		for( unsigned i = 0; m.size1() != i; ++i )
		{
			for( unsigned j = 0; m.size2() != j; ++j )
			{
				result[ make_tuple( i, j ) ] = m( i, j );
			}
		}

		return result;
	}
};




More information about the Cplusplus-sig mailing list