// ---------------------------------------------------------------------------
// - Algebra.hpp                                                             -
// - afnix:mth module - algebraic algorithm 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-2023 amaury darsch                                   -
// ---------------------------------------------------------------------------

#ifndef  AFNIX_ALGEBRA_HPP
#define  AFNIX_ALGEBRA_HPP

#ifndef  AFNIX_IVI_HPP
#include "Ivi.hpp"
#endif

#ifndef  AFNIX_NMI_HPP
#include "Nmi.hpp"
#endif

#ifndef  AFNIX_RMI_HPP
#include "Rmi.hpp"
#endif

#ifndef  AFNIX_CMI_HPP
#include "Cmi.hpp"
#endif

#ifndef  AFNIX_CPI_HPP
#include "Cpi.hpp"
#endif

namespace afnix {

  /// The Algebra class is a class that implements various algorithms used
  /// in algebra calculus. This is the default implementation which is often
  /// optmized by underlying class.
  /// @author amaury darsch

  class Algebra {
  public:
    /// @return true if a vector is nil
    static bool isnil (const Ivi& v);

    /// @return true if a vector is nil
    static bool isnil (const Nvi& v);

    /// @return true if a vector is nil
    static bool isnil (const Rvi& v);

    /// @return true if a vector is nil
    static bool isnil (const Cvi& v);
    
    /// copy a vector into another one
    /// @param r the result vector
    /// @param x the vector argument
    static void cpy (Ivi& r, const Ivi& x);

    /// copy a vector into another one
    /// @param r the result vector
    /// @param x the vector argument
    static void cpy (Rvi& r, const Rvi& x);

    /// copy a vector into another one
    /// @param r the result vector
    /// @param x the vector argument
    static void cpy (Cvi& r, const Cvi& x);
    
    /// compare two vectors
    /// @param x the vector argument
    /// @param y the vector argument
    static bool eql (const Ivi& x, const Ivi& y);

    /// compare two vectors
    /// @param x the vector argument
    /// @param y the vector argument
    static bool eql (const Rvi& x, const Rvi& y);

    /// compare two vectors
    /// @param x the vector argument
    /// @param y the vector argument
    static bool eql (const Cvi& x, const Cvi& y);
    
    /// compare two vectors by precision
    /// @param x the vector argument
    /// @param y the vector argument
    static bool cmp (const Rvi& x, const Rvi& y);

    /// compare two vectors by precision
    /// @param x the vector argument
    /// @param y the vector argument
    static bool cmp (const Cvi& x, const Cvi& y);
    
    /// compute the vector dot product
    /// @param x the vector argument
    /// @param y the vector argument
    static t_real dot (const Rvi& x, const Rvi& y);

    /// compute the vector hilbert product
    /// @param x the vector argument
    /// @param y the vector argument
    static Complex hdot (const Cvi& x, const Cvi& y);
    
    /// compute the vector dot product with Kahan's algorithm
    /// @param x the vector argument
    /// @param y the vector argument
    static t_real kdot (const Rvi& x, const Rvi& y);

    /// compute the vector norm
    /// @param x the vector argument
    static t_real norm (const Nvi& x);

    /// compute the vector norm
    /// @param x the vector argument
    static t_real norm (const Rvi& x);

    /// compute the vector norm
    /// @param x the vector argument
    static t_real norm (const Cvi& x);
    
    /// add a vector with a scalar
    /// @param r the result vector
    /// @param x the vector argument
    /// @param s the scalar factor
    static void add (Ivi& r, const Ivi& x, const long s);

    /// add a vector with a scalar
    /// @param r the result vector
    /// @param x the vector argument
    /// @param s the scalar factor
    static void add (Rvi& r, const Rvi& x, const t_real s);

    /// add a vector with a scalar
    /// @param r the result vector
    /// @param x the vector argument
    /// @param s the scalar factor
    static void add (Cvi& r, const Cvi& x, const Complex& s);
    
    /// add a vector with another one
    /// @param r the result vector
    /// @param x the vector argument
    /// @param y the vector argument
    static void add (Ivi& r, const Ivi& x, const Ivi& y);

