/*
    This file is part of the FElt finite element analysis package.
    Copyright (C) 1993-2000 Jason I. Gobat and Darren C. Atkinson

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

    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.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/************************************************************************
 * File:	data.c	
 *	
 * Description:	
 *		
 ************************************************************************/

# include <stdio.h>
# include <stdlib.h>
# include "matrix.h"
# include "cmatrix.h"
# include "error.h"

complex cmdata (A, row, col)
   ComplexMatrix	A;
   unsigned		row;
   unsigned		col;
{
   unsigned	height;
   unsigned	temp;

   if (IsFull (A))
      return A -> data [row][col];
   else if (IsCompact (A)) {
      if (row > col) {
         temp = col;
         col = row;
         row = temp;
      }

      if (col == 1)
         height = 1;
      else
         height = A -> diag [col] - A -> diag [col - 1];

      if (row > col - height)
         return A -> data [A -> diag [col] + row - col][1]; 
      else
         return zero();
   }

   return zero();
}

ComplexMatrix CreateSubsectionComplexMatrix (a, sr, sc, er, ec)
   ComplexMatrix	a;
   unsigned	sr, sc;
   unsigned	er, ec;
{
   ComplexMatrix	b;
   unsigned	i;
   ComplexMatrix	root;

   if (er > a -> nrows || ec > a -> ncols || sc < 1 || sr < 1)
      return NULL;

   if (IsCompact (a))
      return NULL;

   b = (struct complex_matrix *) malloc (sizeof (struct complex_matrix));
   if (b == NULL)
	Fatal ("unable to allocate subsection matrix");

   b -> nrows = er - sr + 1;
   b -> ncols = ec - sc + 1;

   b -> data = (complex **) malloc (sizeof (complex *) * b -> nrows);
   if (b -> data == NULL)
	Fatal ("unable to allocate subsection matrix");
   b -> data --;

   for (i = 1 ; i <= b -> nrows ; i++)
      b -> data [i] = &(a -> data [i + sr - 1][sc - 1]); 

   b -> refcount = 0;
   b -> size = 0;

   root = a;
   while (root -> parent)
      root = root -> parent;

   b -> parent = root;
   root -> refcount ++;

   return b;
}

ComplexMatrix CreateFullComplexMatrix (rows, cols)
   unsigned	rows;
   unsigned	cols;
{
   unsigned	i;
   ComplexMatrix	m;

   m = (struct complex_matrix *) malloc (sizeof (struct complex_matrix));
   if (m == NULL)
	Fatal ("unable to allocate full matrix");

   m -> data = (complex **) malloc (sizeof (complex *) * rows);
   if (m -> data == NULL)
	Fatal ("unable to allocate full matrix");
   m -> data --;

   m -> data [1] = (complex *) malloc (sizeof (complex) * rows * cols);
   if (m -> data [1] == NULL)
	Fatal ("unable to allocate full matrix");
   m -> data [1] --;
   for (i = 2 ; i <= rows ; i++)
      m -> data [i] = m -> data [i-1] + cols;

   m -> nrows = rows;
   m -> ncols = cols;
   m -> size = 0;
   m -> refcount = 1;
   m -> parent = NULL;

   return m;
}

ComplexMatrix CreateComplexRowVector (size)
   unsigned	size;
{
   return CreateFullComplexMatrix (1, size);
}

ComplexMatrix CreateComplexColumnVector (size)
   unsigned	size;
{
   return CreateFullComplexMatrix (size, 1);
}

void DestroyComplexMatrix (m)
   ComplexMatrix	m;
{
   if (m -> parent != NULL) {
      m -> parent -> refcount --;
 
      if (m -> parent -> refcount == 0)
         DestroyComplexMatrix (m -> parent);
      
      m -> data ++;
      free (m -> data);
      free (m); 

      return;
   } 
   else if (-- m -> refcount)
      return;

   m -> data [1] ++;
   free (m -> data [1]);

   m -> data ++;
   free (m -> data);

   if (IsCompact (m)) {
      m -> diag ++;
      free (m -> diag);
   }
   
   free (m);
}

