// ---------------------------------------------------------------------------
// - Rmatrix.hpp                                                             -
// - afnix:mth module - real matrix definitions                              -
// ---------------------------------------------------------------------------
// - This program is free software;  you can redistribute it  and/or  modify -
// - it provided that this copyright notice is kept intact.                  -
// -                                                                         -
// - This program  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.  In no event shall -
// - the copyright holder be liable for any  direct, indirect, incidental or -
// - special damages arising in any way out of the use of this software.     -
// ---------------------------------------------------------------------------
// - copyright (c) 1999-2013 amaury darsch                                   -
// ---------------------------------------------------------------------------

#ifndef  AFNIX_RMATRIX_HPP
#define  AFNIX_RMATRIX_HPP

#ifndef  AFNIX_RMI_HPP
#include "Rmi.hpp"
#endif
 
#ifndef  AFNIX_RVECTOR_HPP
#include "Rvector.hpp"
#endif
 
namespace afnix {

  /// This Rmatrix class is the default implementation of the real matrix
  /// interface. The matrix is designed to support a sparse representation
  /// the form of blocks aggratgation. The block index is obtained from the
  /// matrix index with the help of field index. The lower index is derived
  /// from the lower 32 bits while the higher index is derived from the higher
  /// 32 bits if needed. The implementation automatically adapt itself with
  /// a 32 bits or 64 bits long integer. The lower 32 bits indexes are derived
  /// as LB[4] (lower bottom - 4 bits), CB[8] (center-bottom 8 bits), CC[8]
  /// (center-center 8 bits), CT[8] (center-top - 8 bits) and LT[4] (lower-top
  /// 4 bits). The upper block (HB) has a variable size.
  /// @author amaury darsch

  class Rmatrix : public Iterable, public Rmi {
  public:
    /// generate a random matrix by size
    /// @param size the matrix size
    /// @param rmin the minimum value
    /// @param rmax the maximum value
    static Rmatrix* random (const t_long size, const t_real rmin,
			    const t_real rmax);

    /// generate a random matrix by size
    /// @param size the matrix size
    /// @param rmin the minimum value
    /// @param rmax the maximum value
    /// @param ddom the diagonally dominant flag
    static Rmatrix* random (const t_long size, const t_real rmin,
			    const t_real rmax, const bool   ddom);

    /// generate a sparse matrix by size
    /// @param size the matrix size
    /// @param rmin the minimum value
    /// @param rmax the maximum value
    /// @param nzsz the non zero size
    static Rmatrix* sparse (const t_long size, const t_real rmin,
			    const t_real rmax, const t_long nzsz);
    
    /// add a matrix with another one
    /// @param mx the matrix argument
    /// @param my the matrix argument
    friend Rmatrix operator + (const Rmatrix& mx, const Rmatrix& my);

    /// substract a matrix with another one
    /// @param mx the matrix argument
    /// @param my the matrix argument
    friend Rmatrix operator - (const Rmatrix& mx, const Rmatrix& my);

    /// multiply a vector with a matrix
    /// @param m the matrix argument
    /// @param x the vector argument
    friend Rvector operator * (const Rmatrix& m, const Rvector& x);

    /// multiply two matrices
    /// @param mx the matrix argument
    /// @param my the matrix argument
    friend Rmatrix operator * (const Rmatrix& mx, const Rmatrix& my);

  public:
    /// the internal lb type
    typedef t_real* t_rmlb;
    /// the internal cb type
    typedef t_rmlb* t_rmcb;
    /// the internal cc type
    typedef t_rmcb* t_rmcc;
    /// the internal ct type
    typedef t_rmcc* t_rmct;
    /// the internal lt type
    typedef t_rmct* t_rmlt;
    /// the internal hb type
    typedef t_rmlt* t_rmhb;

  private:
    /// the sparse matrix
    t_rmhb p_rmhb;

  public:
    /// create a null matrix
    Rmatrix (void);