    /// add a vector with another one
    /// @param r the result vector
    /// @param x the vector argument
    /// @param y the vector argument
    static void add (Rvi& r, const Rvi& x, const Rvi& y);

    /// add a vector with another one
    /// @param r the result vector
    /// @param x the vector argument
    /// @param y the vector argument
    static void add (Cvi& r, const Cvi& x, const Cvi& y);

    /// add a vector with another scaled one
    /// @param r the result vector
    /// @param x the vector argument
    /// @param y the vector argument
    /// @param s the scalar factor
    static void add (Ivi& r, const Ivi& x, const Ivi& y, const long s);

    /// add a vector with another scaled one
    /// @param r the result vector
    /// @param x the vector argument
    /// @param y the vector argument
    /// @param s the scalar factor
    static void add (Rvi& r, const Rvi& x, const Rvi& y, const t_real s);

    /// add a vector with another scaled one
    /// @param r the result vector
    /// @param x the vector argument
    /// @param y the vector argument
    /// @param s the scalar factor
    static void add (Cvi& r, const Cvi& x, const Cvi& y, const Complex& s);
    
    /// substract a vector with a scalar
    /// @param r the result vector
    /// @param x the vector argument
    /// @param s the scalar factor
    static void sub (Ivi& r, const Ivi& x, const long s);

    /// substract a vector with a scalar
    /// @param r the result vector
    /// @param x the vector argument
    /// @param s the scalar factor
    static void sub (Rvi& r, const Rvi& x, const t_real s);

    /// substract a vector with a scalar
    /// @param r the result vector
    /// @param x the vector argument
    /// @param s the scalar factor
    static void sub (Cvi& r, const Cvi& x, const Complex& s);
    
    /// substract a vector with another one
    /// @param r the result vector
    /// @param x the vector argument
    /// @param y the vector argument
    static void sub (Ivi& r, const Ivi& x, const Ivi& y);

    /// substract a vector with another one
    /// @param r the result vector
    /// @param x the vector argument
    /// @param y the vector argument
    static void sub (Rvi& r, const Rvi& x, const Rvi& y);

    /// substract a vector with another one
    /// @param r the result vector
    /// @param x the vector argument
    /// @param y the vector argument
    static void sub (Cvi& r, const Cvi& x, const Cvi& y);
    
    /// multiply a vector with a scalar
    /// @param r the result vector
    /// @param x the vector argument
    /// @param s the scalar factor
    static void mul (Ivi& r, const Ivi& x, const long s);

    /// multiply a vector with a scalar
    /// @param r the result vector
    /// @param x the vector argument
    /// @param s the scalar factor
    static void mul (Rvi& r, const Rvi& x, const t_real s);

    /// multiply a vector with a scalar
    /// @param r the result vector
    /// @param x the vector argument
    /// @param s the scalar factor
    static void mul (Cvi& r, const Cvi& x, const Complex& s);
    
    /// multiply a vector with another one
    /// @param r the result vector
    /// @param x the vector argument
    /// @param y the vector argument
    static void mul (Ivi& r, const Ivi& x, const Ivi& y);

    /// multiply a vector with another one
    /// @param r the result vector
    /// @param x the vector argument
    /// @param y the vector argument
    static void mul (Rvi& r, const Rvi& x, const Rvi& y);

    /// multiply a vector with another one
    /// @param r the result vector
    /// @param x the vector argument
    /// @param y the vector argument
    static void mul (Cvi& r, const Cvi& x, const Cvi& y);
    
    /// divide a vector with another one
    /// @param r the result vector
    /// @param x the vector argument
    /// @param y the vector argument
    static void div (Rvi& r, const Rvi& x, const Rvi& y);

    /// divide a vector with another one
    /// @param r the result vector
    /// @param x the vector argument
    /// @param y the vector argument
    static void div (Cvi& r, const Cvi& x, const Cvi& y);

    /// add equal with a vector
    /// @param r the result vector
    /// @param x the vector argument
    static void aeq (Ivi& r, const Ivi& x);

    /// add equal with a vector
    /// @param r the result vector
    /// @param x the vector argument
    static void aeq (Rvi& r, const Rvi& x);

    /// add equal with a vector
    /// @param r the result vector
    /// @param x the vector argument
    static void aeq (Cvi& r, const Cvi& x);

