
/*******************************************************************************
 * Copyright 2009-2021 Intel Corporation.
 *
 * This software and the related documents are Intel copyrighted  materials,  and
 * your use of  them is  governed by the  express license  under which  they were
 * provided to you (License).  Unless the License provides otherwise, you may not
 * use, modify, copy, publish, distribute,  disclose or transmit this software or
 * the related documents without Intel's prior written permission.
 *
 * This software and the related documents  are provided as  is,  with no express
 * or implied  warranties,  other  than those  that are  expressly stated  in the
 * License.
 *******************************************************************************/

/*
   ZGEEV Example.
   ==============

   Program computes the eigenvalues and left and right eigenvectors of a general
   rectangular matrix A:

   ( -3.84,  2.25) ( -8.94, -4.75) (  8.95, -6.53) ( -9.87,  4.82)
   ( -0.66,  0.83) ( -4.40, -3.82) ( -3.50, -4.26) ( -3.15,  7.36)
   ( -3.99, -4.73) ( -5.88, -6.60) ( -3.36, -0.40) ( -0.75,  5.23)
   (  7.74,  4.18) (  3.66, -7.53) (  2.58,  3.60) (  4.59,  5.41)

   Description.
   ============

   The routine computes for an n-by-n complex nonsymmetric matrix A, the
   eigenvalues and, optionally, the left and/or right eigenvectors. The right
   eigenvector v(j) of A satisfies

   A*v(j)= lambda(j)*v(j)

   where lambda(j) is its eigenvalue. The left eigenvector u(j) of A satisfies

   u(j)H*A = lambda(j)*u(j)H

   where u(j)H denotes the conjugate transpose of u(j). The computed
   eigenvectors are normalized to have Euclidean norm equal to 1 and
   largest component real.

   Example Program Results.
   ========================

   ZGEEV Example Program Results

   Eigenvalues
   ( -9.43,-12.98) ( -3.44, 12.69) (  0.11, -3.40) (  5.76,  7.13)

   Left eigenvectors
   (  0.24, -0.18) (  0.61,  0.00) ( -0.18, -0.33) (  0.28,  0.09)
   (  0.79,  0.00) ( -0.05, -0.27) (  0.82,  0.00) ( -0.55,  0.16)
   (  0.22, -0.27) ( -0.21,  0.53) ( -0.37,  0.15) (  0.45,  0.09)
   ( -0.02,  0.41) (  0.40, -0.24) (  0.06,  0.12) (  0.62,  0.00)

   Right eigenvectors
   (  0.43,  0.33) (  0.83,  0.00) (  0.60,  0.00) ( -0.31,  0.03)
   (  0.51, -0.03) (  0.08, -0.25) ( -0.40, -0.20) (  0.04,  0.34)
   (  0.62,  0.00) ( -0.25,  0.28) ( -0.09, -0.48) (  0.36,  0.06)
   ( -0.23,  0.11) ( -0.10, -0.32) ( -0.43,  0.13) (  0.81,  0.00)
   */
#include <stdlib.h>
#include <stdio.h>
#include <mkl.h>

/* Auxiliary routines prototypes */
function void 
print_matrix_cmplx16( char* desc, int m, int n, MKL_Complex16* a, int lda );

#ifndef TEST_ZGEEV_N
#define TEST_ZGEEV_N 4
#endif

