public inbox for gsl-discuss@sourceware.org
 help / color / mirror / Atom feed
* gsl_linalg_complex_householder_transform
@ 2003-05-26 13:04 Mario Pernici
  2003-05-28 14:56 ` gsl_linalg_complex_householder_transform Brian Gough
  0 siblings, 1 reply; 5+ messages in thread
From: Mario Pernici @ 2003-05-26 13:04 UTC (permalink / raw)
  To: gsl-discuss

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1824 bytes --]


Dear Sirs,
 it seems that  gsl_linalg_complex_householder_transform
 does not follow Golub and Van Loan; is it done
 on purpose or there is a bug?

 Below I present the problem;
 in an attached files I give a modification of the
 code for gsl_linalg_complex_householder_transform
 according to Golub and Van Loan, the function
 gsl_linalg_complex_householder_hv
 and an example. Using the modified code for
 gsl_linalg_complex_householder_transform the example gives the
 expected results (es.1.out); the original code gives results
 not according to Golub and Van Loan (es.2.out).
 Best regards
   Mario

Problem:
 In the function
 double gsl_linalg_householder_transform(gsl_vector * v)
 there is a rescaling
  gsl_blas_dscal (1.0 / (alpha - beta), &x.vector);
 such that the first component of the householder vector is rescaled
 from (alpha - beta) to 1 (and then it is replaced by the norm).

 However this does not happen in
 gsl_complex
 gsl_linalg_complex_householder_transform (gsl_vector_complex * v).
 According to Golub and Van Loan, Problem P5.1.3, (their notation)
 householder matrix:
 P = 1 - beta u u^H
 P x = -e^{i theta} ||x||_2 * e_1
 householder vector:
 u = (x + e^{i theta} ||x||_2 * e_1 * s
 where x(1) = |x(1)| * e^{i theta}
 and where I added the scaling factor s, chosen to be
 s = 1/(x(1) + e^{i theta} ||x||_2) to set first component of the
 householder vector u(1) = 1.
 In the notation of linalg/householdercomplex.c the rescaling factor is
 s = 1/(alpha - e^{i theta} * beta_r);
 beta = (||x||_2 + |x(1)|)/||x||_2  becomes, in gsl notation,
 tau = (beta_r - |alpha|)/beta_r; notice that it is real (but I used
 a gsl_complex for it, not to change notation).

 In the gsl code the scaling factor is
 s = 1/(alpha - beta_r)
 so that u(1) is not rescaled to 1 when alpha = x(1) is not real.




[-- Attachment #2: Type: APPLICATION/x-gzip, Size: 1765 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: gsl_linalg_complex_householder_transform
  2003-05-26 13:04 gsl_linalg_complex_householder_transform Mario Pernici
@ 2003-05-28 14:56 ` Brian Gough
  0 siblings, 0 replies; 5+ messages in thread
From: Brian Gough @ 2003-05-28 14:56 UTC (permalink / raw)
  To: Mario Pernici; +Cc: gsl-discuss

Mario Pernici writes:
 > 
 > Dear Sirs,
 >  it seems that  gsl_linalg_complex_householder_transform
 >  does not follow Golub and Van Loan; is it done
 >  on purpose or there is a bug?

Hi,

I think I used the LAPACK method described in Lapack Working Note 72
"The Computation of Elementary Matrices", as it is supposed to have
better properties than the one in Golub and Van Loan.

I don't remember the details now -- I should have put some comments in
the code.

I will take another look at it to make sure it is ok.  Thanks for the
bug reports, keep them coming.

-- 
Brian

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: gsl_linalg_complex_householder_transform
  2003-05-29 20:40 gsl_linalg_complex_householder_transform Mario Pernici
@ 2003-05-30 14:40 ` Brian Gough
  0 siblings, 0 replies; 5+ messages in thread
From: Brian Gough @ 2003-05-30 14:40 UTC (permalink / raw)
  To: Mario Pernici; +Cc: gsl-discuss

Mario Pernici writes:
 >  Now my examples for the functions in the section Tridiagonal
 >  Decomposition of Hermitian Matrices work without modifications of
 >  the code of gsl.  The key point is that gsl_complex
 >  gsl_linalg_complex_householder_transform (gsl_vector_complex * v)
 >  returns a complex number tau such that (I - tau^* v v^H) x = -/+
 >  ||x|| e_1 (see Working Note 72) while I thought the relation was
 >  (I - tau v v^H) x = -/+ ||x|| e_1 Maybe this should be added in
 >  the comments to the source code of this function.

Yes, I should have commented it before... I've added some comments
now, and the function gsl_linalg_complex_householder_hv.

Brian


^ permalink raw reply	[flat|nested] 5+ messages in thread

* gsl_linalg_complex_householder_transform
@ 2003-05-29 20:40 Mario Pernici
  2003-05-30 14:40 ` gsl_linalg_complex_householder_transform Brian Gough
  0 siblings, 1 reply; 5+ messages in thread