    /// add equal with a scaled vector
    /// @param r the result vector
    /// @param x the vector argument
    /// @param s the scalar factor
    static void aeq (Ivi& r, const Ivi& x, const long s);

    /// add equal with a scaled vector
    /// @param r the result vector
    /// @param x the vector argument
    /// @param s the scalar factor
    static void aeq (Rvi& r, const Rvi& x, const t_real s);

    /// add equal with a scaled vector
    /// @param r the result vector
    /// @param x the vector argument
    /// @param s the scalar factor
    static void aeq (Cvi& r, const Cvi& x, const Complex& s);
    
    /// rescale equal with a vector
    /// @param r the result vector
    /// @param x the vector argument
    /// @param s the scalar factor
    static void req (Ivi& r, const Ivi& x, const long s);

    /// rescale equal with a vector
    /// @param r the result vector
    /// @param x the vector argument
    /// @param s the scalar factor
    static void req (Rvi& r, const Rvi& x, const t_real s);

    /// rescale equal with a vector
    /// @param r the result vector
    /// @param x the vector argument
    /// @param s the scalar factor
    static void req (Cvi& r, const Cvi& x, const Complex& s);
    
    /// normalize a vector
    /// @param r the result vector
    /// @param x the vector to normalize
    static void normalize (Rvi& r, const Rvi& x);

    /// normalize a vector
    /// @param r the result vector
    /// @param x the vector to normalize
    static void normalize (Cvi& r, const Cvi& x);
    
    /// @return true if a trace is nil
    static bool isnil (const Nti& t);

    /// @return true if a trace is nil
    static bool isnil (const Rti& t);

    /// @return true if a trace is nil
    static bool isnil (const Cti& t);
    
    /// copy a trace into another one
    /// @param r the result trace
    /// @param x the trace argument
    static void cpy (Rti& r, const Rti& x);

    /// copy a trace into another one
    /// @param r the result trace
    /// @param x the trace argument
    static void cpy (Cti& r, const Cti& x);
    
    /// compare two traces
    /// @param x the trace argument
    /// @param y the trace argument
    static bool eql (const Rti& x, const Rti& y);

    /// compare two traces
    /// @param x the trace argument
    /// @param y the trace argument
    static bool eql (const Cti& x, const Cti& y);
    
    /// compare two traces by precision
    /// @param x the trace argument
    /// @param y the trace argument
    static bool cmp (const Rti& x, const Rti& y);

    /// compare two traces by precision
    /// @param x the trace argument
    /// @param y the trace argument
    static bool cmp (const Cti& x, const Cti& y);
    
    /// add a trace with a scalar
    /// @param r the result trace
    /// @param x the trace argument
    /// @param s the scalar factor
    static void add (Rti& r, const Rti& x, const t_real s);

    /// add a trace with a scalar
    /// @param r the result trace
    /// @param x the trace argument
    /// @param s the scalar factor
    static void add (Cti& r, const Cti& x, const Complex& s);
    
    /// add a trace with another one
    /// @param r the result trace
    /// @param x the trace argument
    /// @param y the trace argument
    static void add (Rti& r, const Rti& x, const Rti& y);

    /// add a trace with another one
    /// @param r the result trace
    /// @param x the trace argument
    /// @param y the trace argument
    static void add (Cti& r, const Cti& x, const Cti& y);

    /// add a trace with another scaled one
    /// @param r the result trace
    /// @param x the trace argument
    /// @param y the trace argument
    /// @param s the scalar factor
    static void add (Rti& r, const Rti& x, const Rti& y, const t_real s);

    /// add a trace with another scaled one
    /// @param r the result trace
    /// @param x the trace argument
    /// @param y the trace argument
    /// @param s the scalar factor
    static void add (Cti& r, const Cti& x, const Cti& y, const Complex& s);
    
    /// substract a trace with a scalar
    /// @param r the result trace
    /// @param x the trace argument
    /// @param s the scalar factor
    static void sub (Rti& r, const Rti& x, const t_real s);

    /// substract a trace with a scalar
    /// @param r the result trace
    /// @param x the trace argument
    /// @param s the scalar factor
    static void sub (Cti& r, const Cti& x, const Complex& s);
    