/* Main program */
static void
test_mkl_zgeev(void) {
  /* Locals */
  int N = TEST_ZGEEV_N;
  MKL_INT n = N, lda = N, ldvl = N, ldvr = N, info, lwork;
  MKL_Complex16 wkopt;
  MKL_Complex16* work;
  /* Local arrays */
  /* rwork dimension should be at least 2*n */
  double rwork[2*TEST_ZGEEV_N];
  MKL_Complex16 w[TEST_ZGEEV_N], vl[TEST_ZGEEV_N*TEST_ZGEEV_N], vr[TEST_ZGEEV_N*TEST_ZGEEV_N];
  MKL_Complex16 a[TEST_ZGEEV_N*TEST_ZGEEV_N] = {
    {-3.84,  2.25}, {-0.66,  0.83}, {-3.99, -4.73}, { 7.74,  4.18},
    {-8.94, -4.75}, {-4.40, -3.82}, {-5.88, -6.60}, { 3.66, -7.53},
    { 8.95, -6.53}, {-3.50, -4.26}, {-3.36, -0.40}, { 2.58,  3.60},
    {-9.87,  4.82}, {-3.15,  7.36}, {-0.75,  5.23}, { 4.59,  5.41}
  };
  /* Executable statements */
  LOG( " ZGEEV Example Program Results\n" );
  /* Query and allocate the optimal workspace */
  lwork = -1;
  zgeev( "Vectors", "Vectors", &n, a, &lda, w, vl, &ldvl, vr, &ldvr,
      &wkopt, &lwork, rwork, &info );
  lwork = (MKL_INT)wkopt.real;
  work = (MKL_Complex16*)malloc( lwork*sizeof(MKL_Complex16) );
  /* Solve eigenproblem */
  zgeev( "Vectors", "Vectors", &n, a, &lda, w, vl, &ldvl, vr, &ldvr,
      work, &lwork, rwork, &info );
  /* Check for convergence */
  if( info > 0 ) {
    LOG( "The algorithm failed to compute eigenvalues.\n" );
    exit( 1 );
  }
  /* Print eigenvalues */
  print_matrix_cmplx16( "Eigenvalues", 1, n, w, 1 );
  /* Print left eigenvectors */
  print_matrix_cmplx16( "Left eigenvectors", n, n, vl, ldvl );
  /* Print right eigenvectors */
  print_matrix_cmplx16( "Right eigenvectors", n, n, vr, ldvr );
  /* Free workspace */
  free( (void*)work );
  //exit( 0 );
} /* End of ZGEEV Example */

/* Auxiliary routine: printing a matrix */
function void
print_matrix_cmplx16( char* desc, int m, int n, MKL_Complex16* a, int lda ) {
  ArenaTemp scratch = scratch_get(0,0);
  int i, j;
  String8 newline = str8_lit("\n");
  String8 header = str8_pushf(scratch.arena, "\n %s\n", desc );
  LOG(header.str);
  //printf("\n %s \n", desc);
  for( i = 0; i < m; i++ ) {
    for( j = 0; j < n; j++ ) {
      String8 outstr = str8_pushf(scratch.arena, " (%6.2f,%6.2f)", a[i+j*lda].real, a[i+j*lda].imag );
      LOG(outstr.str);
      //printf(" (%6.2f,%6.2f)", a[i+j*lda].real, a[i+j*lda].imag );
    }
    LOG(newline.str);
    //printf("\n");
  }
}

/*******************************************************************************
 * Copyright 2009-2021 Intel Corporation.
 *
 * This software and the related documents are Intel copyrighted  materials,  and
 * your use of  them is  governed by the  express license  under which  they were
 * provided to you (License).  Unless the License provides otherwise, you may not
 * use, modify, copy, publish, distribute,  disclose or transmit this software or
 * the related documents without Intel's prior written permission.
 *
 * This software and the related documents  are provided as  is,  with no express
 * or implied  warranties,  other  than those  that are  expressly stated  in the
 * License.
 *******************************************************************************/