ComplexMatrix CreateCompactComplexMatrix (rows, cols, size, diag)
   unsigned	rows;
   unsigned 	cols;
   unsigned	size;
   unsigned	*diag;
{
   ComplexMatrix	A;

   A = CreateFullComplexMatrix (size, 1);

   A -> nrows = rows; 
   A -> ncols = cols;
   A -> size = size;
   A -> parent = NULL;

   if (diag != NULL) {
      A -> diag = (unsigned *) malloc (sizeof (unsigned) * rows);
      if (A -> diag == NULL)
         Fatal ("unable to create compact matrix");

      A -> diag --;

      memcpy ((void *) &(A -> diag[1]), (void *) &(diag[1]), 
              sizeof(unsigned)*rows);
   }

   return A;
}

ComplexMatrix CreateCopyComplexMatrix (a)
   ComplexMatrix	a;
{
   ComplexMatrix	b;
   unsigned	size;
   unsigned	rows, cols;

   rows = a -> nrows;
   cols = a -> ncols;

   if (IsCompact(a)) {
      size = Msize(a)*sizeof(complex);
      b = CreateCompactComplexMatrix (rows, cols, Msize(a), NULL); 
      b -> diag = (unsigned *) malloc (sizeof(unsigned) * rows);
      if (b -> diag == NULL)
	Fatal ("unable to create compact matrix");
      b -> diag --;
      memcpy ((void *) &(b -> diag[1]), (void *) &(a -> diag[1]), 
              sizeof(unsigned)*rows);
   }
   else { 
      size = rows*cols*sizeof (complex);
      b = CreateFullComplexMatrix (rows, cols);
   }   

   memcpy ((void *) &(b -> data[1][1]),(void *) &(a -> data[1][1]), size);

   return b;
}

ComplexMatrix MakeFullFromCompactComplex (A)
   ComplexMatrix	A;
{
   unsigned 		i,j;
   ComplexMatrix	B;

   B = CreateFullComplexMatrix (Mrows(A), Mcols(A));

   for (i = 1 ; i <= Mrows(A) ; i++) 
      for (j = 1 ; j <= Mcols(A) ; j++)
         B -> data [i][j] = cmdata(A, i, j);

   return B; 
}

ComplexMatrix MakeCompactFromFullComplex (A)
   ComplexMatrix	A;
{
   unsigned	*diag;
   ComplexMatrix	compA;
   unsigned	i,j,k,
		curr_row;
   unsigned	rows,cols;
   unsigned	size;
   unsigned	height;

   if (IsCompact(A))
      return (ComplexMatrix) NullMatrix;

   if (!IsSquare(A))
      return (ComplexMatrix) NullMatrix;

   if (!IsSymmetricComplexMatrix(A))
      return (ComplexMatrix) NullMatrix;

   rows = Mrows (A);
   cols = Mcols (A);

   size = 0;
   for (i = 1 ; i <= rows ; i++) {
      if (re(cmdata(A,i,i)) == 0 && im(cmdata(A,i,i)) == 0) {
         size = 1;
         break;
      }
   }

   if (size)
      return (ComplexMatrix) NullMatrix;

   diag = (unsigned *) malloc (sizeof(unsigned) * cols);
   if (diag == NULL)
	Fatal ("unable to create compact matrix");

   diag--;
    
	/*
	 * determine the height of the columns and store in diag
	 */

   for (j = 1 ; j <= cols ; j++) {
      diag [j] = 0;
      for (i = 1 ; i <= rows; i++) {

         if ((re(cmdata(A,i,j)) != 0.0 || im(cmdata(A,i,j)) != 0)  && 
             i <= j && (j - (i-1)) > diag [j]) 

            diag [j] = j - (i-1);
      }
   }

   size = 0;
   for (i = 1 ; i <= cols ; i++) 
      size += diag [i];
   
   compA = CreateCompactComplexMatrix (rows, cols, size, NULL);

   diag [1] = 1;
   compA -> data [1][1] = cmdata (A, 1, 1);
  
   for (i = 2 ; i <= cols ; i++) {
      height = diag [i];
      diag [i] += diag [i-1];
      curr_row = i - height + 1 ;
      for (k = diag [i] - height + 1 ; k <= diag [i] ; k++) 
         compA -> data [k][1] = cmdata (A, curr_row++, i);
   }

   compA -> diag = diag;

   return compA;
} 


syntax highlighted by Code2HTML, v. 0.9.1