    /// substract a trace with another one
    /// @param r the result trace
    /// @param x the trace argument
    /// @param y the trace argument
    static void sub (Rti& r, const Rti& x, const Rti& y);

    /// substract a trace with another one
    /// @param r the result trace
    /// @param x the trace argument
    /// @param y the trace argument
    static void sub (Cti& r, const Cti& x, const Cti& y);
    
    /// multiply a trace with a scalar
    /// @param r the result trace
    /// @param x the trace argument
    /// @param s the scalar factor
    static void mul (Rti& r, const Rti& x, const t_real s);

    /// multiply a trace with a scalar
    /// @param r the result trace
    /// @param x the trace argument
    /// @param s the scalar factor
    static void mul (Cti& r, const Cti& x, const Complex& s);
    
    /// multiply a trace with another one
    /// @param r the result trace
    /// @param x the trace argument
    /// @param y the trace argument
    static void mul (Rti& r, const Rti& x, const Rti& y);

    /// multiply a trace with another one
    /// @param r the result trace
    /// @param x the trace argument
    /// @param y the trace argument
    static void mul (Cti& r, const Cti& x, const Cti& y);
    
    /// divide a trace with another one
    /// @param r the result trace
    /// @param x the trace argument
    /// @param y the trace argument
    static void div (Rti& r, const Rti& x, const Rti& y);

    /// divide a trace with another one
    /// @param r the result trace
    /// @param x the trace argument
    /// @param y the trace argument
    static void div (Cti& r, const Cti& x, const Cti& y);

    /// add equal with a trace
    /// @param r the result trace
    /// @param x the trace argument
    static void aeq (Rti& r, const Rti& x);

    /// add equal with a trace
    /// @param r the result trace
    /// @param x the trace argument
    static void aeq (Cti& r, const Cti& x);

    /// add equal with a scaled trace
    /// @param r the result trace
    /// @param x the trace argument
    /// @param s the scalar factor
    static void aeq (Rti& r, const Rti& x, const t_real s);

    /// add equal with a scaled trace
    /// @param r the result trace
    /// @param x the trace argument
    /// @param s the scalar factor
    static void aeq (Cti& r, const Cti& x, const Complex& s);
    
    /// rescale equal with a trace
    /// @param r the result trace
    /// @param x the trace argument
    /// @param s the scalar factor
    static void req (Rti& r, const Rti& x, const t_real s);

    /// rescale equal with a trace
    /// @param r the result trace
    /// @param x the trace argument
    /// @param s the scalar factor
    static void req (Cti& r, const Cti& x, const Complex& s);

    /// initialize an identity trace
    static void eye (Nti& t);
    
    /// initialize an identity trace
    static void eye (Rti& t);

    /// initialize an identity trace
    static void eye (Cti& t);
    
    /// clear a matrix lower triangular part
    static void clt (Rmi& m);

    /// clear a matrix lower triangular part
    static void clt (Cmi& m);

    /// copy a matrix into another one
    /// @param mr the result matrix
    /// @param mx the matrix argument
    static void cpy (Rmi& mr, const Rmi& mx);

    /// copy a matrix into another one
    /// @param mr the result matrix
    /// @param mx the matrix argument
    static void cpy (Cmi& mr, const Cmi& mx);

    /// copy a matrix diagonal into a trace
    /// @param r the result trace
    /// @param m the matrix argument
    static void cpt (Rti& r, const Rmi& m);

    /// copy a matrix diagonal into a trace
    /// @param r the result trace
    /// @param m the matrix argument
    static void cpt (Cti& r, const Cmi& m);

    /// copy a trace as a matrix diagonal
    /// @param m the result matrix
    /// @param t the trace argument
    static void cpt (Rmi& m, const Rti& t);
    
    /// copy a trace as a matrix diagonal
    /// @param m the result matrix
    /// @param t the trace argument
    static void cpt (Cmi& m, const Cti& t);
    
    /// copy a matrix row into a vector
    /// @param r   the result vector
    /// @param m   the matrix argument
    /// @param row the row to copy
    static void cpr (Rvi& r, const Rmi& m, const t_long row);

