0

I am trying to calculate eigenvalues of a matrix using a downloaded tqli algorithm. As a simple example I am trying to test it for a 4x4 identity matrix:

double ze[4][4];
double *zepointer;
ze[0][0] = 1;
ze[1][1] = 1;
ze[2][2] = 1;
ze[3][3] = 1;

ze[0][1] = 0;
ze[1][0] = 0;
ze[0][2] = 0;
ze[2][0] = 0;

ze[0][3] = 0;
ze[3][0] = 0;
ze[1][2] = 0;
ze[2][1] = 0;

ze[1][3] = 0;
ze[3][1] = 0;
ze[2][3] = 0;
ze[3][2] = 0;

zepointer = &ze;

tqli(de,ee,4,zepointer);

Besides that there is hopefully a smarter way to produce an identity matrix my compiler gives me a warning saying 'double ' differs in levels of indirection from 'double ()[4][4]' for the line 'zepointer = &ze;'. I looked at this question and there it says the warning comes from referencing before declaring. However I can not see that I have done that in my code snippet.

TQLI is an algorithm to calculate eigenvalues and eigenvectors. I downloaded it from here.

Axel
  • 1,415
  • 1
  • 16
  • 40
  • 2
    Array indexes are *zero based*. So an array of four elements have indexes from `0` to `3` (inclusive). – Some programmer dude Feb 19 '18 at 13:25
  • 2
    As for your error (or rather how to solve it) what are you trying to do? What is `tqli`, what is its arguments, and what is `zepointer` supposed to actually point to? – Some programmer dude Feb 19 '18 at 13:26
  • Oh wow... Matlab really made me stupid. Could that be a source of the error though? – Axel Feb 19 '18 at 13:26
  • @Axel There should be so many duplicates for your question... – llllllllll Feb 19 '18 at 13:28
  • Possible duplicate of [Create a pointer to two-dimensional array](https://stackoverflow.com/questions/1052818/create-a-pointer-to-two-dimensional-array) – llllllllll Feb 19 '18 at 13:28
  • It all depends on how your `tqli` is defined, but most likely what you need is `double **zeropointer` instead of `double *zeropointer` – ChatterOne Feb 19 '18 at 13:28
  • TQLI is a QL algorithm that calculates eigenvalues and eigenvector. The first input is the diagonal elements of the matrix, the second the subdiagonal elements and the last an identity matrix that in which columns the eigenvectors will be written. – Axel Feb 19 '18 at 13:29
  • 1
    @ChatterOne **No**. There's no way to get a `double**` from a `double[4][4]`. *Arrays are not pointers.* – Angew is no longer proud of SO Feb 19 '18 at 13:35
  • I tried using double **zeropointer. It gave me the same error. – Axel Feb 19 '18 at 13:42
  • How is `tqli()` declared? – alk Feb 19 '18 at 13:42
  • As void tqli(double d[], double e[], int n, double **z) – Axel Feb 19 '18 at 13:44
  • @Axel, it appears that you are trying to obtain the address of the first element of the first row of your matrix, but until you show us how you intend to use it we can't really help you. You could get that value with `zepointer = &ze[0][0]`, but that may not help. If you want to do direct pointer arithmetic, you should not use a multi-dimensional array. Pick one representation and stick with it. – William Pursell Feb 19 '18 at 14:02
  • Ok as shown there I made a double *zeptr; that is defined as zeptr = &ze[0][0]; With that there are no errors while building but during runtime the calculation crashes. – Axel Feb 19 '18 at 14:03
  • @Angew Where did I say that he should assign `ze` to `zeropointer`? I said that he needed a `double **` because *most likely* that's what the function was expecting. And indeed, it was. – ChatterOne Feb 19 '18 at 14:05
  • So to summarize: When a function is declared as double **z it expects a pointer to the first element of a matrix using double *zeptr; zeptr = &ze[0][0];? – Axel Feb 19 '18 at 14:11
  • When a function expects `double**` you need to pass a `double**`. `&ze[0][0]` evaluates to a `double*` only. – alk Feb 19 '18 at 14:53

2 Answers2

0

I am trying to calculate eigenvalues of a matrix using a downloaded tqli algorithm

There is no way to get a double** pointer by trying to cast double[4][4].

You have to use different approach to supply required double ** pointer for the tqli function.

You can pass your data using one of the method below.

First method:

1) Allocate memory for pointers to pointers double **aa and initialize them with pointers to row vectors in the a array.

Second method:

2) Allocate memory for pointers to matrix rows (as above). Allocate memory for the content of the rows. Copy all element values from your ze.

The testing program:

#include <stdlib.h>
#include <stdio.h>

#define M_SIZE  4  // size of the nxn matrix

void tqli(double d[], double e[], int n, double **z)
{
    int i,j;

    for(i=0; i<n; i++)
    {
        for(j=0; j<n; j++)
        {
             double d = z[i][j]; 
             printf(" z[%i][%i] = %f \n", i, j, d );
        }
        printf("\n"); 
    }
}

