Use of Intel® MKL data types in C/C++ applications

By oscar barragan villanueva, published on June 13 , 2011

Use of Intel® MKL data types in Intel® C/C++ applications

Currently, the following Intel® MKL types are defined in the mkl_types.h header file:
MKL_INT   - for integer values
MKL_UINT - for unsigned integer values
MKL_Complex8   - for single precision complex values   (a structure that contains single precision real and imaginary parts real and imag)
MKL_Complex16  - for double precision complex values (a structure that contains double precision real and imaginary parts real and imag)
See the Intel® MKL User's Guide and the mkl_types.h header file for more details.
The types listed above can be redefined in Intel® MKL version 10.3 update 4 so that C/C++ developers can avoid explicit argument casting when calling the library in applications that use the types "binary compatible" with those in Intel® MKL.
Such a possibility is often needed because the user can use his or her own types that can be "binary compatible", that is, having the same representation or memory layout.
For example:
  1. ISO C99 Complex type qualifier _Complex
  2. C++ Complex types std::complex
  3. There are several integer types on Linux* OS for ILP64, for example: __int64, long or long long
To redefine types supported by the Intel® MKL library, the #define statement should be used before including the mkl.h header file.
Another way to do this is to use the compiler option -D<name>=<username>, for example:
#define MKL_INT size_t
#include "mkl.h"
or
add the compiler option "-DMKL_INT=size_t" in the command line or build configuration.
Inaccurate redefinition of the Intel® MKL types may result in unpredictable computational results and/or crash of the application if the user's data types and those of Intel® MKL turn out to be incompatible (*). It is the user's responsibility to make a thorough analysis of such cases before redefining data types in Intel® MKL.
An example of incorrect redefinition for the Intel MKL integer data type: #define MKL_INT double
An example of correct redefinition of MKL_INT for ILP64 if positive integer values less than 2^63 are used:
#define MKL_INT size_t
Below is a short C++ example zhetrd.cpp on the Linux OS and Windows, that covers the correct redefinition of MKL_Complex16
and MKL_INT:
#include <stdio.h>
#define MKL_ILP64 // in order to use size_t instead of MKL_INT

#if 1 // to use user-defined MKL_INT and MKL_Complex16
#define FLEXCOMPLEX

typedef size_t  INT;
#define MKL_INT INT // this tells MKL about user's MKL_INT type

#ifdef  _WIN32
#include <complex>
typedef std::complex<double> DCOMPLEX;
#else
typedef double _Complex DCOMPLEX;
#endif

#define MKL_Complex16 DCOMPLEX // this tells MKL about user's MKL_Complex16 type

#else // using MKL default types MKL_INT and MKL_Complex16

#define DCOMPLEX MKL_Complex16
#define INT      MKL_INT

#endif

#include "mkl.h"

/* Auxiliary routine: printing a vector of doubles */
void print_vector_of_doubles( char* desc, int n, double* a ) {
    int i;
    printf( "%sn", desc );
    for( i = 0; i < n; i++ ) printf( " %.4g", a[i] );
    printf( "n" );
}

/* Parameters */
#define SIZE   4
#define LDA    SIZE
#define LWORK  (64*SIZE)
#define UPLO   "Low"

int main(void) { // based on NAG F08FSF example

    /* Locals */
    INT n = SIZE;
    INT lda = LDA;
    INT lwork = LWORK;
    INT info = 1000;

    /* Local arrays */
    DCOMPLEX A[LDA*SIZE] = {

#ifdef FLEXCOMPLEX
#ifdef _WIN32
        DCOMPLEX(-2.28, 0.00), DCOMPLEX( 1.78, 2.03), DCOMPLEX( 2.26,-0.10), DCOMPLEX(-0.12,-2.53),
        DCOMPLEX( 1.78, 2.03), DCOMPLEX(-1.12, 0.00), DCOMPLEX( 0.01,-0.43), DCOMPLEX(-1.07,-0.86),
        DCOMPLEX( 2.26,-0.10), DCOMPLEX( 0.01,-0.43), DCOMPLEX(-0.37, 0.00), DCOMPLEX( 2.31, 0.92),
        DCOMPLEX(-0.12,-2.53), DCOMPLEX(-1.07,-0.86), DCOMPLEX( 2.31, 0.92), DCOMPLEX(-0.73, 0.00)
#else
        -2.28+__I__*0.00,  1.78+__I__*2.03,  2.26-__I__*0.10, -0.12-__I__*2.53,
         1.78+__I__*2.03, -1.12+__I__*0.00,  0.01-__I__*0.43, -1.07-__I__*0.86,
         2.26-__I__*0.10,  0.01-__I__*0.43, -0.37+__I__*0.00,  2.31+__I__*0.92,
         0.12-__I__*2.53, -1.07-__I__*0.86,  2.31+__I__*0.92, -0.73+__I__*0.00
#endif
#else // struct MKL_Complex16
        {-2.28, 0.00}, { 1.78, 2.03}, { 2.26,-0.10}, {-0.12,-2.53},
        { 1.78, 2.03}, {-1.12, 0.00}, { 0.01,-0.43}, {-1.07,-0.86},
        { 2.26,-0.10}, { 0.01,-0.43}, {-0.37, 0.00}, { 2.31, 0.92},
        {-0.12,-2.53}, {-1.07,-0.86}, { 2.31, 0.92}, {-0.73, 0.00}
#endif

    };

    DCOMPLEX TAU[SIZE-1];
    DCOMPLEX WORK[LWORK];
    double D[SIZE];
    double E[SIZE-1];

    zhetrd_(UPLO, &n, A, &lda, D, E, TAU, WORK, &lwork, &info);

    if (!info) {
        print_vector_of_doubles( "Diagonal", SIZE, D);
        print_vector_of_doubles( "Off-diagonal", SIZE-1, E);
    } else
        printf( "FAILEDn" );

    return 0;
}
Use the following on the Linux OS with the Intel® compiler:
%icpc zhetrd.cpp -lmkl_rt -lpthread
and the next example illustrates linking that uses Intel® compilers on the Window OS.
%icl zhetrd.cpp mkl_rt.lib /Qopenmp

The result:

% ./a.out
Diagonal
-2.28 -0.1285 -0.1666 -1.925
Off-diagonal
-4.338 -2.023 -1.802

(*) this feature is intended for advanced users

1

Product and Performance Information

1

Intel's compilers may or may not optimize to the same degree for non-Intel microprocessors for optimizations that are not unique to Intel microprocessors. These optimizations include SSE2, SSE3, and SSSE3 instruction sets and other optimizations. Intel does not guarantee the availability, functionality, or effectiveness of any optimization on microprocessors not manufactured by Intel. Microprocessor-dependent optimizations in this product are intended for use with Intel microprocessors. Certain optimizations not specific to Intel microarchitecture are reserverd for Intel microprocessors. Please refer to the applicable product User and Reference Guides for more information regarding the specific instruction sets covered by this notice.

Notice revision #20110804