    /// copy a matrix row into a vector
    /// @param r   the result vector
    /// @param m   the matrix argument
    /// @param row the row to copy
    static void cpr (Cvi& r, const Cmi& m, const t_long row);

    /// copy a vector as a matrix row
    /// @param m   the result matrix
    /// @param x   the vector argument
    /// @param row the row to copy
    static void cpr (Rmi& m, const Rvi& x, const t_long row);

    /// copy a vector as a matrix row
    /// @param m   the result matrix
    /// @param x   the vector argument
    /// @param row the row to copy
    static void cpr (Cmi& m, const Cvi& x, const t_long row);

    /// copy a matrix column into a vector
    /// @param r   the result vector
    /// @param m   the matrix argument
    /// @param col the column to copy
    static void cpc (Rvi& r, const Rmi& m, const t_long col);

    /// copy a matrix column into a vector
    /// @param r   the result vector
    /// @param m   the matrix argument
    /// @param col the column to copy
    static void cpc (Cvi& r, const Cmi& m, const t_long col);

    /// copy a vector as a matrix column
    /// @param m   the result matrix
    /// @param x   the vector argument
    /// @param col the column to copy
    static void cpc (Rmi& m, const Rvi& x, const t_long col);

    /// copy a vector as a matrix column
    /// @param m   the result matrix
    /// @param x   the vector argument
    /// @param col the column to copy
    static void cpc (Cmi& m, const Cvi& x, const t_long col);

    /// compare two matrices
    /// @param mx the matrix argument
    /// @param my the matrix argument
    static bool eql (const Rmi& mx, const Rmi& my);

    /// compare two matrices
    /// @param mx the matrix argument
    /// @param my the matrix argument
    static bool eql (const Cmi& mx, const Cmi& my);

    /// compare two matrices by precision
    /// @param mx the matrix argument
    /// @param my the matrix argument
    static bool cmp (const Rmi& mx, const Rmi& my);

    /// compare two matrices by precision
    /// @param mx the matrix argument
    /// @param my the matrix argument
    static bool cmp (const Cmi& mx, const Cmi& my);

    /// check if a matrix row is null
    /// @param m the matrix argument
    /// @param row the matrix row
    static bool isnrow (const Rmi& m, const t_long row);

    /// check if a matrix row is null
    /// @param m the matrix argument
    /// @param row the matrix row
    static bool isnrow (const Cmi& m, const t_long row);

    /// check if a matrix column is null
    /// @param m the matrix argument
    /// @param col the matrix row
    static bool isncol (const Rmi& m, const t_long col);

    /// check if a matrix column is null
    /// @param m the matrix argument
    /// @param col the matrix row
    static bool isncol (const Cmi& m, const t_long col);

    /// compute the matrix freobenius norm
    /// @param m the matrix argument
    static t_real norm (const Rmi& m);

    /// compute the matrix freobenius norm
    /// @param m the matrix argument
    static t_real norm (const Cmi& m);
    
    /// check if the matrix has null diagonal elements
    /// @param m the matrix argument
    static bool nulld (const Rmi& m);

    /// check if the matrix has null diagonal elements
    /// @param m the matrix argument
    static bool nulld (const Cmi& m);

    /// add a matrix with another one
    /// @param mr the result matrix
    /// @param mx the matrix argument
    /// @param my the matrix argument
    static void add (Rmi& mr, const Rmi& mx, const Rmi& my);

    /// add a matrix with another one
    /// @param mr the result matrix
    /// @param mx the matrix argument
    /// @param my the matrix argument
    static void add (Cmi& mr, const Cmi& mx, const Cmi& my);
    
    /// substract a matrix with another one
    /// @param mr the result matrix
    /// @param mx the matrix argument
    /// @param my the matrix argument
    static void sub (Rmi& mr, const Rmi& mx, const Rmi& my);

    /// substract a matrix with another one
    /// @param mr the result matrix
    /// @param mx the matrix argument
    /// @param my the matrix argument
    static void sub (Cmi& mr, const Cmi& mx, const Cmi& my);
    
    /// multiply two vectors as a matrix
    /// @param mr the result matrix
    /// @param u  the vector argument
    /// @param v  the second argument
    static void mul (Rmi& mr, const Rvi& u, const Rvi& v);