    /// create a square matrix by size
    /// @param size the matrix size
    Rmatrix (const t_long size);

    /// create a matrix by size
    /// @param rsiz the row size
    /// @param csiz the column size
    Rmatrix (const t_long rsiz, const t_long csiz);

    /// copy construct this matrix
    /// @param that the matrix to copy
    Rmatrix (const Rmatrix& that);

    /// destroy this matrix
    ~Rmatrix (void);

    /// @return the class name
    String repr (void) const;

    /// @return a clone of this object
    Object* clone (void) const;

    /// assign a matrix to this one
    /// @param that the matrix to assign
    Rmatrix& operator = (const Rmatrix& that);

    /// resize this matrix
    /// @param rsiz the new matrix row size
    /// @param csiz the new matrix column size
    void resize (const t_long rsiz, const t_long csiz);

    /// clear this matrix
    void clear (void);

    /// set a matrix by position
    /// @param row the row position
    /// @param col the column position
    /// @param val the value to set
    void set (const t_long row, const t_long col, const t_real val);

    /// get a matrix value by position
    /// @param row the row position
    /// @param col the column position
    t_real get (const t_long row, const t_long col) const;

    /// @return a new iterator for this matrix
    Iterator* makeit (void);

  private:
    // make the matrix iterator a friend
    friend class Rmatrixit;

  public:
    /// create a new object in a generic way
    /// @param argv the argument vector
    static Object* mknew (Vector* argv);

    /// @return true if the given quark is defined
    bool isquark (const long quark, const bool hflg) const;

    /// operate this object with another object
    /// @param type   the operator type
    /// @param object the operand object
    Object* oper (t_oper type, Object* object);

    /// apply this object with a set of arguments and a quark
    /// @param robj  the current runnable
    /// @param nset  the current nameset    
    /// @param quark the quark to apply these arguments
    /// @param argv  the arguments to apply
    Object* apply (Runnable* robj, Nameset* nset, const long quark,
                   Vector* argv);
  };

  /// The Rmatrixit class is the iterator for the real matrix class. Such 
  /// iterator is constructed with the "makeit" method. The iterator
  /// is reset to the beginning of the matrix.
  /// @author amaury darsch

  class Rmatrixit : public Iterator {
  private:
    /// the matrix to iterate
    Rmatrix* p_mobj;
    /// the hb size
    long d_hbsz;
    /// the hb block index
    long d_bihb;
    /// the lt block index
    long d_bilt;
    /// the ct block index
    long d_bict;
    /// the cc block index
    long d_bicc;
    /// the cl block index
    long d_bicb;
    /// the lb block index
    long d_bilb;

  public:
    /// create a new iterator from a matrix
    /// @param mobj the matrix to iterate
    Rmatrixit (Rmatrix* vobj);
    
    /// destroy this matrix iterator
    ~Rmatrixit (void);
    
    /// @return the class name
    String repr (void) const;
    
    /// reset the iterator to the begining
    void begin (void);
    
    /// reset the iterator to the end
    void end (void);
    
    /// move the matrix iterator to the next position
    void next (void);
    
    /// move the matrix iterator to the previous position
    void prev (void);
    
    /// @return the object at the current position
    Object* getobj (void) const;
    
    /// @return true if the iterator is at the end
    bool isend (void);
    
  private:
    // make the rmatrix a friend
    friend class Rmatrix;
    // move the iterator to the next position (no lock)
    void   mvnext (void);
    // move the iterator to the previous position (no lock)
    void   mvprev (void);
    // get the row coordinate at the iterator position (no lock)
    t_long getrow (void) const;
    // get the column coordinate at the iterator position (no lock)
    t_long getcol (void) const;
    // get the value at the iterator position (no lock)
    t_real getval (void) const;

  private:
    // make the copy constructor private
    Rmatrixit (const Rmatrixit&);
    // make the assignment operator private
    Rmatrixit& operator = (const Rmatrixit&);
  };
}

#endif
