简体   繁体   中英

Array not changing after being passed through void function

I've written a program in C to compute the SVD of a matrix, using Jacobi's algorithm. I've got 3 functions in the program: a function called jacobi_helper which will perform the SVD, a function called jacobi which calls jacobi_helper after initializing a few arrays, and the main function which calls jacobi.

My problem lies in the fact that the SVD seems to be performed correctly while in jacobi_helper but those values don't seem to return to jacobi even though they are passed in a void function. In the end I'm trying to print the matrices U and V of an SVD and the vector of singular values, and my confusion arises from the fact that the vector of singular values is able to print well but the matrices are not.

Here is my code:

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

    double dot_product(double *a, double *b, int n){
        double sum = 0;
        for(int i = 0; i < n; i++){
            sum = sum + a[i]*b[i];
        }
        return sum;
    }

    //Right matrix must be transpose of the matrix you want to multiply
    void matrix_multiplication(left, right, output, n)
    int n;
    double left[n][n];
    double right[n][n];
    double output[n][n];
    {
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                output[i][j] = dot_product(left[i], right[j], n);
            }
        }
    }

    void transpose(a, n, a_transpose)
    int n;
    double a[n][n];
    double a_transpose[n][n];
    {

        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                a_transpose[i][j] = a[j][i];
            }
        }
    }


    void jacobi_helper(a, n, givens, givens_transpose, s, s_matrix, u, temp_u, u_output, v, temp_v, v_output)
    int n; //Dimension of Matrix
    double a[n][n]; //Input Matrix
    double givens[n][n]; //Givens matrix to be formed in each step
    double givens_transpose[n][n]; //Transpose of Givens Matrix
    double s[n]; //Vector of singular values
    double s_matrix[n][n]; //Matrix containing the singular values.
    double u[n][n]; //U Matrix in SVD. (A = USV)
    double temp_u[n][n]; //Temporary Matrix
    double u_output[n][n];
    double v[n][n];
    double temp_v[n][n];
    double v_output[n][n];
    {
        u = a;


        //Set V to Identity Matrix
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                if(i == j){
                    v[i][j] = 1;
                }
                else{
                    v[i][j] = 0;
                }
            }
        }

        double n_squared = 0;
        double value = 0;
        double epsilon = 0.1;

        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                n_squared = n_squared + (u[i][j]*u[i][j]);
            }
        }

        do{
            value = 0;
            for(int i = 0; i < (n-1); i++){
                for(int j = (i+1); j < n; j++){

                    double tmp1 = 0, tmp2 = 0, tmp4 = 0;
                    for(int k = 0; k < n; k++){
                        tmp1 = tmp1 + (u[k][i]*u[k][i]);
                        tmp2 = tmp2 + (u[k][i]*u[k][j]);
                        tmp4 = tmp4 + (u[k][j]*u[k][j]);
                    }

                    double tau = (tmp4 - tmp1)/(2*tmp2);

                    double t;
                    double t1;
                    double t2;

                    t1 = -tau + sqrt(1 + (tau*tau));
                    t2 = -tau - sqrt(1 + (tau*tau));

                    if(fabs(t1) < fabs(t2)){
                        t = t1;
                    }else{
                        t = t2;
                    }

                    double cos = 1/(sqrt(1+(t*t)));
                    double sin = cos*t;


                    //Make Givens Matrix
                    for(int k = 0; k < n; k++){
                        for(int l = 0; l < n; l++){
                            if(k == i && l == i){
                                givens[k][l] = cos;
                            }
                            else if (k == j && l == j){
                                givens[k][l] = cos;
                            }
                            else if ((k == i && l == j) && i < j){
                                givens[k][l] = -sin;
                            }
                            else if ((k == i && l == j) && i > j){
                                givens[k][l] = sin;
                            }
                            else if ((k == j && l == i) && i < j){
                                givens[k][l] = sin;
                            }
                            else if ((k == j && l == i) && i > j){
                                givens[k][l] = -sin;
                            }
                            else if(k == l){
                                givens[k][l] = 1;
                            }
                            else{
                                givens[k][l] = 0;
                            }
                        }
                    }


                    //Set U <- U*Givens
                    matrix_multiplication(u, givens, temp_u, n);
                    u = temp_u;

                    //Set V <- V*Givens
                    matrix_multiplication(v, givens, temp_v, n);
                    v = temp_v;

                    double temp = 0;
                    for(int k = 0; k < n; k++){
                        temp = temp + (u[k][i]*u[k][j]);
                    }
                    value = value + temp*temp;
                }
            }

        }while(sqrt(value) >= (epsilon*epsilon)*(n_squared));

        for(int i = 0; i < n; i++){
            double sing_value = 0;
            for(int k = 0; k < n; k++){
                sing_value = sing_value + (u[k][i]*u[k][i]);
            }
            s[i] = sqrt(sing_value);
            s_matrix[i][i] = 1/sqrt(sing_value);
        }

        matrix_multiplication(u, s_matrix, temp_u, n);
        u = temp_u;

        printf("%.16f  %.16f  %.16f  %.16f\n",u[0][0],u[0][1],u[1][0],u[1][1]);
        printf("%.16f  %.16f  %.16f  %.16f\n",v[0][0],v[0][1],v[1][0],v[1][1]);
        printf("%.16f  %.16f\n\n", s[0], s[1]);
    }


    void jacobi(double *a, int n, double *s, double *u, double *v){
        static double s_matrix[5000000];
        static double givens[5000000];
        static double givens_transpose[5000000];
        static double temp_u[5000000];
        static double temp_v[5000000];
        static double u_output[5000000];
        static double v_output[5000000];


        jacobi_helper(a, n, givens, givens_transpose, s, s_matrix, u, temp_u, u_output, v, temp_v, v_output);
    }

    int main(int argc, const char * argv[]) {
        static double a[4] = {2,2,-1,1};
        int n = 2;
        static double s[2];
        static double u[4];
        static double v[4];


        jacobi(a, n, s, u, v);
        printf("%.16f  %.16f  %.16f  %.16f\n",u[0],u[1],u[2],u[3]);
        printf("%.16f  %.16f  %.16f  %.16f\n",v[0],v[1],v[2],v[3]);
        printf("%.16f  %.16f\n", s[0], s[1]);
        return 0;
    }