    /// multiply a matrix with a vector and a scaling factor
    /// @param r the result vector
    /// @param m the matrix argument
    /// @param x the vector argument
    /// @param s the scaling factor
    static void mul (Rvi& r, const Rmi& m, const Rvi& x, const t_real s);

    /// multiply a matrix with a vector and a scaling factor
    /// @param r the result vector
    /// @param m the matrix argument
    /// @param x the vector argument
    /// @param s the scaling factor
    static void mul (Cvi& r, const Cmi& m, const Cvi& x, const Complex& s);

    /// multiply two matrices
    /// @param mr the result matrix
    /// @param mx the matrix argument
    /// @param my the matrix argument
    static void mul (Rmi& mr, const Rmi& mx, const Rmi& my);

    /// multiply two matrices
    /// @param mr the result matrix
    /// @param mx the matrix argument
    /// @param my the matrix argument
    static void mul (Cmi& mr, const Cmi& mx, const Cmi& my);

    /// multiply a transposed matrix with a vector and a scaling factor
    /// @param r the result vector
    /// @param m the matrix argument
    /// @param x the vector argument
    /// @param s the scaling factor
    static void tmul (Rvi& r, const Rmi& m, const Rvi& x, const t_real s);

    /// multiply a transposed matrix with a vector and a scaling factor
    /// @param r the result vector
    /// @param m the matrix argument
    /// @param x the vector argument
    /// @param s the scaling factor
    static void tmul (Cvi& r, const Cmi& m, const Cvi& x, const Complex& s);

    /// add equal a matrix with a vector at a column position
    /// @param m   the matrix to update
    /// @param v   the vector argument
    /// @param s   the scaling factor
    /// @param col the column to update
    static void cva (Rmi& m, const Rvi& x, const t_real s, const t_long col);

    /// add equal a matrix with a vector at a row position
    /// @param m   the matrix to update
    /// @param v   the vector argument
    /// @param s   the scaling factor
    /// @param row the row to update
    static void rva (Rmi& m, const Rvi& x, const t_real s, const t_long row);

    /// initialize an identity matrix
    static void eye (Nmi& mr);
    
    /// initialize an identity matrix
    static void eye (Rmi& mr);

    /// initialize an identity matrix
    static void eye (Cmi& mr);

    /// create an adjoint matrix
    static void adj (Cmi& mr, const Cmi& mx);
    
    /// create a random vector with bounds
    /// @param r    the result vector
    /// @param rmin the minimum value
    /// @param rmax the maximum value
    static void random (Ivi& r, const long rmin, const long rmax);

    /// create a random vector with bounds
    /// @param r    the result vector
    /// @param rmin the minimum value
    /// @param rmax the maximum value
    static void random (Nvi& r, const Numeral& rmin, const Numeral& rmax);

    /// create a random vector with bounds
    /// @param r    the result vector
    /// @param rmin the minimum value
    /// @param rmax the maximum value
    static void random (Rvi& r, const t_real rmin, const t_real rmax);

    /// create a random matrix with bounds
    /// @param mr   the result matrix
    /// @param nmin the minimum value
    /// @param nmax the maximum value
    static void random (Nmi& mr, const Numeral& rmin, const Numeral& rmax);

    /// create a random matrix with bounds
    /// @param mr   the result matrix
    /// @param rmin the minimum value
    /// @param rmax the maximum value
    static void random (Rmi& mr, const t_real rmin, const t_real rmax);

    /// create a sparse matrix with bounds
    /// @param mr   the result matrix
    /// @param rmin the minimum value
    /// @param rmax the maximum value
    /// @param nzsz the non zero size
    static void sparse (Rmi& mr, const t_real rmin, const t_real rmax,
			const t_long nzsz);

    /// make a matrix diagonaly dominant
    /// @param mr the result matrix
    /// @param df the diagonal factor to add
    static void toddom (Rmi& mr, const t_real df);

    /// perform a givens vector update
    /// @param r the vector to update
    /// @param i the row coordinate
    /// @param j the column coordinate
    /// @param c the givens ii/jj coefficient
    /// @param s the givens ij/ji coefficient
    static void givens (Rvi& r, const t_long i, const t_long j, 
			const t_real c, const t_real s);