From: Mario Pernici @ 2003-05-29 20:40 UTC (permalink / raw)
  To: gsl-discuss


Hi Brian,
< I think I used the LAPACK method described in Lapack Working Note 72

 thank you for the reference!
 Now my examples for the functions in the section
 Tridiagonal Decomposition of Hermitian Matrices
 work without modifications of the code of gsl.
 The key point is that
 gsl_complex
 gsl_linalg_complex_householder_transform (gsl_vector_complex * v)
 returns a complex number tau such that
 (I - tau^* v v^H) x = -/+ ||x|| e_1
 (see Working Note 72)
 while I thought the relation was (I - tau v v^H) x = -/+ ||x|| e_1
 Maybe this should be added in the comments to the source code of
 this function.

 And you could add to householdercomplex.c the function
gsl_linalg_complex_householder_hv in analogy with householder.c .
======================
int
gsl_linalg_complex_householder_hv(gsl_complex tau, const 
gsl_vector_complex * v, gsl_vector_complex *  w)
{
  size_t i;
  gsl_complex z;

  if (GSL_REAL(tau) == 0.0 && GSL_IMAG(tau) == 0.0)
      return GSL_SUCCESS;

  /* z = v^H w */
  gsl_blas_zdotc(v, w, &z);

  /* w = w - tau * (v^H w) * v   */
  z = gsl_complex_mul(z, tau);
  for (i = 0; i < v->size; i++)
  {
     gsl_complex vi, wi;
         vi = gsl_vector_complex_get(v,i);
         wi = gsl_vector_complex_get(w,i);
         vi = gsl_complex_mul(vi, z);
         wi = gsl_complex_sub(wi, vi);
         gsl_vector_complex_set(w, i, wi);
   }

}

=============================
Bye
 Mario





^ permalink raw reply	[flat|nested] 5+ messages in thread

* gsl_linalg_complex_householder_transform
@ 2003-05-27  8:18 Mario Pernici
  0 siblings, 0 replies; 5+ messages in thread
From: Mario Pernici @ 2003-05-27  8:18 UTC (permalink / raw)
  To: gsl-discuss

