Hi Julian, thanks for your reply

The code I have trouble with is something like this:

using namespace std;

template<class T> struct MKL_Traits {
  typedef T mType;
  typedef T mPrec;
};

template<> struct MKL_Traits<complex<float> > {
  typedef MKL_Complex8 mType;
  typedef float mPrec;
};

void sTest(float*,int*);
void cTest(MKL_Complex8*,int*);

template<class T> void testWrapper(typename MKL_Traits<T>::mType *,int *);

template<> void testWrapper<float>(typename MKL_Traits<float>::mType *m,int *info)
{
  sTest(m,info);
}

template<> void testWrapper<complex<float> >(typename MKL_Traits<complex<float> >::mType *m,int *info)
{
  cTest(m,info);
}


compiles fine with g++, but visual studio says that the explicit specialisation is not an specialisation of a function template. It is not really a problem, as overloading does it. I was trying to use templates as I expect these to get inlined no matter what, while the overloaded functions may or may not get inlined depending on the optimisation options, am I correct in this assumption?

The traits comes into play in some LAPACK functions that mix real and complex types. For instance, singular value decomposition, the singular values are real, but the matrices are complex, so the SVDecomposition class is something like:

template <class T> class SVDecomposition {
public:
  /// default constructor
        CSVDecomposition(void):mSingularValues(Array<typename MKL_Traits<T>::mPrec,1>(FortranArray<1>())),mU(Array<T,2>(FortranArray<2>())),mVT(Array<T,2>(FortranArray<2>())){;}
        /// perform the transformation
  virtual void DoTransform(const Array<T,2>&);
  /// return the matrix U (left singular vectors)
  Array<T,2> U(void){return mU;}
  /// return the transpose of V (right singular vectors)
  Array<T,2> VT(void){return mVT;}
  /// return the singular values of the matrix
  Array<typename MKL_Traits<T>::mPrec,1> SingularValues(void){return mSingularValues;}
private:
/// contains the singular values
 Array<typename MKL_Traits<T>::mPrec,1> mSingularValues;
 /// contains U
 Array<T,2> mU;
 /// contains VT
 Array<T,2> mVT;
};

that way for float both the singular values and the matrices are float, but for complex<float> the singular values are float and the matrices are complex<float>, so I avoid having to specialise SVDecomposition for the complex types explicitly. Also, it should help if the representation for complex in LAPACK changed, in that case only the traits struct needs to be changed, and the rest of the code is independent of the particular representation LAPACK uses (so long as the pointers can be casted to and fro).

Am I doing things too complicated unnecessarily?

Regards

Carlos A. Rega, PhD
Development Scientist
Malvern Instruments Ltd
Grovewood Rd, Malvern
WR14 1XZ

Tel: +44 (0)1684 581 304
Fax: +44 (0)1684 892 789

e-mail: carlos.rega@malvern.co.uk



"Julian C. Cummings" <cummings@cacr.caltech.edu>
Sent by: blitz-support-bounces@oonumerics.org

10/06/2004 21:40
Please respond to cummings; Please respond to Support list for Blitz++

       
        To:        "'Support list for Blitz++'" <blitz-support@oonumerics.org>
        cc:        
        Subject:        RE: [Blitz-support] Template support in VC++ .NET



Hello Carlos,

I would need to see the precise code being compiled to offer more specific
comments.  However, just looking over the code snippets below, I am puzzled
by this one:

> template<class T>
> void lapack_function_wrapper(MKL_Traits<T>::Type *,MKL_Traits<T>::Type
*,int*)

Why would you template the wrapper function on the exported types from the
MKL_Traits class rather than templating on the initial type T and then
converting types inside the wrapper function specializations?  How is this
any better than simple overloading?

void lapack_function_wrapper(float *x, float *y, int *z) {
   return slapack_function(x,y,z);
}
void lapack_function_wrapper(double *x, double *y, int *z) {
   return dlapack_function(x,y,z);
}
void lapack_function_wrapper(std::complex<float> *x, std::complex<float> *y,
int *z) {
   return clapack_function(reinterpret_cast<MKL_Complex8 *>(x),
                           reinterpret_cast<MKL_Complex8 *>(y), z);
}
void lapack_function_wrapper(std::complex<double> *x, std::complex<double>
*y, int *z) {
   return zlapack_function(reinterpret_cast<MKL_Complex16 *>(x),
                           reinterpret_cast<MKL_Complex16 *>(y), z);
}

Since you are specializing the wrapper function, there is no real need to
utilize the MKL_Traits class here, as the result type is already known.
Maybe I am missing something here?  A complete example of the code that
fails to compile under VS.NET would help clarify the problem you are having.
I tried to cook up my own example using template specialization, but I don't
encounter any similar compilation problems with VS.NET.

Regards, Julian C.

Dr. Julian C. Cummings
Staff Scientist, CACR/Caltech
(626) 395-2543
cummings@cacr.caltech.edu