int main()
{
    int i,j;

    double ze[M_SIZE][M_SIZE];
    double **zepointer;

    ze[0][0] = 1;
    ze[1][1] = 1;
    ze[2][2] = 1;
    ze[3][3] = 1;

    ze[0][1] = 0;
    ze[1][0] = 0;
    ze[0][2] = 0;
    ze[2][0] = 0;

    ze[0][3] = 0;
    ze[3][0] = 0;
    ze[1][2] = 0;
    ze[2][1] = 0;

    ze[1][3] = 0;
    ze[3][1] = 0;
    ze[2][3] = 0;
    ze[3][2] = 0;

    double de[M_SIZE] = {0};
    double ee[M_SIZE] = {0};

   // 1.---------------------

    printf(" First array is { {6,7,8,9}, {1,6,1,5}, {6,2,2,4}, {1,2,3,4} } \n"); 

    double a[M_SIZE][M_SIZE]={ {6,7,8,9}, {1,6,1,5}, {6,2,2,4}, {1,2,3,4} };

    double **aa = malloc( M_SIZE * sizeof(double*)); // allocate memory to hold the pointers to all rows

    for(i=0; i<M_SIZE; i++) 
        aa[i] = a[i];     // initialize pointers to the `a` rows

    tqli(de,ee,M_SIZE,aa); // test

    free(aa);              // free memory for row pointers


   // 2.--------------------

   printf(" Second array is { {1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1} } \n"); 

   zepointer = malloc( M_SIZE * sizeof(double*));    // allocate memory to hold the pointers to all rows

   // allocate memory for every row to hold column elements
   for(i=0; i<M_SIZE; i++) 
      zepointer[i] = malloc (M_SIZE * sizeof (double )) ;

   // assign values from your ze[][] matrix 
   for(i=0; i<M_SIZE; i++) 
      for(j=0; j<M_SIZE; j++)
            zepointer[i][j] = ze[i][j];

   tqli(de,ee,M_SIZE,zepointer); // test

   // cleanup

   for(i=0; i<M_SIZE; i++)       // free memory allocated for row elements 
     free(zepointer[i]) ;

   free(zepointer);              // free memory for the row pointers      

   return 0;
}

Output:

 First method: array is { {6,7,8,9}, {1,6,1,5}, {6,2,2,4}, {1,2,3,4} } 
 z[0][0] = 6.000000 
 z[0][1] = 7.000000 
 z[0][2] = 8.000000 
 z[0][3] = 9.000000 

 z[1][0] = 1.000000 
 z[1][1] = 6.000000 
 z[1][2] = 1.000000 
 z[1][3] = 5.000000 

 z[2][0] = 6.000000 
 z[2][1] = 2.000000 
 z[2][2] = 2.000000 
 z[2][3] = 4.000000 

 z[3][0] = 1.000000 
 z[3][1] = 2.000000 
 z[3][2] = 3.000000 
 z[3][3] = 4.000000 

 Second method: array is { {1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1} } 
 z[0][0] = 1.000000 
 z[0][1] = 0.000000 
 z[0][2] = 0.000000 
 z[0][3] = 0.000000 

 z[1][0] = 0.000000 
 z[1][1] = 1.000000 
 z[1][2] = 0.000000 
 z[1][3] = 0.000000 

 z[2][0] = 0.000000 
 z[2][1] = 0.000000 
 z[2][2] = 1.000000 
 z[2][3] = 0.000000 

 z[3][0] = 0.000000 
 z[3][1] = 0.000000 
 z[3][2] = 0.000000 
 z[3][3] = 1.000000 
sg7
  • 6,108
  • 2
  • 32
  • 40
0

From the function's definition

void tqli(double d[], double e[], int n, double **z)

I conclude the function expects the 2 dimensions of double being passed as a "jagged" aka "scattered" array.

To create such a thing go for the following:

const size_t rows = 4;
const size_t columns = 4;

/* Allocate as many pointers to column's 1st element as we have rows. */
double ** z = malloc(rows * sizeof *z);

/* Loop over all rows (pointers to column's 1st element). */
for (size_t r = 0; r < rows; ++r)
{
  /* Allocate to each row (pointer to column's 1st element) as many doubles as we have columns. */
  z[r] = malloc(columns * sizeof *z[r]);
}


/* Assign value to z's elements. */
for (size_t r = 0; r < rows; ++r)
{
  for (size_t c = 0; c < columns; ++c)
  {
    z[r][c] = r * c;
  }
}

tqli(..., z);

/* Free the stuff, 
   by calling free() on every item we received from malloc().  */
for (size_t i = 0; i < rows; ++i)
{
  free(z[i]);
}

free(z);

Adding sane error checking is left to the reader.

alk
  • 69,737
  • 10
  • 105
  • 255