←to practical programming

Homework "eigenvalues (matrix diagonalization)"

Objective

Implement the Jacobi eigenvalue algorithm for matrix diagonalizaion (also called matrix eigenvalue decomposition or eigendecomposition).

Tasks

  1. (6 points) Jacobi diagonalization with cyclic sweeps
    1. Implement a function, timesJ, that multiplies the given matrix A and the Jacobi matrix J(p,q,θ) in O(n) operations, A←AJ. Something like

      void timesJ(matrix A, int p, int q, double theta){
      	double c=cos(theta),s=sin(theta);
      	for(int i=0;i<A.size1;i++){
      		double aip=A[i,p],aiq=A[i,q];
      		A[i,p]=c*aip-s*aiq;
      		A[i,q]=s*aip+c*aiq;
      		}
      }
      
    2. Implement a function, Jtimes, that multiplies the Jacobi matrix J(p,q,θ) and the given matrix A in O(n) operations, A←JA. Something like

      void timesJ(matrix A, int p, int q, double theta){
      	double c=cos(theta),s=sin(theta);
      	for(int j=0;j<A.size1;j++){
      		double apj=A[p,j],aqj=A[q,j];
      		A[p,j]= c*apj+s*aqj;
      		A[q,j]=-s*apj+c*aqj;
      		}
      }
      
    3. Make a function, say jacobi.cyclic, that implements the Jacobi eigenvalue algorithm for real symmetric matrices using the cyclic sweeps: eliminates the off-diagonal elements in a predefined sequence which spans all off-diagonal elements, for example row after row, and repeats the sweeps until converged. The convergence criterion could be that the eigenvalues did not change after a whole sweep. Something like

      bool changed;
      do{
      	changed=false;
      	for(int p=0;p<n-1;p++)
      	for(int q=p+1;q<n;q++){
      		double apq=matrix.get(A,p,q);
      		double app=matrix.get(A,p,p);
      		double aqq=matrix.get(A,q,q);
      		double theta=0.5*atan2(2*apq,aqq-app);
      		double c=cos(theta),s=sin(theta);
      		double new_app=c*c*app-2*s*c*apq+s*s*aqq;
      		double new_aqq=s*s*app+2*s*c*apq+c*c*aqq;
      		if(new_app!=app || new_aqq!=aqq) // do rotation
      			{
      			changed=true;
      			timesJ(A,p,q, theta);
      			Jtimes(A,p,q,-theta); // A←J^T*A*J 
      			timesJ(V,p,q, theta); // V←V*J
      			}
      	}
      }while(changed);
      

      Prove that your implementation works as intended: generate a random symmetric matrix A, apply your routine to perform the eigenvalue-decomposition, A=VDVT (where V is the orthogonal matrix of eigenvectors and D is the diagonal matrix with the corresponding eigenvalues), and check that VTAV==D, VDVT==A, VTV==1, VVT==1,

  2. (3 points) Hydrogen atom: s-wave radial Schrödinger equation

    The s-wave radial Schrödinger equation for the Hydrogen atom reads (in units "Bohr radius" and "Hartree"),

    -(1/2)f'' -(1/r)f = εf ,

    where f(r) is the reduced radial wave-function, f(r)=r*R(r), ε is the energy, and primes denote the derivative over r.

    The bound s-state wave-function satisfies this equation and the two boundary conditions,

    f(r → 0) = r-r², (prove this)
    f(r → ∞) = 0 .

    These two boundary conditions can only be satisfied for certain discrete (negative) values of the energy.

    Since one cannot integrate numerically to ∞ one substitutes ∞ with a reasonably large number, rmax, such that it is much larger than the typical size of the hydrogen atom but still managable for the numerical inregrator (say, rmax = 10 Bohr radii for the ground state),

    f(∞)=0 → f(rmax)=0 .
    

    Numerically one can represent this problem on an equidistant N-point grid with step Δr,

    ri = rmax i Δr , Δr = rmax/(N+1) , i = 1...N ,

    where the wave-function is represented by a vector fi = f(ri), and where the second derivative operation in the Hamiltonian can then be approximated using the three point finite difference formula,

    f''i = (fi-1-2fi+fi+1)/Δr² .

    Now the Schrödinger equation becomes a matrix eigenvalue equation,

    j=1..N-1 Hij fj = εfi , i=1...N ,

    or, in matrix notation,

    H f = ε f ,

    where the Hamiltonian matrix H=K+V is given as

                ( -2   1   0   0  ...  0  )
                (  1  -2   1   0  ...  0  )
                (  0   1  -2   1  ...  0  )
    K = - 1/2Δr² ( ... ... ... ... ... ... )
                (  0  ...  0   1  -2   1  )
                (  0  ...  0   0   1  -2  )
    
                ( -1/r1   0   0   0    ...   0   )
                (   0  -1/r2  0   0    ...   0   )
                (   0    0  -1/r3 0    ...   0   )
    V =         (  ...  ...  ... ...   ...  ...  )
                (   0   ...   0   0  -1/rN-2  0   )
                (   0   ...   0   0    0  -1/rN-1 )
    
    Notice that the boundary condition f(0)=0, f(rmax)=0 is in-built in the K-matrix (and the V-matrix): indeed the (ommited) components u0 and uN+1 have been assumed to be zero. Thus the zero-boundary conditions are in-built in the formulation of the matrix problem.

    Solving the matrix eigenvalue equation amounts to matrix diagonalization. If you give the matrix H to your diagonalization routine it will return a vector e with eigenvalues and a matrix V whith the corresponding eigenvectors as columns, such that

    j HijVjk = ek Vik .

    Now calculate numerically (using your diagonalization routine) the lowest egenvalues and eigenfunctions of the s-wave hydrogen atom and compare with the exact results.

    Build the Hamiltonian matrix

    double rmax=10,dr=0.3;
    int npoints = (int)(rmax/dr)-1;
    vector r = new vector(npoints);
    for(int i=0;i<npoints;i++)r[i]=dr*(i+1);
    matrix H = new matrix(npoints,npoints);
    for(int i=0;i<npoints-1;i++){
      matrix.set(H,i,i,-2);
      matrix.set(H,i,i+1,1);
      matrix.set(H,i+1,i,1);
      }
    matrix.set(H,npoints-1,npoints-1,-2);
    H*=-0.5/dr/dr;
    for(int i=0;i<npoints;i++)H[i,i]+=-1/r[i];
    

    Diagonalize the matrix using your Jacobi routine.

    Investigate convergence of your energies with respect to rmax and dr.

    Plot the several lowest eigenfunctions and compare with the analytical result.

  3. (1 point) Scaling and optimization

    1. Check that the number of operations for matrix diagonalization scales as O(n³) (by measuring the time it takes to diagonalize a random matrix of size n).
    2. Optimize your diagonalization routine: when rotating matrix A update only the upper-right triangle of your symmetric matrix (see the corresponding formula in the lecture note). Compare the speed with the non-optimized version.
    3. Illustrate your results with a plot.