/*
   DSYEVD Example.
   ==============

   Program computes all eigenvalues and eigenvectors of a real symmetric
   matrix A using divide and conquer algorithm, where A is:

   6.39   0.13  -8.23   5.71  -3.18
   0.13   8.37  -4.46  -6.10   7.21
   -8.23  -4.46  -9.58  -9.25  -7.42
   5.71  -6.10  -9.25   3.72   8.54
   -3.18   7.21  -7.42   8.54   2.51

   Description.
   ============

   The routine computes all eigenvalues and, optionally, eigenvectors of an
   n-by-n real symmetric matrix A. The eigenvector v(j) of A satisfies

   A*v(j) = lambda(j)*v(j)

   where lambda(j) is its eigenvalue. The computed eigenvectors are
   orthonormal.
   If the eigenvectors are requested, then this routine uses a divide and
   conquer algorithm to compute eigenvalues and eigenvectors.

   Example Program Results.
   ========================

   DSYEVD Example Program Results

   Eigenvalues
   -17.44 -11.96   6.72  14.25  19.84

   Eigenvectors (stored columnwise)
   -0.26   0.31  -0.74   0.33   0.42
   -0.17  -0.39  -0.38  -0.80   0.16
   -0.89   0.04   0.09   0.03  -0.45
   -0.29  -0.59   0.34   0.31   0.60
   -0.19   0.63   0.44  -0.38   0.48
   */
#include <stdlib.h>
#include <stdio.h>
#include <mkl.h>

/* Auxiliary routines prototypes */
extern void print_matrix( char* desc, int m, int n, double* a, int lda );

/* Parameters */
#define TEST_DSYEVD_N 5
#define LDA TEST_DSYEVD_N

/* Main program */
function void 
test_mkl_dsyevd(void) {
  /* Locals */
  MKL_INT n = TEST_DSYEVD_N, lda = LDA, info, lwork, liwork;
  MKL_INT iwkopt;
  MKL_INT* iwork;
  double wkopt;
  double* work;
  /* Local arrays */
  double w[TEST_DSYEVD_N];
  double a[LDA*TEST_DSYEVD_N] = {
    6.39,  0.00,  0.00,  0.00,  0.00,
    0.13,  8.37,  0.00,  0.00,  0.00,
    -8.23, -4.46, -9.58,  0.00,  0.00,
    5.71, -6.10, -9.25,  3.72,  0.00,
    -3.18,  7.21, -7.42,  8.54,  2.51
  };
  /* Executable statements */
  LOG( " DSYEVD Example Program Results\n" );
  /* Query and allocate the optimal workspace */
  lwork = -1;
  liwork = -1;
  dsyevd( "Vectors", "Upper", &n, a, &lda, w, &wkopt, &lwork, &iwkopt,
      &liwork, &info );
  lwork = (MKL_INT)wkopt;
  work = (double*)malloc( lwork*sizeof(double) );
  liwork = iwkopt;
  iwork = (MKL_INT*)malloc( liwork*sizeof(MKL_INT) );
  /* Solve eigenproblem */
  dsyevd( "Vectors", "Upper", &n, a, &lda, w, work, &lwork, iwork,
      &liwork, &info );
  /* Check for convergence */
  if( info > 0 ) {
    LOG( "The algorithm failed to compute eigenvalues.\n" );
    exit( 1 );
  }
  /* Print eigenvalues */
  print_matrix( "Eigenvalues", 1, n, w, 1 );
  /* Print eigenvectors */
  print_matrix( "Eigenvectors (stored columnwise)", n, n, a, lda );
  /* Free workspace */
  free( (void*)iwork );
  free( (void*)work );
} /* End of DSYEVD Example */

/* Auxiliary routine: printing a matrix */
void print_matrix( char* desc, int m, int n, double* a, int lda ) {
  ArenaTemp scratch = scratch_get(0, 0);
  int i, j;
  //printf( "\n %s\n", desc );
  String8 header = str8_pushf(scratch.arena, "\n %s\n", desc);
  LOG(header.str);
  for( i = 0; i < m; i++ ) {
    for( j = 0; j < n; j++ ) 
    {
      String8 out = str8_pushf(scratch.arena, " %6.2f", a[i+j*lda] );
      LOG(out.str);
      //printf( " %6.2f", a[i+j*lda] );
    }
    LOG(str8_lit("\n").str);
  }
}


