// -*-C++-*- 

// Copyright (C) 2004 
// Christian Stimming <stimming@tuhh.de>

// Row-order modifications by Jacob (Jack) Gryn <jgryn at cs dot yorku dot ca>

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2, or (at
// your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public License along
// with this library; see the file COPYING.  If not, write to the Free
// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.

/** @file 
 * @brief General Dense Rectangular Matrix Class with float elements
 */

//      LAPACK++ (V. 1.1)
//      (C) 1992-1996 All Rights Reserved.
//
//      Lapack++ Rectangular Matrix Class
//
//      Dense (nonsingular) matrix, assumes no special structure or properties.
//
//      ) allows 2-d indexing
//      ) non-unit strides
//      ) deep (copy) assignment
//      ) std::cout << A.info()  prints out internal states of A
//      ) indexing via A(i,j) where i,j are either integers or
//              LaIndex         

#ifndef _LA_GEN_MAT_FLOAT_H_
#define _LA_GEN_MAT_FLOAT_H_

#include "arch.h"
#include "lafnames.h"
#include VECTOR_FLOAT_H
#include LA_INDEX_H

class LaGenMatComplex;
class LaGenMatDouble;
class LaGenMatFloat;
class LaGenMatInt;
class LaGenMatLongInt;


class DLLIMPORT LaGenMatFloat
{
   public:
      /** The type of the value elements. */
      typedef float value_type;
      /** Convenience typedef of this class to itself to make
       * common function definitions easier. (New in
       * lapackpp-2.4.5) */
      typedef LaGenMatFloat matrix_type;
      /** Internal wrapper type; don't use that in an
       * application. */
      typedef VectorFloat vec_type;
   private:
    vec_type     v;
    LaIndex         ii[2];
    int             dim[2];  // size of original matrix, not submatrix
    int             sz[2];   // size of this submatrix
    void init(int m, int n);
    static int  debug_; // trace all entry and exits into methods and 
                        // operators of this class.  This variable is
                        // explicitly initalized in lagenmatfloat.cc

    static int      *info_;   // print matrix info only, not values
                             //   originally 0, set to 1, and then
                             //   reset to 0 after use.
                // use as in
                //
                //    std::cout << B.info() << std::endl;
                //
                // this *info_ member is unique in that it really isn't
                // part of the matrix info, just a flag as to how
                // to print it.   We've included in this beta release
                // as part of our testing, but we do not expect it 
                // to be user accessable.
                // It has to be declared as global static
                // so that we may monitor expresssions like
                // X::(const &X) and still utilize without violating
                // the "const" condition.
                // Because this *info_ is used at most one at a time,
                // there is no harm in keeping only one copy of it,
                // also, we do not need to malloc free space every time
                // we call a matrix constructor.


    int shallow_; // set flag to '0' in order to return matrices
                    // by value from functions without unecessary
                    // copying.


    // users shouldn't be able to modify assignment semantics..
    //
    //LaGenMatFloat& shallow_assign();

public:



        /*::::::::::::::::::::::::::*/

        /* Constructors/Destructors */

        /*::::::::::::::::::::::::::*/


        LaGenMatFloat();
        LaGenMatFloat(int, int);

	/** Constructs an \f$m\times n\f$ matrix by using the values
	 * from the one-dimensional C array \c v of length \c m*n. 
	 *
	 * \note If \c row_ordering is \c false, then the data will \e
	 * not be copied but instead the C array will be shared
	 * (shallow copy). In that case, you must not delete the C
	 * array as long as you use this newly created matrix. Also,
	 * if you need a copy (deep copy), construct one matrix \c A
	 * by this constructor, and then copy this content into a
	 * second matrix by \c B.copy(A). On the other hand, if \c
	 * row_ordering is \c true, then the data will be copied
	 * immediately (deep copy).
	 *
	 * \param v The one-dimensional C array of size \c m*n whose
	 * data should be used. If \c row_ordering is \c false, then
	 * the data will \e not be copied but shared (shallow
	 * copy). If \c row_ordering is \c true, then the data will be
	 * copied (deep copy).
	 *
	 * \param m The number of rows in the new matrix.
	 *
	 * \param n The number of columns in the new matrix.
	 *
	 * \param row_ordering If \c false, then the C array is used
	 * in column-order, i.e. the first \c m elements of \c v are
	 * used as the first column of the matrix, the next \c m
	 * elements are the second column and so on. (This is the
	 * default and this is also the internal storage format in
	 * order to be compatible with the underlying Fortran
	 * subroutines.) If this is \c true, then the C array is used
	 * in row-order, i.e. the first \c n elements of \c v are used
	 * as the first row of the matrix, the next \c n elements are
	 * the second row and so on. (Internally, this is achieved by
	 * allocating a new copy of the array and copying the array
	 * into the internal ordering.)
	 */
        LaGenMatFloat(float* v, int m, int n, bool row_ordering=false);

      /** Create a new matrix from an existing one by copying.
       *
       * Watch out! Due to the C++ "named return value optimization"
       * you cannot use this as an alias for copy() when declaring a
       * variable if the right-side is a return value of
       * operator(). More precisely, you cannot write the following:
       * \verbatim
       LaGenMatFloat x( y(LaIndex(),LaIndex()) ); // erroneous reference copy!
       \endverbatim
       *
       * Instead, if the initialization should create a new copy of
       * the right-side matrix, you have to write it this way:
       * \verbatim
       LaGenMatFloat x( y(LaIndex(),LaIndex()).copy() ); // correct deep-copy
       \endverbatim
       *
       * Or this way:
       * \verbatim
       LaGenMatFloat x;
       x = y(LaIndex(),LaIndex()); // correct deep-copy
       \endverbatim
       */
        LaGenMatFloat(const LaGenMatFloat&);
    virtual ~LaGenMatFloat();


      /** @name Information Predicates */
      //@{
      /** Returns true if this is an all-zero matrix. (New in
       * lapackpp-2.4.5) */
      bool is_zero() const;

      /** Returns true if this matrix is only a submatrix view of
       * another (larger) matrix. (New in lapackpp-2.4.4) */
      bool is_submatrixview() const
      { return size(0) != gdim(0) || size(1) != gdim(1); };

      /** Returns true if this matrix has unit stride. 
       *
       * This is a necessary condition for not being a submatrix
       * view, but it's not sufficient. (New in lapackpp-2.4.4) */
      bool has_unitstride() const
      { return inc(0) == 1 && inc(1) == 1; };

      /** Returns true if the given matrix \c mat is exactly equal
       * to this object. (New in lapackpp-2.4.5) */
      bool equal_to(const matrix_type& mat) const;
      //@}


        /*::::::::::::::::::::::::::::::::*/

        /*  Indices and access operations */

        /*::::::::::::::::::::::::::::::::*/

    inline int size(int d) const;   // submatrix size
      /** Returns the number of columns, i.e. for a M x N matrix
       * this returns N. New in lapackpp-2.4.4. */
      inline int cols() const { return size(1); }
      /** Returns the number of rows, i.e. for a M x N matrix this
       * returns M. New in lapackpp-2.4.4. */
      inline int rows() const { return size(0); }
    inline int inc(int d) const;    // explicit increment
    inline int gdim(int d) const;   // global dimensions
    inline int start(int d) const;  // return ii[d].start()
    inline int end(int d) const;    // return ii[d].end()
    inline LaIndex index(int d) const;// index
    inline int ref_count() const;
    inline LaGenMatFloat& shallow_assign();
    inline float* addr() const;       // begining addr of data space
    
    inline float& operator()(int i, int j);
    inline float& operator()(int i, int j) const;
    LaGenMatFloat operator()(const LaIndex& I, const LaIndex& J) ;
    LaGenMatFloat operator()(const LaIndex& I, const LaIndex& J) const;
      /** Returns a submatrix view for the specified row \c k of
       * this matrix.
       *
       * The returned object references still the same memory as
       * this object, so if you modify elements, they will appear
       * modified in both objects.  (New in lapackpp-2.4.6) */
      LaGenMatFloat row(int k);
      /** Returns a submatrix view for the specified row \c k of
       * this matrix.
       *
       * The returned object references still the same memory as
       * this object, so if you modify elements, they will appear
       * modified in both objects.  (New in lapackpp-2.4.6) */
      LaGenMatFloat row(int k) const;
      /** Returns a submatrix view for the specified column \c k
       * of this matrix.
       *
       * The returned object references still the same memory as
       * this object, so if you modify elements, they will appear
       * modified in both objects.  (New in lapackpp-2.4.6) */
      LaGenMatFloat col(int k);
      /** Returns a submatrix view for the specified column \c k
       * of this matrix.
       *
       * The returned object references still the same memory as
       * this object, so if you modify elements, they will appear
       * modified in both objects.  (New in lapackpp-2.4.6) */
      LaGenMatFloat col(int k) const;

            LaGenMatFloat& operator=(float s);
      /** Release left-hand side (reclaiming memory space if
       * possible) and copy elements of elements of \c s. Unline \c
       * inject(), it does not require conformity, and previous
       * references of left-hand side are unaffected. 
       *
       * This is an alias for copy().
       *
       * Watch out! Due to the C++ "named return value optimization"
       * you cannot use this as an alias for copy() when declaring a
       * variable if the right-side is a return value of
       * operator(). More precisely, you cannot write the following:
       * \verbatim
       LaGenMatFloat x = y(LaIndex(),LaIndex()); // erroneous reference copy!
       \endverbatim
       *
       * Instead, if the initialization should create a new copy of
       * the right-side matrix, you have to write it this way:
       * \verbatim
       LaGenMatFloat x = y(LaIndex(),LaIndex()).copy(); // correct deep-copy
       \endverbatim
       *
       * Or this way:
       * \verbatim
       LaGenMatFloat x;
       x = y(LaIndex(),LaIndex()); // correct deep-copy
       \endverbatim
       *
       * Note: The manual for lapack++-1.1 claimed that this
       * operator would be an alias for ref(), not for copy(),
       * i.e. this operator creates a reference instead of a deep
       * copy. However, since that confused many people, the
       * behaviour was changed so that B=A will now create B as a
       * deep copy instead of a reference. If you want a
       * reference, please write B.ref(A) explicitly.
       */
    LaGenMatFloat& operator=(const LaGenMatFloat& s); //copy

    LaGenMatFloat& operator+=(float s);
    LaGenMatFloat& add(float s);

    LaGenMatFloat& resize(int m, int n);
    LaGenMatFloat& resize(const LaGenMatFloat& s);
    LaGenMatFloat& ref(const LaGenMatFloat& s);
    LaGenMatFloat& inject(const LaGenMatFloat& s);
    LaGenMatFloat& copy(const LaGenMatFloat& s);

      /** Returns a newly allocated matrix that is an
       * element-by-element copy of this matrix.
       *
       * New in lapackpp-2.5.2 */
      LaGenMatFloat copy() const;

      /** @name Expensive access functions */
      //@{
      /** Returns a newly allocated large matrix that consists of
       * \c M-by-N copies of the given matrix. (New in
       * lapackpp-2.4.5.) */
      matrix_type repmat (int M, int N) const;
      /** Returns the trace, i.e. the sum of all diagonal elements
       * of the matrix. (New in lapackpp-2.4.5) */
      value_type trace () const;
      /** Returns a newly allocated column vector of dimension \c
       * Nx1 that contains the diagonal of the given matrix. (New
       * in lapackpp-2.4.5) */
      matrix_type diag () const;
      //@}


    inline int shallow() const      // read global shallow flag
        { return shallow_;}
    inline int debug() const;       // read global debug flag
    inline int debug(int d);        // set global debug flag
    inline const LaGenMatFloat& info() const { 
            int *t = info_; 
            *t = 1; 
            return *this;};

    //* I/O *//
    friend DLLIMPORT std::ostream& operator<<(std::ostream&, const LaGenMatFloat&);
    std::ostream& Info(std::ostream& s) const
    {
        s << "Size: (" << size(0) << "x" << size(1) << ") " ;
        s << "Indeces: " << ii[0] << " " << ii[1];
        s << "#ref: " << ref_count() << "addr: " << addr() << std::endl;
        return s;
    };

      /** @name Matrix type conversions */
      //@{
      /** Convert this matrix to a complex matrix with imaginary part zero. */
      LaGenMatComplex to_LaGenMatComplex() const;
      /** Convert this matrix to a double (floating-point double precision) matrix. */
      LaGenMatDouble to_LaGenMatDouble() const;
      /** Convert this matrix to an int matrix. */
      LaGenMatInt to_LaGenMatInt() const;
      /** Convert this matrix to a long int matrix. */
      LaGenMatLongInt to_LaGenMatLongInt() const;
      //@}


      /** @name Constructors for elementary matrices */
      //@{
      /** Returns a newly allocated all-zero matrix of dimension
       * \c NxN, if \c M is not given, or \c NxM if \c M is given.
       * (New in lapackpp-2.4.5) */
      static matrix_type zeros (int N, int M=0);
      /** Returns a newly allocated all-one matrix of dimension \c
       * NxN, if \c M is not given, or \c NxM if \c M is given.
       * (New in lapackpp-2.4.5) */
      static matrix_type ones (int N, int M=0);
      /** Returns a newly allocated identity matrix of dimension
       * \c NxN, if \c M is not given, or a rectangular matrix \c
       * NxM if \c M is given.  (New in lapackpp-2.4.5) */
      static matrix_type eye (int N, int M=0);
      /** Returns a newly allocated matrix of dimension \c NxM
       * with pseudo-random values. The values are uniformly
       * distributed in the interval \c (0,1) or, if specified, \c
       * (low,high).  (New in lapackpp-2.4.5)
       *
       * Note: Since this uses the system's \c rand() call, the
       * randomness of the values might be questionable -- don't
       * use this if you need really strong random numbers. */
      static matrix_type rand (int N, int M,
			       value_type low=0, value_type high=1);
      /** Returns a newly allocated diagonal matrix of dimension
       * \c NxN that has the vector \c vect of length \c N on the
       * diagonal.  (New in lapackpp-2.4.5) */
      static matrix_type from_diag (const matrix_type &vect);
      /** Returns a newly allocated linarly spaced column vector
       * with \c nr_points elements, between and including \c
       * start and \c end. (New in lapackpp-2.4.5.) */
      static matrix_type linspace (value_type start, value_type end,
				   int nr_points);
      //@}

};  //* End of LaGenMatFloat Class *//


namespace la {
   /** The matrix data type containing (single-precision) \c float
       values. */
   typedef LaGenMatFloat fmat;
} // namespace

/** Print the matrix to the given output stream. If the matrix
 * info flag is set, then this prints only the matrix info,
 * see LaGenMatDouble::info(). Otherwise all matrix elements
 * are printed. 
 *
 * \see LaPreferences::setPrintFormat() 
 */
DLLIMPORT
std::ostream& operator<<(std::ostream&, const LaGenMatFloat&);

        

    //* Member Functions *//


 
inline int LaGenMatFloat::size(int d) const
{
    return sz[d];
}

inline int LaGenMatFloat::inc(int d) const
{
    return ii[d].inc();
}

inline int LaGenMatFloat::gdim(int d) const
{
    return dim[d];
}

inline int LaGenMatFloat::start(int d) const
{
    return ii[d].start();
}

inline int LaGenMatFloat::end(int d) const
{
    return ii[d].end();
}

inline int LaGenMatFloat::ref_count() const
{
    return v.ref_count();
}


inline LaIndex LaGenMatFloat::index(int d)  const
{
    return ii[d];
}

inline float* LaGenMatFloat::addr() const
{
    return  v.addr();
}

inline int LaGenMatFloat::debug() const
{
    return debug_;
}

inline int LaGenMatFloat::debug(int d)
{
    return debug_ = d;
}

inline float& LaGenMatFloat::operator()(int i, int j)
{

#ifdef LA_BOUNDS_CHECK
    assert(i>=0);
    assert(i<size(0));
    assert(j>=0);
    assert(j<size(1));
#endif
    return v( dim[0]*(ii[1].start() + j*ii[1].inc()) + 
                ii[0].start() + i*ii[0].inc());
}

inline float& LaGenMatFloat::operator()(int i, int j) const
{

#ifdef LA_BOUNDS_CHECK
    assert(i>=0);
    assert(i<size(0));
    assert(j>=0);
    assert(j<size(1));
#endif

    return v( dim[0]*(ii[1].start() + j*ii[1].inc()) + 
                ii[0].start() + i*ii[0].inc());
}




inline  LaGenMatFloat&  LaGenMatFloat::shallow_assign()
{
    shallow_ = 1;
    return *this;
}





#endif 
// _LA_GEN_MAT_H_


syntax highlighted by Code2HTML, v. 0.9.1