[-- Attachment #1: Type: TEXT/PLAIN, Size: 2868 bytes --]


Dear Sirs,
 it seems that the modification of 
gsl_linalg_complex_householder_transform
 works fine; here I give a similar correction in gsl_linalg_hermtd_decomp.

 As in the previous mail,
 householder matrix:
 P = 1 - beta u u^H
 P x = -e^{i theta} ||x||_2 * e_1

 so that in gsl_linalg_hermtd_decomp
 the phase e^{i theta} must be taken into account when setting
 gsl_vector_complex_set (&v.vector, 0, ei);
 see attached file.

-------------------
 In the manual there are misprints:
 Tridiagonal Decomposition of Hermitian Matrices
A hermitian matrix A can be factorized by similarity transformations
 into the form,
 A = U T U^T
(becomes A = U T U^H)
 where U is an unitary matrix and T is a real symmetric tridiagonal 
matrix.
 ( T is a hermitian tridiagonal matrix).
---------------------

 Below I give an example in ruby-gsl; comments are added, so it should
 be understandable without running it.

require 'assert'
require "GSL"; include GSL; include GSL::Math
require 'gsl_matrix'; require 'gsl_linalg'

# complex numbers 0 and 1
zero = Complex.new2(0,0)
one = Complex.new2(1,0)

# initialize a 4x4 hermitian matrix
a = Matrix_complex.new([2,0,  3,2, 4,1, 5,2],
                       [3,-2, 2,0, 8,1, 4,4],
                       [4,-1, 8,-1,3,0, 3,2],
                       [5,-2, 4,-4,3,-2, 1,0])

# check that it is hermitian
assert a == a.h
# get the output matrix a1 and the vector tau using hermtd_decomp
a1, tau = a.hermtd_decomp

# In the lower part of a1 are stored the elements of the tridiagonal
# matrix and the householder vectors
#
#       [t             ]
#  a1 = [t    t        ]
#       [v_0  t   t    ]
#       [v_0  v_1 t  t ]

# householder vectors
v_0 = Vector_complex.new2(zero, one, a1.get(2,0),a1.get(3,0))
v_1 = Vector_complex.new2(zero,zero,one,a1.get(3,1))

# householder matrices h_i = I - tau_i v_i v_i^H
# where tau_i = 2/(v_i^H v_i)
h_0 = v_0.house
h_1 = v_1.house
# Q
q = h_0 * h_1
# Q is unitary
assert q * q.h =~ Matrix_complex.identity(4)

# Get the tridiagonal matrix t1 out of a1
# first put to zero the elements in the lower part where are stored
# the householder vectors
a1[2,0] = zero; a1[3,0] = zero; a1[3,1] = zero

# get the full hermitian tridiagonal matrix from its lower part
t1 = a1.lower(true) + a1.lower(false).h

# t1 = Q^H * a * Q within precision 1.0e-14
assert t1 =~ [q.h * a * q, 1.0e-14]
p t1
#[ (2, 0)  (-6.3911, -4.26073)  (0, 0)  (0, 0)
#   (-6.3911, 4.26073)  (9.89831, 0)  (-5.12537, -5.45784)  (0, 0)
#   (0, 0)  (-5.12537, 5.45784)  (-0.50685, 0)  (1.10104, -2.20513)
#    (0, 0)  (0, 0)  (1.10104, 2.20513)  (-3.39146, 0)  ]

# check that tau is related to the norms of the householder vectors
n0 = v_0.dznrm2
n1 = v_1.dznrm2
assert float_equal(2/(n0**2),tau[0].real, 1.0e-15)
assert float_equal(2/(n1**2),tau[1].real, 1.0e-15)
p tau
#[(1.4694, 0)  (0.632016, 0)  (-1.54304, 0.69892)  ]




[-- Attachment #2: Type: TEXT/PLAIN, Size: 2654 bytes --]

/* in linalg/hermtd.c */

int 
gsl_linalg_hermtd_decomp (gsl_matrix_complex * A, gsl_vector_complex * tau)  
{
  if (A->size1 != A->size2)
    {
      GSL_ERROR ("hermitian tridiagonal decomposition requires square matrix",
                 GSL_ENOTSQR);
    }
  else if (tau->size + 1 != A->size1)
    {
      GSL_ERROR ("size of tau must be (matrix size - 1)", GSL_EBADLEN);
    }
  else
    {
      const size_t N = A->size1;
      size_t i;
  
      const gsl_complex zero = gsl_complex_rect (0.0, 0.0);
      const gsl_complex one = gsl_complex_rect (1.0, 0.0);
      const gsl_complex neg_one = gsl_complex_rect (-1.0, 0.0);

      for (i = 0 ; i < N - 2; i++)
        {
          gsl_vector_complex_view c = gsl_matrix_complex_column (A, i);
          gsl_vector_complex_view v = gsl_vector_complex_subvector (&c.vector, i + 1, N - (i + 1));
          gsl_complex c0 = gsl_vector_complex_get(&c.vector, i+1);
          gsl_complex tau_i = gsl_linalg_complex_householder_transform (&v.vector);
	  /* get the phase of the first element */
	  c0 = gsl_complex_div_real(c0, gsl_complex_abs(c0));
          /* Apply the transformation H^T A H to the remaining columns */

          if ( !(GSL_REAL(tau_i) == 0.0 && GSL_IMAG(tau_i) == 0.0)) 
            {
              gsl_matrix_complex_view m = 
                gsl_matrix_complex_submatrix (A, i + 1, i + 1, 
                                              N - (i+1), N - (i+1));
              gsl_complex ei = gsl_vector_complex_get(&v.vector, 0);
              gsl_vector_complex_view x = gsl_vector_complex_subvector (tau, i, N-(i+1));
              gsl_vector_complex_set (&v.vector, 0, one);
              
              /* x = tau * A * v */
              gsl_blas_zhemv (CblasLower, tau_i, &m.matrix, &v.vector, zero, &x.vector);

              /* w = x - (1/2) tau * (x' * v) * v  */
              {
                gsl_complex xv, txv, alpha;
                gsl_blas_zdotc(&x.vector, &v.vector, &xv);
                txv = gsl_complex_mul(tau_i, xv);
                alpha = gsl_complex_mul_real(txv, -0.5);
                gsl_blas_zaxpy(alpha, &v.vector, &x.vector);
              }
              
              /* apply the transformation A = A - v w' - w v' */
              gsl_blas_zher2(CblasLower, neg_one, &v.vector, &x.vector, &m.matrix);

              /* multiply ei by the phase */
	      ei = gsl_complex_mul(ei, c0);
              gsl_vector_complex_set (&v.vector, 0, ei);
            }
          
          gsl_vector_complex_set (tau, i, tau_i);
        }
      
      return GSL_SUCCESS;
    }
}  




^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2003-05-30 14:40 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-05-26 13:04 gsl_linalg_complex_householder_transform Mario Pernici
2003-05-28 14:56 ` gsl_linalg_complex_householder_transform Brian Gough
2003-05-27  8:18 gsl_linalg_complex_householder_transform Mario Pernici
2003-05-29 20:40 gsl_linalg_complex_householder_transform Mario Pernici
2003-05-30 14:40 ` gsl_linalg_complex_householder_transform Brian Gough

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).