    // @(#)root/matrix:$Name:  $:$Id: TMatrixFLazy.cxx,v 1.5 2004/09/03 13:41:34 brun Exp $
    // Authors: Fons Rademakers, Eddy Offermann  Nov 2003

    /*************************************************************************
     * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
     * All rights reserved.                                                  *
     *                                                                       *
     * For the licensing terms see $ROOTSYS/LICENSE.                         *
     * For the list of contributors see $ROOTSYS/README/CREDITS.             *
     *************************************************************************/

    //////////////////////////////////////////////////////////////////////////
    //                                                                      //
    // Lazy Matrix classes.                                                 //
    //                                                                      //
    //   TMatrixFLazy                                                       //
    //   TMatrixFSymLazy                                                    //
    //   THaarMatrixF                                                       //
    //   THilbertMatrixF                                                    //
    //                                                                      //
    //////////////////////////////////////////////////////////////////////////

    #include "TMatrixF.h"
    #include "TMatrixFSym.h"
    #include "TMatrixFLazy.h"

    ClassImp(TMatrixFLazy)
    ClassImp(TMatrixFSymLazy)
    ClassImp(THaarMatrixF)
    ClassImp(THilbertMatrixF)

    //______________________________________________________________________________
    THaarMatrixF::THaarMatrixF(Int_t order,Int_t no_cols)
        : TMatrixFLazy(1<<order, no_cols == 0 ? 1<<order : no_cols)
    {
      Assert(order > 0 && no_cols >= 0);
    }

    //______________________________________________________________________________
    void MakeHaarMat(TMatrixF &m)
    {
      // Create an orthonormal (2^n)*(no_cols) Haar (sub)matrix, whose columns
      // are Haar functions. If no_cols is 0, create the complete matrix with
      // 2^n columns. Example, the complete Haar matrix of the second order is:
      // column 1: [ 1  1  1  1]/2
      // column 2: [ 1  1 -1 -1]/2
      // column 3: [ 1 -1  0  0]/sqrt(2)
      // column 4: [ 0  0  1 -1]/sqrt(2)
      // Matrix m is assumed to be zero originally.

      Assert(m.IsValid());
      const Int_t no_rows = m.GetNrows();
      const Int_t no_cols = m.GetNcols();
      Assert(no_rows >= no_cols && no_cols > 0);

      // It is easier to calculate a Haar matrix when the elements are stored
      // column-wise . Since we are row-wise, the transposed Haar is calculted

      TMatrixF mtr(no_cols,no_rows);
            Float_t *cp    = mtr.GetMatrixArray();
      const Float_t *m_end = mtr.GetMatrixArray()+no_rows*no_cols;

      Float_t norm_factor = 1/TMath::Sqrt((Float_t)no_rows);

      // First row is always 1 (up to normalization)
      Int_t j;
      for (j = 0; j < no_rows; j++)
        *cp++ = norm_factor;

      // The other functions are kind of steps: stretch of 1 followed by the
      // equally long stretch of -1. The functions can be grouped in families
      // according to their order (step size), differing only in the location
      // of the step
      Int_t step_length = no_rows/2;
      while (cp < m_end && step_length > 0) {
        for (Int_t step_position = 0; cp < m_end && step_position < no_rows;
               step_position += 2*step_length, cp += no_rows) {
          Float_t *ccp = cp+step_position;
          for (j = 0; j < step_length; j++)
            *ccp++ = norm_factor;
          for (j = 0; j < step_length; j++)
            *ccp++ = -norm_factor;
        }
        step_length /= 2;
        norm_factor *= TMath::Sqrt(2.0);
      }

      Assert(step_length != 0       || cp == m_end);
      Assert(no_rows     != no_cols || step_length == 0);

      m.Transpose(mtr);
    }

    //______________________________________________________________________________
    void THaarMatrixF::FillIn(TMatrixF &m) const
    {
      MakeHaarMat(m);
    }

    //______________________________________________________________________________
    THilbertMatrixF::THilbertMatrixF(Int_t no_rows,Int_t no_cols)
        : TMatrixFLazy(no_rows,no_cols)
    {
      Assert(no_rows > 0 && no_cols > 0);
    }

    //______________________________________________________________________________
    THilbertMatrixF::THilbertMatrixF(Int_t row_lwb,Int_t row_upb,Int_t col_lwb,Int_t col_upb)
        : TMatrixFLazy(row_lwb,row_upb,col_lwb,col_upb)
    {
      Assert(row_upb-row_lwb+1 > 0 && col_upb-col_lwb+1 > 0);
    }

    //______________________________________________________________________________
    void MakeHilbertMat(TMatrixF &m)
    {
      // Make a Hilbert matrix. Hilb[i,j] = 1/(i+j+1),
      // i,j=0...max-1 (matrix need not be a square one).

      Assert(m.IsValid());
      const Int_t no_rows = m.GetNrows();
      const Int_t no_cols = m.GetNcols();
      Assert(no_rows > 0 && no_cols > 0);

      Float_t *cp = m.GetMatrixArray();
      for (Int_t i = 0; i < no_rows; i++)
        for (Int_t j = 0; j < no_cols; j++)
          *cp++ = 1.0/(i+j+1.0);
    }

    //______________________________________________________________________________
    void THilbertMatrixF::FillIn(TMatrixF &m) const
    {
      MakeHilbertMat(m);
    }

    //______________________________________________________________________________
    THilbertMatrixFSym::THilbertMatrixFSym(Int_t no_rows)
        : TMatrixFSymLazy(no_rows)
    {
      Assert(no_rows > 0);
    }

    //______________________________________________________________________________
    THilbertMatrixFSym::THilbertMatrixFSym(Int_t row_lwb,Int_t row_upb)
        : TMatrixFSymLazy(row_lwb,row_upb)
    {
      Assert(row_upb-row_lwb+1 > 0);
    }

    //______________________________________________________________________________
    void MakeHilbertMat(TMatrixFSym &m)
    {
      // Make a Hilbert matrix. Hilb[i,j] = 1/(i+j+1),
      // i,j=0...max-1 (matrix must be square).

      Assert(m.IsValid());
      const Int_t no_rows = m.GetNrows();
      Assert(no_rows > 0);

      Float_t *cp = m.GetMatrixArray();
      for (Int_t i = 0; i < no_rows; i++)
        for (Int_t j = 0; j < no_rows; j++)
          *cp++ = 1.0/(i+j+1.0);
    }

    //______________________________________________________________________________
    void THilbertMatrixFSym::FillIn(TMatrixFSym &m) const
    {
      MakeHilbertMat(m);
    }