> -----Original Message-----
> From: blitz-support-bounces@oonumerics.org
> [mailto:blitz-support-bounces@oonumerics.org] On Behalf Of
> carlos.rega@malvern.co.uk
> Sent: Thursday, June 10, 2004 2:52 AM
> To: Support list for Blitz++
> Subject: [Blitz-support] Template support in VC++ .NET
>
>
>
> Hi,
>
> Just had a quick look about the exporting makefiles issue in
> the VC++ help, and the 2003 version explicitly says that you
> can not export makefiles (whatever the reason for that may
> be). However, there seems to be the possibility of running
> the editor, would you believe it, in a command line mode that
> will treat the solution file as a makefile. Whatever was
> wrong with exporting makefiles and running them through nmake
> does not explain.
>
> Anyhow, now that I am in rant mode about Visual Studio I will
> comment on a problem I have found. As I said in a previous
> message we are trying to write a wrapper that uses blitz and
> the intel MKL implementation of LAPACK. In general it is
> rather simple, just passing the pointers returned by the
> data() method to the LAPACK functions.
>
> I started writing my code using gcc, just to check that the
> project was feasible and would not take a huge amount of
> time. Using gcc I used the following approach to wrap the
> LAPACK functions. For each function there are usually 4
> flavours, two real (single and double precision) and two
> complex (again single and double). The signature of the
> function is the same, only the types of the arguments are different:
>
> slapack_function(float *,float*,int*)  // single precision real
> dlapack_function(double*,double*,int*)  // double precision real
> clapack_function(MKL_Complex8*,MKL_Complex8*,int*) // single
> precision complex

> zlapack_function(MKL_Complex16*,MKL_Complex16*,int*) //
> double precision complex
>
> the MKL_Complex types are structs like:
>
> struct MKL_Complex8 {
>         float real;
>         float imag;
> };
>
> so you can cast safely from complex<float>* to MKL_Complex8*
> and the other way around.
>
> The C++ interface will be a set of classes that call MKL as a
> back-end, and use blitz for the matrix representation, like so:
>
> template<class T> class LUFactorisation
> {
>
> public:
>
>          /// default constructor
>
>        
> CLUFactorisation(void):mResult(Array<T,2>(FortranArray<2>())),
> mIpiv(Array<int,1>(FortranArray<1>())){;}
>
>         /// implements the call to the LAPACK function
>
>         void Factor(const Array<T,2>&);
>
>         /// returns the L matrix
>
>         Array<T,2> L(void);
>
>         /// returns the U matrix
>
>         Array<T,2> U(void);        
>
> private:
>
>         Array<T,2> mResult;
>
>         /// contains the permutation vector, row i is swapped
> with row mIpiv(i)
>
>         Array<int,1> mIpiv;
>
> };
>
> There are two possibilities for getting Factor to call the
> right LAPACK function, explicit specialisation of the
> template for each type, or writing a template function that
> wraps the LAPACK function and let the compiler generate the
> four different Factor functions. The second approach is more
> economical, as in this case the only difference between the
> four template specialisations is which function to call, and
> the rest of the code is exactly the same.
>
> So, I would write something like:
>
> template<class T> void
> lapack_function_wapper(MKL_Traits<T>::Type
> *,MKL_Traits<T>::Type *,int*)
>
> and specialise for each type. Here MKL_Traits<T>::Type
> returns the correct type expected by the MKL functions, float
> for T = float, double for T=double, MKL_Complex8 for
> complex<float> and MKL_Complex16 for complex<double>.
>
> This worked fine with gcc, with these wrappers getting
> expanded in line, even without optimisation.
>
> Now, here it is a VS only shop, so I need to port that code
> to VS, luckily VS .NET 2003 compiles blitz, so it should be a
> matter of just copying the files and generating the project,
> as there is nothing really fancy in what I have written,
> right? Nope, The above template trick will not work in VS, it
> refuses to recognise the specialisations as specialisations
> of the above template, and I end up with no other choice but
> to use overloading instead. Not that overloading is all that
> bad, but I would expect that templates would give slightly
> better performance, as they should get automatically inlined
> at compile time, while it might be slightly trickier to get
> the compiler to inline the overloaded functions.
>
> So, my question is, is what I am trying to do non standard
> and it just happens that it works in gcc, but it is not
> really supposed to or is VS support of templates still
> slightly flaky?
>
> Thanks for your patience
>
> Carlos A. Rega, PhD
> Development Scientist
> Malvern Instruments Ltd
> Grovewood Rd, Malvern
> WR14 1XZ
>
> Tel: +44 (0)1684 581 304
> Fax: +44 (0)1684 892 789
>
> e-mail: carlos.rega@malvern.co.uk
>
> --------------------------------------------------------------
> ------------------------------------------------------
> This email and any files transmitted with it are confidential
> and intended solely for the use of the individual or entity
> to whom they are addressed.
>
> If you have received this email in error please notify the
> originator of the message.
>
> Any views expressed in this message are those of the
> individual sender, except where the sender specifies and with
> authority, states them to be the views of Malvern Instruments.
>
>


_______________________________________________
Blitz-support mailing list
Blitz-support@oonumerics.org
http://www.oonumerics.org/mailman/listinfo.cgi/blitz-support





--------------------------------------------------------------------------------------------------------------------
This email and any files transmitted with it are confidential and
intended solely for the use of the individual or entity to whom
they are addressed.

If you have received this email in error please notify the
originator of the message.

Any views expressed in this message are those of the individual
sender, except where the sender specifies and with authority,
states them to be the views of Malvern Instruments.