So the problem is that when I have the printf statements at the end, s[0] and s[1] are the same in both cases, but u[0] to u[3] and v[0] to v[3] are not the same.

From the print statement inside the jacobi_helper function I get (the correct values of):

    u = 1.0000000000000000  0.0000000000000000  0.0000000000000000  1.0000000000000000
    v = 0.7071067811865475  -0.7071067811865475  0.7071067811865475  0.7071067811865475
    s = 2.8284271247461898  1.4142135623730949

But from the main function I get:

    u = 0.0000000000000000  0.0000000000000000  0.0000000000000000  0.0000000000000000
    v = 1.0000000000000000  0.0000000000000000  0.0000000000000000  1.0000000000000000
    s = 2.8284271247461898  1.4142135623730949

Can anyone help with this? In case this is useful, the algorithm I was using was Algorithm 6 from this website: http://www.cs.utexas.edu/users/inderjit/public_papers/HLA_SVD.pdf

jacobi_helper is called with the argument double *u , which is a pointer to a memory address where the results may be stored, but the first thing jacobi_helper does is u = a which means: forget that memory address u and use a instead. You set some values in the array pointed to be the argument v , but later you carry on with v = temp_v .

An array variable is only a pointer to a memory address, assigning a value to that array variable will replace that memory address by another address. If you want to change the memory pointed to by the array variable, you have do dereference the address.

The code

u[0] = 123;
u[1] = 345;
u[2] = 678;

changes the data hold by the memory pointed to by u. On the other hand,

u = a;

will just change u, and all subsequent access to u[0] will in fact access the same memory as a[0] .

Also the type of the argument double *u and the parameter double u[n][n] do not match.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM