//$$ newmat5.cxx         Transpose, evaluate etc

// Copyright (C) 1991: R B Davies and DSIR

#include "include.hxx"

#include "newmat.hxx"
#include "newmatrc.hxx"

//#define REPORT { static ExeCounter ExeCount(__LINE__,5); ExeCount++; }

#define REPORT {}


/************************ carry out operations ******************************/


GeneralMatrix* GeneralMatrix::Transpose(MatrixType mt)
{
   if ((int)mt==0) mt = Type().t();           // type of transposed matrix
   GeneralMatrix* gm1 = mt.New(ncols,nrows); gm1->ReleaseAndDelete();

   if (mt == Type().t())
   {
      REPORT
      for (int i=0; i<ncols; i++)
      {
	 MatrixRow mr(gm1, StoreOnExit+DirectPart, i);
         MatrixCol mc(this, mr.Store(), LoadOnEntry, i);
      }
   }
   else
   {
      REPORT
      MatrixRow mr(this, LoadOnEntry);
      MatrixCol mc(gm1, StoreOnExit+DirectPart);
      int i = nrows;
      while (i--) { mc.Copy(mr); mr.Next(); mc.Next(); }
   }
   tDelete(); return gm1;
}

GeneralMatrix* SymmetricMatrix::Transpose(MatrixType mt)
{ REPORT  return Evaluate(mt); }


GeneralMatrix* DiagonalMatrix::Transpose(MatrixType mt)
{ REPORT return Evaluate(mt); }

BOOL GeneralMatrix::IsZero() const
{
   REPORT
   real* s=store; int i=storage;
   while (i--) { if (*s++) return FALSE; }
   return TRUE;
}

GeneralMatrix* ColumnVector::Transpose(MatrixType mt)
{
   REPORT
   GeneralMatrix* gmx = new RowVector; MatrixErrorNoSpace(gmx);
   gmx->nrows = 1; gmx->ncols = gmx->storage = storage;
   return BorrowStore(gmx,mt);
}

GeneralMatrix* RowVector::Transpose(MatrixType mt)
{
   REPORT
   GeneralMatrix* gmx = new ColumnVector; MatrixErrorNoSpace(gmx);
   gmx->ncols = 1; gmx->nrows = gmx->storage = storage;
   return BorrowStore(gmx,mt);
}

GeneralMatrix* GeneralMatrix::Evaluate(MatrixType mt)
{
   if ((int)mt==0) { REPORT return this; }
   if (mt==this->Type()) { REPORT return this; }
   REPORT
   GeneralMatrix* gmx = mt.New(nrows,ncols);
   MatrixRow mr(this, LoadOnEntry);
   MatrixRow mrx(gmx, StoreOnExit+DirectPart);
   int i=nrows;
   while (i--) { mrx.Copy(mr); mrx.Next(); mr.Next(); }
   tDelete(); gmx->ReleaseAndDelete(); return gmx;
}

GeneralMatrix* ConstMatrix::Evaluate(MatrixType mt)
{
   if ((int)mt==0 || mt==cgm->Type()) { REPORT return (GeneralMatrix*)cgm; }

   REPORT
   GeneralMatrix* gmx = cgm->Type().New(cgm->Nrows(),cgm->Ncols());
   MatrixRow mr((GeneralMatrix*)cgm, LoadOnEntry);//assume won't change this
   MatrixRow mrx(gmx, StoreOnExit+DirectPart);
   int i=cgm->Nrows();
   while (i--) { mrx.Copy(mr); mrx.Next(); mr.Next(); }
   gmx->ReleaseAndDelete(); return gmx; // no tDelete
}

GeneralMatrix* ShiftedMatrix::Evaluate(MatrixType mt)
{
   GeneralMatrix* gm=bm->Evaluate();
   if ((int)mt==0)
      { MatrixType mteqel(MatrixType::EqEl); mt = gm->Type()+mteqel; }
   int nr=gm->Nrows(); int nc=gm->Ncols();
   if (!(mt==gm->Type()))
   {
      REPORT
      GeneralMatrix* gmx = mt.New(nr,nc);
      MatrixRow mr(gm, LoadOnEntry); 
      MatrixRow mrx(gmx, StoreOnExit+DirectPart);
      while (nr--) { mrx.Add(mr,f); mrx.Next(); mr.Next(); }
      gmx->ReleaseAndDelete(); gm->tDelete(); return gmx;
   }
   else if (gm->reuse()) { REPORT gm->Add(f); return gm; }
   else
   {
      REPORT GeneralMatrix* gmy = gm->Type().New(nr,nc);
      gmy->ReleaseAndDelete(); gmy->Add(gm,f); return gmy;
   }
}

GeneralMatrix* ScaledMatrix::Evaluate(MatrixType mt)
{
   GeneralMatrix* gm=bm->Evaluate();
   int nr=gm->Nrows(); int nc=gm->Ncols();
   if ((int)mt==0) mt = gm->Type();
   if (mt==gm->Type())
   {
      if (gm->reuse()) { REPORT gm->Multiply(f); return gm; }
      else
      {
         REPORT GeneralMatrix* gmx = gm->Type().New(nr,nc);
         gmx->ReleaseAndDelete(); gmx->Multiply(gm,f); return gmx;
      }
   }
   else
   {
      REPORT
      GeneralMatrix* gmx = mt.New(nr,nc);
      MatrixRow mr(gm, LoadOnEntry); 
      MatrixRow mrx(gmx, StoreOnExit+DirectPart);
      while (nr--) { mrx.Multiply(mr,f); mrx.Next(); mr.Next(); }
      gmx->ReleaseAndDelete(); gm->tDelete(); return gmx;
   }
}

GeneralMatrix* NegatedMatrix::Evaluate(MatrixType mt)
{
   GeneralMatrix* gm=bm->Evaluate();
   if ((int)mt==0) mt = gm->Type();
   int nr=gm->Nrows(); int nc=gm->Ncols();
   if (mt==gm->Type())
   {
      if (gm->reuse()) { REPORT gm->Negate(); return gm; }
      else
      {
         REPORT
         GeneralMatrix* gmx = gm->Type().New(nr,nc); gmx->ReleaseAndDelete();
         gmx->Negate(gm); return gmx;
      }
   }
   else
   {
      REPORT
      GeneralMatrix* gmx = mt.New(nr,nc);
      MatrixRow mr(gm, LoadOnEntry); 
      MatrixRow mrx(gmx, StoreOnExit+DirectPart);
      while (nr--) { mrx.Negate(mr); mrx.Next(); mr.Next(); }
      gmx->ReleaseAndDelete(); gm->tDelete(); return gmx;
   }
}   

GeneralMatrix* TransposedMatrix::Evaluate(MatrixType mt)
{
   REPORT
   GeneralMatrix* gm=bm->Evaluate();
   if ((int)mt==0) mt = gm->Type().t();
   GeneralMatrix* gmx=gm->Transpose(mt);
   return gmx;
}
   
GeneralMatrix* RowedMatrix::Evaluate(MatrixType mt)
{
   GeneralMatrix* gm = bm->Evaluate();
   GeneralMatrix* gmx = new RowVector; MatrixErrorNoSpace(gmx);
   gmx->nrows = 1; gmx->ncols = gmx->storage = gm->storage;
   return gm->BorrowStore(gmx,mt);
}

GeneralMatrix* ColedMatrix::Evaluate(MatrixType mt)
{
   GeneralMatrix* gm = bm->Evaluate();
   GeneralMatrix* gmx = new ColumnVector; MatrixErrorNoSpace(gmx);
   gmx->ncols = 1; gmx->nrows = gmx->storage = gm->storage;
   return gm->BorrowStore(gmx,mt);
}

GeneralMatrix* DiagedMatrix::Evaluate(MatrixType mt)
{
   GeneralMatrix* gm = bm->Evaluate();
   GeneralMatrix* gmx = new DiagonalMatrix; MatrixErrorNoSpace(gmx);
   gmx->nrows = gmx->ncols = gmx->storage = gm->storage;
   return gm->BorrowStore(gmx,mt);
}

GeneralMatrix* MatedMatrix::Evaluate(MatrixType mt)
{
   GeneralMatrix* gm = bm->Evaluate();
   GeneralMatrix* gmx = new Matrix; MatrixErrorNoSpace(gmx);
   gmx->nrows = nr; gmx->ncols = nc; gmx->storage = gm->storage;
   if (nr*nc != gmx->storage)
      MatrixError("Incompatible dimensions in CopyToMatrix");
   return gm->BorrowStore(gmx,mt);
}

GeneralMatrix* GetSubMatrix::Evaluate(MatrixType mt)
{
   REPORT
   GeneralMatrix* gm = bm->Evaluate();
   if (row_skip+row_number > gm->Nrows() || col_skip+col_number > gm->Ncols())
      MatrixError("SubMatrix dimension error");
   if (int(mt)==0) mt = MatrixType::Rect;
   GeneralMatrix* gmx = mt.New(row_number, col_number);
   int i = row_number;
   MatrixRow mr(gm, LoadOnEntry, row_skip); 
   MatrixRow mrx(gmx, StoreOnExit+DirectPart);
   MatrixRowCol sub;
   while (i--)
   {
      mr.SubRowCol(sub, col_skip, col_number);   // put values in sub
      mrx.Copy(sub); mrx.Next(); mr.Next();
   }
   gmx->ReleaseAndDelete(); gm->tDelete(); return gmx;
}   

GeneralMatrix* ReturnMatrix::Evaluate(MatrixType mt)
{ return gm->Evaluate(mt); }


void GeneralMatrix::Add(GeneralMatrix* gm1, real f)
{
   REPORT
   register real* s1=gm1->store;
   register real* s=store; register int i=storage;
   while (i--) *s++ = *s1++ + f;
}
   
void GeneralMatrix::Add(real f)
{
   REPORT
   register real* s=store; register int i=storage; while (i--) *s++ += f;
}
   
void GeneralMatrix::Negate(GeneralMatrix* gm1)
{
   // change sign of elements
   REPORT
   real* s1=gm1->store; real* s=store; register int i=storage;
   while(i--) *s++ = -(*s1++);
}
   
void GeneralMatrix::Negate()
{
   REPORT
   real* s=store; register int i=storage; while(i--) { *s = -(*s); s++; } 
}
   
void GeneralMatrix::Multiply(GeneralMatrix* gm1, real f)
{
   REPORT
   register real* s1=gm1->store;
   register real* s=store; register int i=storage;
   while (i--) *s++ = *s1++ * f;
}
   
void GeneralMatrix::Multiply(real f)
{
   REPORT
   register real* s=store; register int i=storage; while (i--) *s++ *= f;
}
   