    /// perform a givens matrix update
    /// @param m the matrix to update
    /// @param i the row coordinate
    /// @param j the column coordinate
    /// @param c the givens ii/jj coefficient
    /// @param s the givens ij/ji coefficient
    /// @param pflg the partial flag
    static void givens (Rmi& m, const t_long i, const t_long j, 
			const t_real c, const t_real s, const bool pflg);

    /// perform an upper triangular multiplication
    /// @param r the result vector
    /// @param m the matrix argument
    /// @param x the vector argument
    static void utmul (Rvi& r, const Rmi& m, const Rvi& x);

    /// perform an upper triangular division
    /// @param r the result vector
    /// @param m the matrix argument
    /// @param x the vector argument
    static void utdiv (Rvi& r, const Rmi& m, const Rvi& x);

    /// perform a lower triangular multiplication
    /// @param r the result vector
    /// @param m the matrix argument
    /// @param x the vector argument
    static void ltmul (Rvi& r, const Rmi& m, const Rvi& x);

    /// perform a lower triangular division
    /// @param r the result vector
    /// @param m the matrix argument
    /// @param x the vector argument
    static void ltdiv (Rvi& r, const Rmi& m, const Rvi& x);
    
    /// perform a vector permutation
    /// @param r the result vector
    /// @param x the vector argument
    /// @param p the permutation argument
    static void permutate (Ivi& r, const Ivi& x, const Cpi& p);

    /// perform a vector permutation
    /// @param r the result vector
    /// @param x the vector argument
    /// @param p the permutation argument
    static void permutate (Rvi& r, const Rvi& x, const Cpi& p);

    /// perform a vector permutation
    /// @param r the result vector
    /// @param x the vector argument
    /// @param p the permutation argument
    static void permutate (Cvi& r, const Cvi& x, const Cpi& p);

    /// perform a trace permutation
    /// @param r the result trace
    /// @param x the trace argument
    /// @param p the permutation argument
    static void permutate (Rti& r, const Rti& x, const Cpi& p);

    /// perform a trace permutation
    /// @param r the result trace
    /// @param x the trace argument
    /// @param p the permutation argument
    static void permutate (Cti& r, const Cti& x, const Cpi& p);
    
    /// perform a matrix permutation
    /// @param r the result matrix
    /// @param m the matrix argument
    /// @param p the permutation argument
    static void permutate (Rmi& r, const Rmi& m, const Cpi& p);

    /// perform a matrix permutation
    /// @param r the result matrix
    /// @param m the matrix argument
    /// @param p the permutation argument
    static void permutate (Cmi& r, const Cmi& m, const Cpi& p);

    /// perform a reverse vector permutation
    /// @param r the result vector
    /// @param x the vector argument
    /// @param p the permutation argument
    static void reverse (Ivi& r, const Ivi& x, const Cpi& p);

    /// perform a reverse vector permutation
    /// @param r the result vector
    /// @param x the vector argument
    /// @param p the permutation argument
    static void reverse (Rvi& r, const Rvi& x, const Cpi& p);

    /// perform a reverse vector permutation
    /// @param r the result vector
    /// @param x the vector argument
    /// @param p the permutation argument
    static void reverse (Cvi& r, const Cvi& x, const Cpi& p);

    /// perform a reverse trace permutation
    /// @param r the result trace
    /// @param x the trace argument
    /// @param p the permutation argument
    static void reverse (Rti& r, const Rti& x, const Cpi& p);

    /// perform a reverse trace permutation
    /// @param r the result trace
    /// @param x the trace argument
    /// @param p the permutation argument
    static void reverse (Cti& r, const Cti& x, const Cpi& p);
    
    /// perform a reverse matrix permutation
    /// @param r the result matrix
    /// @param m the matrix argument
    /// @param p the permutation argument
    static void reverse (Rmi& r, const Rmi& m, const Cpi& p);

    /// perform a reverse matrix permutation
    /// @param r the result matrix
    /// @param m the matrix argument
    /// @param p the permutation argument
    static void reverse (Cmi& r, const Cmi& m, const Cpi& p);
  };
}

#endif
