/*
 * Copyright (C) 1996-2011 Daniel Waggoner
 *
 * This 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 3 of the License, or
 * (at your option) any later version.
 *
 * It 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.
 *
 * If you did not received a copy of the GNU General Public License
 * with this software, see <http://www.gnu.org/licenses/>.
 */

#include "matrix_test_instances.hpp"
#include "dw_matrix_rand.h"
#include "dw_error.h"
#include "dw_std.h"

#include <math.h>
#include <string.h>

PRECISION EqualMatrices(TMatrix X, TMatrix Y);
PRECISION EqualVectors(TVector x, TVector y);
PRECISION IsZeroMatrix(TMatrix X);
PRECISION IsZeroVector(TVector x);
PRECISION IsIdentity(TMatrix X);
PRECISION IsSymmetric(TMatrix X);
PRECISION IsOrthogonal(TMatrix X);

#define RTRN(type) dynamic_cast<type*>(rtrn)->GetReturn()
#define ARG(type,i) dynamic_cast<type*>(arg(i))->GetArg()
#define COPY(type,i) dynamic_cast<type*>(arg(i))->GetCopy()

#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define MAX(a,b) (((a) > (b)) ? (a) : (b))

//=== CreateVector()
//=== Also tests DimV(), ElementV(), pElementV()
int CreateVector_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=CreateVector(ARG(TArg_int_size,0));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION CreateVector_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION *p;
  TVector v=RTRN(TReturn_TVector);
  int dim=COPY(TArg_int_size,0), i;

  if (!v || (dim != DimV(v)))
    err=-1.0;
  else
    {
      p=pElementV(v);
      for (i=0; i < dim; i++) p[i]=0.0;
      for (i=0; i < dim; i++)
	{
	  ElementV(v,i)=1.0;
	  if (p[i] != 1.0) err=-1.0;
	  ElementV(v,i)=0.0;
	}
    }

  return err;
}

//=== CreateMatrix() 
//=== Also tests RowM(), ColM(), ElementM(), pElementM() and MajorForm()
int CreateMatrix_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=CreateMatrix(ARG(TArg_int_size,0),ARG(TArg_int_size,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION CreateMatrix_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION *p;
  TMatrix X=RTRN(TReturn_TMatrix);
  int row=COPY(TArg_int_size,0), col=COPY(TArg_int_size,1), i, j;

  if (!X || (row != RowM(X)) || (col != ColM(X)))
    err=-1.0;
  else
    {
      p=pElementM(X);
      for (i=0; i < row*col; i++) p[i]=0.0;
      if (MajorForm(X) == COLUMN_MAJOR)
	{
	  for (i=0; i < row; i++)
	    for (j=0; j < col; j++)
	      {
		ElementM(X,i,j)=1.0;
		if (p[j*row + i] != 1.0) err=-1.0;
		ElementM(X,i,j)=0.0;
	      }
	}
      else
	{
	  for (i=0; i < row; i++)
	    for (j=0; j < col; j++)
	      {
		ElementM(X,i,j)=1.0;
		if (p[i*col + j] != 1.0) err=-1.0;
		ElementM(X,i,j)=0.0;
	      }
	}
    }

  return err;
}

//=== InitializeVector()
int InitializeVector_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=InitializeVector(ARG(TArg_TVector,0),ARG(TArg_PRECISION,1));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION InitializeVector_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp, x=COPY(TArg_PRECISION,1);
  TVector X=RTRN(TReturn_TVector);
  int i;

  if (!X)
    err=-1.0;
  else
    for (i=DimV(X)-1; i >= 0; i--)
      if ((tmp=fabs(ElementV(X,i)-x)) > err) err=tmp;

  return err;
}

//=== InitializeMatrix()
int InitializeMatrix_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=InitializeMatrix(ARG(TArg_TMatrix,0),ARG(TArg_PRECISION,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION InitializeMatrix_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp, x=COPY(TArg_PRECISION,1);
  TMatrix X=RTRN(TReturn_TMatrix);
  int i, j;

  if (!X)
    err=-1.0;
  else
    for (i=RowM(X)-1; i >= 0; i--)
      for (j=ColM(X)-1; j >= 0; j--)
	if ((tmp=fabs(ElementM(X,i,j)-x)) > err) err=tmp;

  return err;
}

//=== EquateVector()
int EquateVector_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=EquateVector(ARG(TArg_TVector,0),ARG(TArg_TVector,1));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION EquateVector_T::ResultOK(void)
{
  return EqualVectors(RTRN(TReturn_TVector),COPY(TArg_TVector,1));
}

//=== EquateMatrix()
int EquateMatrix_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=EquateMatrix(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION EquateMatrix_T::ResultOK(void)
{
  return EqualMatrices(RTRN(TReturn_TMatrix),COPY(TArg_TMatrix,1));
}

//=== Transpose()
int Transpose_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=Transpose(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION Transpose_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), R=RTRN(TReturn_TMatrix);
  int i, j;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(X)-1; i >= 0; i--)
      for (j=ColM(X)-1; j >= 0; j--)
	if ((tmp=fabs(ElementM(X,i,j)-ElementM(R,j,i))) > err) err=tmp;

  return err;
}

//=== IdentityMatrix()
int IdentityMatrix_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=IdentityMatrix(ARG(TArg_TMatrix,0),ARG(TArg_int_size,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION IdentityMatrix_T::ResultOK(void)
{
  return IsIdentity(RTRN(TReturn_TMatrix));
}

//=== DiagonalMatrix()
int DiagonalMatrix_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=DiagonalMatrix(ARG(TArg_TMatrix,0),ARG(TArg_TVector,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION DiagonalMatrix_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix R=RTRN(TReturn_TMatrix);
  TVector X=COPY(TArg_TVector,1);
  int i, j;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	if (i == j)
	  { if ((tmp=fabs(ElementM(R,i,i)-ElementV(X,i))) > err) err=tmp; }
	else
	  { if ((tmp=fabs(ElementM(R,i,j))) > err) err=tmp; }

  return err;
}
void DiagonalMatrix_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[2]=MIN(correct_sizes[0],correct_sizes[1]);
}
void DiagonalMatrix_T::MakeSizeInvalid(int i)
{
  if (i < 2)
    {
      if (actual_sizes[2] > 1)
	actual_sizes[i]=(rand() % (actual_sizes[2] - 1)) + 1;
      else
	actual_sizes[i]=actual_sizes[2]+1;
    }
  else
    TArgList::MakeSizeInvalid(i);
}
int DiagonalMatrix_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  return (actual_sizes[2] !=  MIN(actual_sizes[0],actual_sizes[1])) ? 0 : 1;
}

//=== AbsV()
int AbsV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=AbsV(ARG(TArg_TVector,0),ARG(TArg_TVector,1));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION AbsV_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector X=COPY(TArg_TVector,1), R=RTRN(TReturn_TVector);
  int i;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(X)-1; i >= 0; i--)
      if ((tmp=fabs(ElementV(R,i)-fabs(ElementV(X,i)))) > err) err=tmp;

  return err;
}

//=== AbsM()
int AbsM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=AbsM(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION AbsM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), R=RTRN(TReturn_TMatrix);
  int i, j;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(X)-1; i >= 0; i--)
      for (j=ColM(X)-1; j >= 0; j--)
	if ((tmp=fabs(ElementM(R,i,j)-fabs(ElementM(X,i,j)))) > err) err=tmp;

  return err;
}

//=== MinusV()
int MinusV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=MinusV(ARG(TArg_TVector,0),ARG(TArg_TVector,1));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION MinusV_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector X=COPY(TArg_TVector,1), R=RTRN(TReturn_TVector);
  int i;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(X)-1; i >= 0; i--)
      if ((tmp=fabs(ElementV(R,i) + ElementV(X,i))) > err) err=tmp;

  return err;
}

//=== MinusM()
int MinusM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=MinusM(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION MinusM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), R=RTRN(TReturn_TMatrix);
  int i, j;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(X)-1; i >= 0; i--)
      for (j=ColM(X)-1; j >= 0; j--)
	if ((tmp=fabs(ElementM(R,i,j) + ElementM(X,i,j))) > err) err=tmp;

  return err;
}

//=== InsertSubMatrix()
int InsertSubMatrix_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=InsertSubMatrix(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_int_size,2),ARG(TArg_int_size,3),
					ARG(TArg_int_size,4),ARG(TArg_int_size,5),ARG(TArg_int_size,6),ARG(TArg_int_size,7));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION InsertSubMatrix_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix R=RTRN(TReturn_TMatrix), X=COPY(TArg_TMatrix,1);
  int i, j, bbr=COPY(TArg_int_size,2), bbc=COPY(TArg_int_size,3),
    br=COPY(TArg_int_size,4), bc=COPY(TArg_int_size,5),  r=COPY(TArg_int_size,6), c=COPY(TArg_int_size,7);

  if (!R)
    err=-1.0;
  else
    for (i=r-1; i >= 0; i--)
      for (j=c-1; j >= 0; j--)
	if ((tmp=fabs(ElementM(R,bbr+i,bbc+j)-ElementM(X,br+i,bc+j))) > err) err=tmp;

  return err;
}
void InsertSubMatrix_T::ComputeCorrectSizes(void)
{
  int m;
  TArgList::ComputeCorrectSizes();
  correct_sizes[4]=(correct_sizes[0] > 1) ? (rand() % (correct_sizes[0] - 1)) + 1 : 0;
  correct_sizes[5]=(correct_sizes[1] > 1) ? (rand() % (correct_sizes[1] - 1)) + 1 : 0;
  correct_sizes[6]=(correct_sizes[2] > 1) ? (rand() % (correct_sizes[2] - 1)) + 1 : 0;
  correct_sizes[7]=(correct_sizes[3] > 1) ? (rand() % (correct_sizes[3] - 1)) + 1 : 0;
  m=MIN(correct_sizes[0] - correct_sizes[4],correct_sizes[2] - correct_sizes[6]);
  correct_sizes[8]=(m > 0) ? (rand() % m) + 1 : 1;
  m=MIN(correct_sizes[1] - correct_sizes[5],correct_sizes[3] - correct_sizes[7]);
  correct_sizes[9]=(m > 0) ? (rand() % m) + 1 : 1;
}
void InsertSubMatrix_T::MakeSizeInvalid(int i)
{
  int j;
  switch (i)
    {
    case 0:
      if (actual_sizes[4] + actual_sizes[8] > 1)
	actual_sizes[0]=(rand() % (actual_sizes[4] + actual_sizes[8] - 1)) + 1;
      break;
    case 1:
      if (actual_sizes[5] + actual_sizes[9] > 1)
	actual_sizes[1]=(rand() % (actual_sizes[5] + actual_sizes[9] - 1)) + 1;
      break;
    case 2:
      if (actual_sizes[6] + actual_sizes[8] > 1)
	actual_sizes[2]=(rand() % (actual_sizes[6] + actual_sizes[8] - 1)) + 1;
    case 3:
      if (actual_sizes[7] + actual_sizes[9] > 1)
	actual_sizes[3]=(rand() % (actual_sizes[7] + actual_sizes[9] - 1)) + 1;
      break;
    case 4:
      actual_sizes[4]=actual_sizes[0]-actual_sizes[8] + 1 + (rand() % 3);
      break;
    case 5:
      actual_sizes[5]=actual_sizes[1]-actual_sizes[9] + 1 + (rand() % 3);
      break;
    case 6:
      actual_sizes[6]=actual_sizes[2]-actual_sizes[8] + 1 + (rand() % 3);
      break;
    case 7:
      actual_sizes[7]=actual_sizes[3]-actual_sizes[9] + 1 + (rand() % 3);
      break;
    case 8:
      j=rand() % 2;
      actual_sizes[8]=actual_sizes[2*j]-actual_sizes[4+2*j] + 1 + (rand() % 3);
      break;
    case 9:
      j=rand() % 2;
      actual_sizes[9]=actual_sizes[1+2*j]-actual_sizes[5+2*j] + 1 + (rand() % 3);
      break;
    }
}
int InsertSubMatrix_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  if (actual_sizes[0] < actual_sizes[4] + actual_sizes[8]) return 0;
  if (actual_sizes[1] < actual_sizes[5] + actual_sizes[9]) return 0;
  if (actual_sizes[2] < actual_sizes[6] + actual_sizes[8]) return 0;
  if (actual_sizes[3] < actual_sizes[7] + actual_sizes[9]) return 0;
  return 1;
}
void InsertSubMatrix_T::DefaultTestSizes()
{
  int ts[3]={1,7,10};
  SetTestSizes(3,ts);
}
int InsertSubMatrix_T::ArgumentsError(void)
{
  int err=TFunction::ArgumentsError();
  if (dynamic_cast<TArg_pointer*>(args[0])->address() == dynamic_cast<TArg_pointer*>(args[1])->address()) err|=ARG_ERR_GENERAL;
  return err;
}


//=== InsertColumnVector()
int InsertColumnVector_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=InsertColumnVector(ARG(TArg_TMatrix,0),ARG(TArg_TVector,1),ARG(TArg_int_size,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION InsertColumnVector_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix R=RTRN(TReturn_TMatrix);
  TVector X=COPY(TArg_TVector,1);
  int i, col=COPY(TArg_int_size,2);

  if (!R)
    err=-1.0;
  else
    for (i=DimV(X)-1; i >= 0; i--)
      if ((tmp=fabs(ElementM(R,i,col)-ElementV(X,i))) > err) err=tmp;

  return err;
}
void InsertColumnVector_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[3]=rand() % correct_sizes[1];
}
void InsertColumnVector_T::MakeSizeInvalid(int i)
{
  switch(i)
    {
    case 1:
      if (actual_sizes[3] > 0)
	actual_sizes[1]=actual_sizes[3];
      break;
    case 3:
      actual_sizes[3]=actual_sizes[1] + (rand() % 3);
      break;
    default:
      TArgList::MakeSizeInvalid(i);
    }
}
int InsertColumnVector_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  return (0 <= actual_sizes[3]) && (actual_sizes[3] < actual_sizes[1]) ? 1 : 0;
}


//=== InsertRowVector()
int InsertRowVector_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=InsertRowVector(ARG(TArg_TMatrix,0),ARG(TArg_TVector,1),ARG(TArg_int_size,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION InsertRowVector_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix R=RTRN(TReturn_TMatrix);
  TVector X=COPY(TArg_TVector,1);
  int j, row=COPY(TArg_int_size,2);

  if (!R)
    err=-1.0;
  else
    for (j=DimV(X)-1; j >= 0; j--)
      if ((tmp=fabs(ElementM(R,row,j)-ElementV(X,j))) > err) err=tmp;

  return err;
}
void InsertRowVector_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[3]=rand() % correct_sizes[0];
}
void InsertRowVector_T::MakeSizeInvalid(int i)
{
  switch(i)
    {
    case 0:
      if (actual_sizes[3] > 0)
	actual_sizes[0]=actual_sizes[3];
      break;
    case 3:
      actual_sizes[3]=actual_sizes[0] + (rand() % 3);
      break;
    default:
      TArgList::MakeSizeInvalid(i);
    }
}
int InsertRowVector_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  return (0 <= actual_sizes[3]) && (actual_sizes[3] < actual_sizes[0]) ? 1 : 0;
}

//=== SubVector()
int SubVector_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=SubVector(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_int_size,2),ARG(TArg_int_size,3));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION SubVector_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector R=RTRN(TReturn_TVector), X=COPY(TArg_TVector,1);
  int i, b=COPY(TArg_int_size,2);

  if (!R)
    err=-1.0;
  else
    for (i=DimV(R)-1; i >= 0; i--)
      if ((tmp=fabs(ElementV(R,i)-ElementV(X,i+b))) > err) err=tmp;

  return err;
}
void SubVector_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[1]=correct_sizes[2] + correct_sizes[3] + (rand() % 3);
}
void SubVector_T::MakeSizeInvalid(int i)
{
  switch (i)
    {
    case 1:
      if (actual_sizes[2] + actual_sizes[3] > 1)
	actual_sizes[1]=(rand() % (actual_sizes[2] + actual_sizes[3] - 1)) + 1;
      break;
    case 2:
      actual_sizes[2]=actual_sizes[1]-actual_sizes[3] + 1 + (rand() % 3);
      break;
    default:
      TArgList::MakeSizeInvalid(i);
    }
}
int SubVector_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  return (actual_sizes[1] < actual_sizes[2] + actual_sizes[3]) ? 0 : 1;
}


//=== SubMatrix()
int SubMatrix_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=SubMatrix(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_int_size,2),
				  ARG(TArg_int_size,3),ARG(TArg_int_size,4),ARG(TArg_int_size,5));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION SubMatrix_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix R=RTRN(TReturn_TMatrix), X=COPY(TArg_TMatrix,1);
  int i, j, br=COPY(TArg_int_size,2), bc=COPY(TArg_int_size,3);

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	if ((tmp=fabs(ElementM(R,i,j)-ElementM(X,i+br,j+bc))) > err) err=tmp;

  return err;
}
void SubMatrix_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[2]=correct_sizes[4] + correct_sizes[6] + (rand() % 3);
  correct_sizes[3]=correct_sizes[5] + correct_sizes[7] + (rand() % 3);
}
void SubMatrix_T::MakeSizeInvalid(int i)
{
  switch (i)
    {
    case 2:
      if (actual_sizes[4] + actual_sizes[6] > 1)
	actual_sizes[2]=(rand() % (actual_sizes[4] + actual_sizes[6] - 1)) + 1;
      break;
    case 3:
      if (actual_sizes[5] + actual_sizes[7] > 1)
	actual_sizes[3]=(rand() % (actual_sizes[5] + actual_sizes[7] - 1)) + 1;
      break;
    case 4:
      actual_sizes[4]=actual_sizes[2]-actual_sizes[6] + 1 + (rand() % 3);
    case 5:
      actual_sizes[5]=actual_sizes[3]-actual_sizes[7] + 1 + (rand() % 3);
      break;
    default:
      TArgList::MakeSizeInvalid(i);
    }
}
int SubMatrix_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  if (actual_sizes[2] < actual_sizes[4] + actual_sizes[6]) return 0;
  if (actual_sizes[3] < actual_sizes[5] + actual_sizes[7]) return 0;
  return 1;
}


//=== ColumnVector()
int ColumnVector_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=ColumnVector(ARG(TArg_TVector,0),ARG(TArg_TMatrix,1),ARG(TArg_int_size,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION ColumnVector_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector R=RTRN(TReturn_TVector);
  TMatrix X=COPY(TArg_TMatrix,1);
  int i, col=COPY(TArg_int_size,2);

  if (!R)
    err=-1.0;
  else
    for (i=DimV(R)-1; i >= 0; i--)
      if ((tmp=fabs(ElementV(R,i)-ElementM(X,i,col))) > err) err=tmp;

  return err;
}
void ColumnVector_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[3]=rand() % correct_sizes[2];
}
void ColumnVector_T::MakeSizeInvalid(int i)
{
  if (i == 3)
    actual_sizes[3]=actual_sizes[2] + (rand() % 2);
  else
    TArgList::MakeSizeInvalid(i);
}
int ColumnVector_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  return ((0 <= actual_sizes[3]) && (actual_sizes[3] < actual_sizes[2])) ? 1 : 0;
}

//=== RowVector()
int RowVector_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=RowVector(ARG(TArg_TVector,0),ARG(TArg_TMatrix,1),ARG(TArg_int_size,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION RowVector_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector R=RTRN(TReturn_TVector);
  TMatrix X=COPY(TArg_TMatrix,1);
  int j, row=COPY(TArg_int_size,2);

  if (!R)
    err=-1.0;
  else
    for (j=DimV(R)-1; j >= 0; j--)
      if ((tmp=fabs(ElementV(R,j)-ElementM(X,row,j))) > err) err=tmp;

  return err;
}
void RowVector_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[3]=rand() % correct_sizes[1];
}
void RowVector_T::MakeSizeInvalid(int i)
{
  if (i == 3)
    actual_sizes[3]=actual_sizes[1] + (rand() % 2);
  else
    TArgList::MakeSizeInvalid(i);
}
int RowVector_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  return ((0 <= actual_sizes[3]) && (actual_sizes[3] < actual_sizes[1])) ? 1 : 0;
}

//=== ColumnMatrix()
int ColumnMatrix_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ColumnMatrix(ARG(TArg_TMatrix,0),ARG(TArg_TVector,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ColumnMatrix_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix R=RTRN(TReturn_TMatrix);
  TVector X=COPY(TArg_TVector,1);
  int i;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      if ((tmp=fabs(ElementM(R,i,0)-ElementV(X,i))) > err) err=tmp;

  return err;
}
void ColumnMatrix_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[1]=1;
}
void ColumnMatrix_T::MakeSizeInvalid(int i)
{
  if (i == 1)
    actual_sizes[1]=2+(rand() % 2);
  else
    TArgList::MakeSizeInvalid(i);
}
int ColumnMatrix_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  if (actual_sizes[1] != 1) return 0;
  return 1;
}

//=== RowMatrix()
int RowMatrix_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=RowMatrix(ARG(TArg_TMatrix,0),ARG(TArg_TVector,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION RowMatrix_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix R=RTRN(TReturn_TMatrix);
  TVector X=COPY(TArg_TVector,1);
  int j;

  if (!R)
    err=-1.0;
  else
    for (j=ColM(R)-1; j >= 0; j--)
      if ((tmp=fabs(ElementM(R,0,j)-ElementV(X,j))) > err) err=tmp;

  return err;
}
void RowMatrix_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[0]=1;
}
void RowMatrix_T::MakeSizeInvalid(int i)
{
  if (i == 0)
    actual_sizes[0]=2+(rand() % 2);
  else
    TArgList::MakeSizeInvalid(i);
}
int RowMatrix_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  if (actual_sizes[0] != 1) return 0;
  return 1;
}

//=== AddVV()
int AddVV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=AddVV(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_TVector,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION AddVV_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector X=COPY(TArg_TVector,1), Y=COPY(TArg_TVector,2), R=RTRN(TReturn_TVector);
  int i;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(X)-1; i >= 0; i--)
      if ((tmp=fabs(ElementV(R,i)-(ElementV(X,i) + ElementV(Y,i)))) > err) err=tmp;

  return err;
}

//=== AddMM()
int AddMM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=AddMM(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION AddMM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(X)-1; i >= 0; i--)
      for (j=ColM(X)-1; j >= 0; j--)
	if ((tmp=fabs(ElementM(R,i,j)-(ElementM(X,i,j) + ElementM(Y,i,j)))) > err) err=tmp;

  return err;
}

//=== SubtractVV()
int SubtractVV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=SubtractVV(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_TVector,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION SubtractVV_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector X=COPY(TArg_TVector,1), Y=COPY(TArg_TVector,2), R=RTRN(TReturn_TVector);
  int i;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(X)-1; i >= 0; i--)
      if ((tmp=fabs(ElementV(R,i)-(ElementV(X,i) - ElementV(Y,i)))) > err) err=tmp;

  return err;
}

//=== SubtractMM()
int SubtractMM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=SubtractMM(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION SubtractMM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(X)-1; i >= 0; i--)
      for (j=ColM(X)-1; j >= 0; j--)
	if ((tmp=fabs(ElementM(R,i,j)-(ElementM(X,i,j) - ElementM(Y,i,j)))) > err) err=tmp;

  return err;
}

//=== ProductSV()
int ProductSV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=ProductSV(ARG(TArg_TVector,0),ARG(TArg_PRECISION,1),ARG(TArg_TVector,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION ProductSV_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp, x=COPY(TArg_PRECISION,1);
  TVector Y=COPY(TArg_TVector,2), R=RTRN(TReturn_TVector);
  int i;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(R)-1; i >= 0; i--)
      if ((tmp=fabs(ElementV(R,i)-(x*ElementV(Y,i)))) > err) err=tmp;

  return err;
}

//=== ProductVS()
int ProductVS_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=ProductVS(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_PRECISION,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION ProductVS_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp, y=COPY(TArg_PRECISION,2);
  TVector X=COPY(TArg_TVector,1), R=RTRN(TReturn_TVector);
  int i;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(R)-1; i >= 0; i--)
      if ((tmp=fabs(ElementV(R,i)-(y*ElementV(X,i)))) > err) err=tmp;

  return err;
}

//=== ProductSM()
int ProductSM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ProductSM(ARG(TArg_TMatrix,0),ARG(TArg_PRECISION,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ProductSM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp, x=COPY(TArg_PRECISION,1);
  TMatrix Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	if ((tmp=fabs(ElementM(R,i,j)-(x*ElementM(Y,i,j)))) > err) err=tmp;

  return err;
}

//=== ProductMS()
int ProductMS_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ProductMS(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_PRECISION,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ProductMS_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp, y=COPY(TArg_PRECISION,2);
  TMatrix X=COPY(TArg_TMatrix,1), R=RTRN(TReturn_TMatrix);
  int i, j;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	if ((tmp=fabs(ElementM(R,i,j)-(y*ElementM(X,i,j)))) > err) err=tmp;

  return err;
}

//=== ProductVM()
int ProductVM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=ProductVM(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION ProductVM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector X=COPY(TArg_TVector,1), R=RTRN(TReturn_TVector);
  TMatrix Y=COPY(TArg_TMatrix,2);
  int i, k;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(R)-1; i >= 0; i--)
      {
	for (tmp=ElementV(R,i), k=RowM(Y)-1; k >= 0; k--) tmp-=ElementV(X,k)*ElementM(Y,k,i);
	if ((tmp=fabs(tmp)) > err) err=tmp;
      }

  return err;
}

//=== ProductMV()
int ProductMV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=ProductMV(ARG(TArg_TVector,0),ARG(TArg_TMatrix,1),ARG(TArg_TVector,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION ProductMV_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector Y=COPY(TArg_TVector,2), R=RTRN(TReturn_TVector);
  TMatrix X=COPY(TArg_TMatrix,1);
  int i, k;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(R)-1; i >= 0; i--)
      {
	for (tmp=ElementV(R,i), k=ColM(X)-1; k >= 0; k--) tmp-=ElementM(X,i,k)*ElementV(Y,k);
	if ((tmp=fabs(tmp)) > err) err=tmp;
      }

  return err;
}

//=== ProductMM()
int ProductMM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ProductMM(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ProductMM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j, k;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	{
	  for (tmp=ElementM(R,i,j), k=ColM(X)-1; k >= 0; k--) tmp-=ElementM(X,i,k)*ElementM(Y,k,j);
	  if ((tmp=fabs(tmp)) > err) err=tmp;
	}

  return err;
}

//=== ProductMU()
int ProductMU_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ProductMU(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ProductMU_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j, k;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	{
	  for (tmp=ElementM(R,i,j), k=ColM(X)-1; k >= 0; k--) tmp-=ElementM(X,i,k)*ElementM(Y,k,j);
	  if ((tmp=fabs(tmp)) > err) err=tmp;
	}

  return err;
}

//=== ProductML()
int ProductML_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ProductML(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ProductML_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j, k;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	{
	  for (tmp=ElementM(R,i,j), k=ColM(X)-1; k >= 0; k--) tmp-=ElementM(X,i,k)*ElementM(Y,k,j);
	  if ((tmp=fabs(tmp)) > err) err=tmp;
	}

  return err;
}

//=== ProductUM()
int ProductUM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ProductUM(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ProductUM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j, k;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	{
	  for (tmp=ElementM(R,i,j), k=ColM(X)-1; k >= 0; k--) tmp-=ElementM(X,i,k)*ElementM(Y,k,j);
	  if ((tmp=fabs(tmp)) > err) err=tmp;
	}

  return err;
}

//=== ProductLM()
int ProductLM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ProductLM(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ProductLM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j, k;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	{
	  for (tmp=ElementM(R,i,j), k=ColM(X)-1; k >= 0; k--) tmp-=ElementM(X,i,k)*ElementM(Y,k,j);
	  if ((tmp=fabs(tmp)) > err) err=tmp;
	}

  return err;
}

//=== TransposeProductMV()
int TransposeProductMV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=TransposeProductMV(ARG(TArg_TVector,0),ARG(TArg_TMatrix,1),ARG(TArg_TVector,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION TransposeProductMV_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector Y=COPY(TArg_TVector,2), R=RTRN(TReturn_TVector);
  TMatrix X=COPY(TArg_TMatrix,1);
  int i, k;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(R)-1; i >= 0; i--)
      {
	for (tmp=ElementV(R,i), k=RowM(X)-1; k >= 0; k--) tmp-=ElementM(X,k,i)*ElementV(Y,k);
	if ((tmp=fabs(tmp)) > err) err=tmp;
      }

  return err;
}

//=== TransposeProductMM()
int TransposeProductMM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=TransposeProductMM(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION TransposeProductMM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j, k;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	{
	  for (tmp=ElementM(R,i,j), k=RowM(X)-1; k >= 0; k--) tmp-=ElementM(X,k,i)*ElementM(Y,k,j);
	  if ((tmp=fabs(tmp)) > err) err=tmp;
	}

  return err;
}

//=== ProductTransposeVM()
int ProductTransposeVM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=ProductTransposeVM(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION ProductTransposeVM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector X=COPY(TArg_TVector,1), R=RTRN(TReturn_TVector);
  TMatrix Y=COPY(TArg_TMatrix,2);
  int i, k;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(R)-1; i >= 0; i--)
      {
	for (tmp=ElementV(R,i), k=ColM(Y)-1; k >= 0; k--) tmp-=ElementV(X,k)*ElementM(Y,i,k);
	if ((tmp=fabs(tmp)) > err) err=tmp;
      }

  return err;
}

//=== ProductTransposeMM()
int ProductTransposeMM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ProductTransposeMM(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ProductTransposeMM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j, k;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	{
	  for (tmp=ElementM(R,i,j), k=ColM(X)-1; k >= 0; k--) tmp-=ElementM(X,i,k)*ElementM(Y,j,k);
	  if ((tmp=fabs(tmp)) > err) err=tmp;
	}

  return err;
}

//=== ProductInverseVM()
int ProductInverseVM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=ProductInverseVM(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION ProductInverseVM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector X=COPY(TArg_TVector,1), R=RTRN(TReturn_TVector);
  TMatrix Y=COPY(TArg_TMatrix,2);
  int i, k;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(R)-1; i >= 0; i--)
      {
	for (tmp=ElementV(X,i), k=RowM(Y)-1; k >= 0; k--) tmp-=ElementV(R,k)*ElementM(Y,k,i);
	if ((tmp=fabs(tmp)) > err) err=tmp;
      }

  return err;
}

//=== ProductInverseMM()
int ProductInverseMM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ProductInverseMM(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ProductInverseMM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j, k;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	{
	  for (tmp=ElementM(X,i,j), k=RowM(Y)-1; k >= 0; k--) tmp-=ElementM(R,i,k)*ElementM(Y,k,j);
	  if ((tmp=fabs(tmp)) > err) err=tmp;
	}

  return err;
}

//=== ProductInverseVU()
int ProductInverseVU_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=ProductInverseVU(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION ProductInverseVU_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector X=COPY(TArg_TVector,1), R=RTRN(TReturn_TVector);
  TMatrix Y=COPY(TArg_TMatrix,2);
  int i, k;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(R)-1; i >= 0; i--)
      {
	for (tmp=ElementV(X,i), k=RowM(Y)-1; k >= 0; k--) tmp-=ElementV(R,k)*ElementM(Y,k,i);
	if ((tmp=fabs(tmp)) > err) err=tmp;
      }

  return err;
}

//=== ProductInverseMU()
int ProductInverseMU_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ProductInverseMU(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ProductInverseMU_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j, k;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	{
	  for (tmp=ElementM(X,i,j), k=RowM(Y)-1; k >= 0; k--) tmp-=ElementM(R,i,k)*ElementM(Y,k,j);
	  if ((tmp=fabs(tmp)) > err) err=tmp;
	}

  return err;
}

//=== ProductInverseVL()
int ProductInverseVL_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=ProductInverseVL(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION ProductInverseVL_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector X=COPY(TArg_TVector,1), R=RTRN(TReturn_TVector);
  TMatrix Y=COPY(TArg_TMatrix,2);
  int i, k;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(R)-1; i >= 0; i--)
      {
	for (tmp=ElementV(X,i), k=RowM(Y)-1; k >= 0; k--) tmp-=ElementV(R,k)*ElementM(Y,k,i);
	if ((tmp=fabs(tmp)) > err) err=tmp;
      }

  return err;
}

//=== ProductInverseML()
int ProductInverseML_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ProductInverseML(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ProductInverseML_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j, k;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	{
	  for (tmp=ElementM(X,i,j), k=RowM(Y)-1; k >= 0; k--) tmp-=ElementM(R,i,k)*ElementM(Y,k,j);
	  if ((tmp=fabs(tmp)) > err) err=tmp;
	}

  return err;
}

//=== InverseProductMV()
int InverseProductMV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=InverseProductMV(ARG(TArg_TVector,0),ARG(TArg_TMatrix,1),ARG(TArg_TVector,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION InverseProductMV_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector Y=COPY(TArg_TVector,2), R=RTRN(TReturn_TVector);
  TMatrix X=COPY(TArg_TMatrix,1);
  int i, k;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(R)-1; i >= 0; i--)
      {
	for (tmp=ElementV(Y,i), k=ColM(X)-1; k >= 0; k--) tmp-=ElementM(X,i,k)*ElementV(R,k);
	if ((tmp=fabs(tmp)) > err) err=tmp;
      }

  return err;
}

//=== InverseProductMM()
int InverseProductMM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=InverseProductMM(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION InverseProductMM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j, k;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	{
	  for (tmp=ElementM(Y,i,j), k=ColM(X)-1; k >= 0; k--) tmp-=ElementM(X,i,k)*ElementM(R,k,j);
	  if ((tmp=fabs(tmp)) > err) err=tmp;
	}

  return err;
}

//=== InverseProductUV()
int InverseProductUV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=InverseProductUV(ARG(TArg_TVector,0),ARG(TArg_TMatrix,1),ARG(TArg_TVector,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION InverseProductUV_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector Y=COPY(TArg_TVector,2), R=RTRN(TReturn_TVector);
  TMatrix X=COPY(TArg_TMatrix,1);
  int i, k;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(R)-1; i >= 0; i--)
      {
	for (tmp=ElementV(Y,i), k=ColM(X)-1; k >= 0; k--) tmp-=ElementM(X,i,k)*ElementV(R,k);
	if ((tmp=fabs(tmp)) > err) err=tmp;
      }

  return err;
}

//=== InverseProductUM()
int InverseProductUM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=InverseProductUM(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION InverseProductUM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j, k;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	{
	  for (tmp=ElementM(Y,i,j), k=ColM(X)-1; k >= 0; k--) tmp-=ElementM(X,i,k)*ElementM(R,k,j);
	  if ((tmp=fabs(tmp)) > err) err=tmp;
	}

  return err;
}

//=== InverseProductLV()
int InverseProductLV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=InverseProductLV(ARG(TArg_TVector,0),ARG(TArg_TMatrix,1),ARG(TArg_TVector,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION InverseProductLV_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector Y=COPY(TArg_TVector,2), R=RTRN(TReturn_TVector);
  TMatrix X=COPY(TArg_TMatrix,1);
  int i, k;

  if (!R)
    err=-1.0;
  else
    for (i=DimV(R)-1; i >= 0; i--)
      {
	for (tmp=ElementV(Y,i), k=ColM(X)-1; k >= 0; k--) tmp-=ElementM(X,i,k)*ElementV(R,k);
	if ((tmp=fabs(tmp)) > err) err=tmp;
      }

  return err;
}

//=== InverseProductLM()
int InverseProductLM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=InverseProductLM(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION InverseProductLM_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2), R=RTRN(TReturn_TMatrix);
  int i, j, k;

  if (!R)
    err=-1.0;
  else
    for (i=RowM(R)-1; i >= 0; i--)
      for (j=ColM(R)-1; j >= 0; j--)
	{
	  for (tmp=ElementM(Y,i,j), k=ColM(X)-1; k >= 0; k--) tmp-=ElementM(X,i,k)*ElementM(R,k,j);
	  if ((tmp=fabs(tmp)) > err) err=tmp;
	}

  return err;
}

//=== Inverse_LU()
int Inverse_LU_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=Inverse_LU(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION Inverse_LU_T::ResultOK(void)
{
  PRECISION err=0.0;
  TMatrix X=COPY(TArg_TMatrix,1), R=RTRN(TReturn_TMatrix), I;

  if (!R)
    err=-1.0;
  else
    {
      I=ProductMM((TMatrix)NULL,X,R);
      err=IsIdentity(I);
      FreeMatrix(I);
    }

  return err;
}

//=== Inverse_SVD()
int Inverse_SVD_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=Inverse_SVD(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION Inverse_SVD_T::ResultOK(void)
{
  PRECISION err=0.0;
  TMatrix X=COPY(TArg_TMatrix,1), R=RTRN(TReturn_TMatrix), I;

  if (!R)
    err=-1.0;
  else
    {
      I=ProductMM((TMatrix)NULL,X,R);
      err=IsIdentity(I);
      FreeMatrix(I);
    }

  return err;
}

//=== Inverse_Cholesky()
int Inverse_Cholesky_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=Inverse_Cholesky(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION Inverse_Cholesky_T::ResultOK(void)
{
  PRECISION err=0.0;
  TMatrix X=COPY(TArg_TMatrix,1), R=RTRN(TReturn_TMatrix), I;

  if (!R)
    err=-1.0;
  else
    {
      I=ProductMM((TMatrix)NULL,X,R);
      err=IsIdentity(I);
      FreeMatrix(I);
    }

  return err;
}

//=== Inverse_LT()
int Inverse_LT_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=Inverse_LT(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION Inverse_LT_T::ResultOK(void)
{
  PRECISION err=0.0;
  TMatrix X=COPY(TArg_TMatrix,1), R=RTRN(TReturn_TMatrix), I;

  if (!R)
    err=-1.0;
  else
    {
      I=ProductMM((TMatrix)NULL,X,R);
      err=IsIdentity(I);
      FreeMatrix(I);
    }

  return err;
}

//=== Inverse_UT()
int Inverse_UT_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=Inverse_UT(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION Inverse_UT_T::ResultOK(void)
{
  PRECISION err=0.0;
  TMatrix X=COPY(TArg_TMatrix,1), R=RTRN(TReturn_TMatrix), I;

  if (!R)
    err=-1.0;
  else
    {
      I=ProductMM((TMatrix)NULL,X,R);
      err=IsIdentity(I);
      FreeMatrix(I);
    }

  return err;
}

//=== GeneralizedInverse()
int GeneralizedInverse_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=GeneralizedInverse(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION GeneralizedInverse_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=COPY(TArg_TMatrix,1), R=RTRN(TReturn_TMatrix), RX, XR, XRX, RXR;

  if (!R)
    err=-1.0;
  else
    {
      if ((err=IsSymmetric(XR=ProductMM((TMatrix)NULL,X,R))) >= 0.0)
	{
	  if ((tmp=IsSymmetric(RX=ProductMM((TMatrix)NULL,R,X))) >= 0.0)
	    {
	      if (tmp > err) err=tmp;
	      if ((tmp=EqualMatrices(X,XRX=ProductMM((TMatrix)NULL,X,RX))) >= 0)
		{
		  if (tmp > err) err=tmp;
		  if ((tmp=EqualMatrices(R,RXR=ProductMM((TMatrix)NULL,R,XR))) >= 0)
		    {
		      if (tmp > err) err=tmp;
		    }
		  else
		    err=tmp;
		  FreeMatrix(RXR);
		}
	      FreeMatrix(XRX);
	    }
	  else
	    err=tmp;
	  FreeMatrix(RX);
	}
      FreeMatrix(XR);
    }

  return err;
}

//=== SVD()
int SVD_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_int)=SVD(ARG(TArg_TMatrix,0),ARG(TArg_TVector,1),ARG(TArg_TMatrix,2),ARG(TArg_TMatrix,3));
  SetReturnOwner();
  return RTRN(TReturn_int);
}
PRECISION SVD_T::ResultOK(void)
{
  PRECISION err=0.0;
  TVector d;
  TMatrix U=ARG(TArg_TMatrix,0), V=ARG(TArg_TMatrix,2), A=COPY(TArg_TMatrix,3), D, UD, UDVprime, X;
  int min=(ColM(A) < RowM(A)) ? ColM(A) : RowM(A), fV=0, fU=0;

  if (!RTRN(TReturn_int))
    err=-1.0;
  else
    {
      if (!U)
	{
	  fU=1;
	  U=CreateMatrix(RowM(A),min);
	}
      if (!V)
	{
	  fV=1;
	  V=CreateMatrix(ColM(A),min);
	}
      if (fU || fV)
	{
	  d=CreateVector(min);
	  X=EquateMatrix((TMatrix)NULL,A);
	  SVD(fU ? U : (TMatrix)NULL,d,fV ? V : (TMatrix)NULL,X);
	  FreeVector(d);
	  FreeMatrix(X);
	}
      d=ARG(TArg_TVector,1);
      DiagonalMatrix(D=CreateMatrix(ColM(U),ColM(V)),d);
      UDVprime=ProductTransposeMM((TMatrix)NULL,UD=ProductMM((TMatrix)NULL,U,D),V);
      err=EqualMatrices(UDVprime,A);
      FreeMatrix(UDVprime);
      FreeMatrix(UD);
      FreeMatrix(D);
      if (fU) FreeMatrix(U);
      if (fV) FreeMatrix(V);
    }

  return err;
}
void SVD_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[2]=MIN(correct_sizes[5],correct_sizes[6]);
  if (correct_sizes[1])
    correct_sizes[1]=correct_sizes[4]=correct_sizes[2];
  else
    {
      correct_sizes[1]=correct_sizes[5];
      correct_sizes[4]=correct_sizes[6];
    }
}
int SVD_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  int m=MIN(actual_sizes[5],actual_sizes[6]);
  return ((actual_sizes[2] != m) || ((actual_sizes[1] != m) && (actual_sizes[1] != actual_sizes[5]))
	  || ((actual_sizes[4] != m) && (actual_sizes[4] != actual_sizes[6])))  ? 0 : 1;
}
int SVD_T::ArgumentsError(void)
{
  int err=TFunction::ArgumentsError();
  if (dynamic_cast<TArg_pointer*>(args[0])->address() == dynamic_cast<TArg_pointer*>(args[2])->address()) err|=ARG_ERR_GENERAL;
  return err;
}
void SVD_T::DefaultTestSizes(void)
{
  int ts0[3]={2,0,1}, ts1[6]={5,1,2,3,7,10}, *ts[3]={ts0,ts1,ts1};
  SetTestSizes(ts);
}

//=== QR()
int QR_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_int)=QR(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_int);
}
PRECISION QR_T::ResultOK(void)
{
  PRECISION err=0.0;
  TMatrix Q=ARG(TArg_TMatrix,0), R=ARG(TArg_TMatrix,1), A=COPY(TArg_TMatrix,2), X, Y, Z;
  int fQ=0;

  if (!RTRN(TReturn_int))
    err=-1.0;
  else
    {
      if (!Q)
	{
	  fQ=1;
	  Q=CreateMatrix(RowM(A),RowM(R));
          X=CreateMatrix(RowM(R),ColM(R));
	  Y=EquateMatrix((TMatrix)NULL,A);
	  QR(Q,R,A);
	  FreeMatrix(X);
	  FreeMatrix(Y);
	}
      Z=ProductMM((TMatrix)NULL,Q,R);
      err=EqualMatrices(Z,A);
      FreeMatrix(Z);
      if (fQ) FreeMatrix(Q);
    }

  return err;
}
void QR_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[2]=correct_sizes[1]=correct_sizes[1] ? MIN(correct_sizes[4],correct_sizes[5]) : correct_sizes[4]; 
}
int QR_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  return ((actual_sizes[1] != actual_sizes[2]) || 
	  ((actual_sizes[1] != actual_sizes[4]) && (actual_sizes[1] !=MIN(actual_sizes[4],actual_sizes[5])))) ? 0 : 1;
}
int QR_T::ArgumentsError(void)
{
  int err=TFunction::ArgumentsError();
  if (dynamic_cast<TArg_pointer*>(args[0])->address() == dynamic_cast<TArg_pointer*>(args[1])->address()) err|=ARG_ERR_GENERAL;
  return err;
}
void QR_T::DefaultTestSizes(void)
{
  int ts0[3]={2,0,1}, ts1[6]={5,1,2,3,7,10}, *ts[3]={ts0,ts1,ts1};
  SetTestSizes(ts);
}

//=== CholeskyUT()
int CholeskyUT_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=CholeskyUT(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1));
  SetReturnOwner();
 return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION CholeskyUT_T::ResultOK(void)
{
  PRECISION err=0.0;
  TMatrix X=COPY(TArg_TMatrix,1), R=RTRN(TReturn_TMatrix), Y;

  if (!R)
    err=-1.0;
  else
    {
      Y=TransposeProductMM((TMatrix)NULL,R,R);
      err=EqualMatrices(X,Y);
      FreeMatrix(Y);
    }

  return err;
}

//=== CholeskyLT()
int CholeskyLT_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=CholeskyLT(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1));
  SetReturnOwner();
 return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION CholeskyLT_T::ResultOK(void)
{
  PRECISION err=0.0;
  TMatrix X=COPY(TArg_TMatrix,1), R=RTRN(TReturn_TMatrix), Y;

  if (!R)
    err=-1.0;
  else
    {
      Y=TransposeProductMM((TMatrix)NULL,R,R);
      err=EqualMatrices(X,Y);
      FreeMatrix(Y);
    }

  return err;
}

//=== LU()
int LU_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_int)=LU(ARG(TArg_TPermutation,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
 return RTRN(TReturn_int);
}
PRECISION LU_T::ResultOK(void)
{
  PRECISION err=0.0;
  TMatrix A=COPY(TArg_TMatrix,2), LU=ARG(TArg_TMatrix,1), L, U;
  TPermutation P=ARG(TArg_TPermutation,0);
  int i, j, q;

  if (!RTRN(TReturn_int))
    err=-1.0;
  else
    {
      q=(RowM(LU) < ColM(LU)) ? RowM(LU) : ColM(LU);
      L=SubMatrix((TMatrix)NULL,LU,0,0,RowM(LU),q);
      U=SubMatrix((TMatrix)NULL,LU,0,0,q,ColM(LU));
      for (i=q-1; i >= 0; i--)
	{
	  ElementM(L,i,i)=1.0;
	  for (j=i+1; j < q; j++) ElementM(L,i,j)=0.0;
	  for (j=i-1; j >= 0; j--) ElementM(U,i,j)=0.0;
	}
      LU=ProductMM((TMatrix)NULL,L,U);
      ProductPM(LU,P,LU);

      err=EqualMatrices(LU,A);
      FreeMatrix(LU);
      FreeMatrix(L);
      FreeMatrix(U);
    }

  return err;
}

//=== LU_SolveCol()
int LU_SolveCol_T::CallFunction(void)
{
  // Generate LU decompostion
  LU(ARG(TArg_TPermutation,3),ARG(TArg_TMatrix,2),ARG(TArg_TMatrix,2));
  EquateMatrix(COPY(TArg_TMatrix,2),ARG(TArg_TMatrix,2));
  EquatePermutation(COPY(TArg_TPermutation,3),ARG(TArg_TPermutation,3));

  dw_ClearError();
  RTRN(TReturn_TVector)=LU_SolveCol(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_TMatrix,2),ARG(TArg_TPermutation,3));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION LU_SolveCol_T::ResultOK(void)
{
  PRECISION err=0.0;
  TMatrix LU=COPY(TArg_TMatrix,2), L, U;
  TVector R=RTRN(TReturn_TVector), X=COPY(TArg_TVector,1), v;
  TPermutation P=COPY(TArg_TPermutation,3);
  int i, j, q;

  if (!R)
    err=-1.0;
  else
    {
      q=(RowM(LU) < ColM(LU)) ? RowM(LU) : ColM(LU);
      L=SubMatrix((TMatrix)NULL,LU,0,0,RowM(LU),q);
      U=SubMatrix((TMatrix)NULL,LU,0,0,q,ColM(LU));
      for (i=q-1; i >= 0; i--)
	{
	  ElementM(L,i,i)=1.0;
	  for (j=i+1; j < q; j++) ElementM(L,i,j)=0.0;
	  for (j=i-1; j >= 0; j--) ElementM(U,i,j)=0.0;
	}
      LU=ProductMM((TMatrix)NULL,L,U);
      ProductPM(LU,P,LU);

      v=ProductMV((TVector)NULL,LU,R);
      err=EqualVectors(v,X);
      FreeVector(v);
      FreeMatrix(LU);
      FreeMatrix(L);
      FreeMatrix(U);
    }

  return err;
}

//=== LU_SolveRow()
int LU_SolveRow_T::CallFunction(void)
{
  // Generate LU decompostion
  LU(ARG(TArg_TPermutation,3),ARG(TArg_TMatrix,2),ARG(TArg_TMatrix,2));
  EquateMatrix(COPY(TArg_TMatrix,2),ARG(TArg_TMatrix,2));
  EquatePermutation(COPY(TArg_TPermutation,3),ARG(TArg_TPermutation,3));

  dw_ClearError();
  RTRN(TReturn_TVector)=LU_SolveRow(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_TMatrix,2),ARG(TArg_TPermutation,3));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION LU_SolveRow_T::ResultOK(void)
{
  PRECISION err=0.0;
  TMatrix LU=COPY(TArg_TMatrix,2), L, U;
  TVector R=RTRN(TReturn_TVector), X=COPY(TArg_TVector,1), v;
  TPermutation P=COPY(TArg_TPermutation,3);
  int i, j, q;

  if (!R)
    err=-1.0;
  else
    {
      q=(RowM(LU) < ColM(LU)) ? RowM(LU) : ColM(LU);
      L=SubMatrix((TMatrix)NULL,LU,0,0,RowM(LU),q);
      U=SubMatrix((TMatrix)NULL,LU,0,0,q,ColM(LU));
      for (i=q-1; i >= 0; i--)
	{
	  ElementM(L,i,i)=1.0;
	  for (j=i+1; j < q; j++) ElementM(L,i,j)=0.0;
	  for (j=i-1; j >= 0; j--) ElementM(U,i,j)=0.0;
	}
      LU=ProductMM((TMatrix)NULL,L,U);
      ProductPM(LU,P,LU);

      v=ProductVM((TVector)NULL,R,LU);
      err=EqualVectors(v,X);
      FreeVector(v);
      FreeMatrix(LU);
      FreeMatrix(L);
      FreeMatrix(U);
    }

  return err;
}

//=== Eigenvalue_T()
int Eigenvalues_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_int)=Eigenvalues(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_int);
}
PRECISION Eigenvalues_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TVector u, v;
  TMatrix X, Y, Z;
  int m=RowM(COPY(TArg_TMatrix,2));


  if (!RTRN(TReturn_int))
    err=-1.0;
  else
    {
      Z=EquateMatrix((TMatrix)NULL,COPY(TArg_TMatrix,2));
      X=CreateMatrix(m,m);
      Y=CreateMatrix(m,m);
      u=CreateVector(m);
      v=CreateVector(m);
      if (!Eigen(u,v,X,Y,Z))
	err=-1.0;
      else
	if ((err=EqualVectors(u,ARG(TArg_TVector,0))) >= 0)
	  if ((tmp=EqualVectors(v,ARG(TArg_TVector,1))) < 0)
	    err=tmp;
	  else
	    if (tmp > err) err=tmp;
      FreeMatrix(Z);
      FreeMatrix(Y);
      FreeMatrix(X);
      FreeVector(u);
      FreeVector(v);
    }

  return err;
}
int Eigenvalues_T::ArgumentsError(void)
{
  int err=TFunction::ArgumentsError();
  if (dynamic_cast<TArg_pointer*>(args[0])->address() == dynamic_cast<TArg_pointer*>(args[1])->address()) err|=ARG_ERR_GENERAL;
  return err;
}


//=== Eigen_T()
int Eigen_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_int)=Eigen(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_TMatrix,2),ARG(TArg_TMatrix,3),ARG(TArg_TMatrix,4));
  SetReturnOwner();
  return RTRN(TReturn_int);
}
PRECISION Eigen_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix X=ARG(TArg_TMatrix,2), Y=ARG(TArg_TMatrix,3), Z=COPY(TArg_TMatrix,4),
    U=DiagonalMatrix((TMatrix)NULL,ARG(TArg_TVector,0)), V=DiagonalMatrix((TMatrix)NULL,ARG(TArg_TVector,1)), A, B, C, D, E, F;

  if (!RTRN(TReturn_int))
    err=-1.0;
  else
    {
      A=ProductMM((TMatrix)NULL,X,U);  // ReVec*diag(ReVal)
      B=ProductMM((TMatrix)NULL,X,V);  // ReVec*diag(ImVal)
      C=ProductMM((TMatrix)NULL,Y,U);  // ImVec*diag(ReVal)
      D=ProductMM((TMatrix)NULL,Y,V);  // ImVec*diag(ImVal)
      E=ProductMM((TMatrix)NULL,Z,X);  
      F=ProductMM((TMatrix)NULL,Z,Y);

      SubtractMM(E,E,A);
      AddMM(E,E,D);

      if ((err=IsZeroMatrix(E)) >= 0)
	{
	  SubtractMM(F,F,B);
	  SubtractMM(F,F,C);
	  if (tmp=IsZeroMatrix(F) < 0)
	    err=tmp;
	  else
	    if (tmp > err) err=tmp;
	}

      FreeMatrix(A);
      FreeMatrix(B);
      FreeMatrix(C);
      FreeMatrix(D);
      FreeMatrix(E);
      FreeMatrix(F);
    }

  return err;
}
int Eigen_T::ArgumentsError(void)
{
  int err=TFunction::ArgumentsError();
  if  ((dynamic_cast<TArg_pointer*>(args[0])->address() == dynamic_cast<TArg_pointer*>(args[1])->address()) 
	  || (dynamic_cast<TArg_pointer*>(args[2])->address() == dynamic_cast<TArg_pointer*>(args[3])->address()))
    err|=ARG_ERR_GENERAL;
  return err;
}

//=== NullSpace_T()
int NullSpace_T::CallFunction(void)
{
  // Setup matrix
  TMatrix X=ARG(TArg_TMatrix,0);
  if (X)
    {
      int q=rand() % ((RowM(X) < ColM(X)) ? RowM(X) : ColM(X));
      if (q == 0)
	InitializeMatrix(X,0.0);
      else
	{
	  TMatrix Y, Z;
	  dw_NormalMatrix(Y=CreateMatrix(RowM(X),q));
	  dw_NormalMatrix(Z=CreateMatrix(q,ColM(X)));
	  ProductMM(X,Y,Z);
	  FreeMatrix(Z);
	  FreeMatrix(Y);
	}
      EquateMatrix(COPY(TArg_TMatrix,0),X);
    }

  dw_ClearError();
  RTRN(TReturn_TMatrix)=NullSpace(ARG(TArg_TMatrix,0));
  SetReturnOwner();
  return (dw_GetError() == NO_ERR) ? 1 : 0;
}
PRECISION NullSpace_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix R=RTRN(TReturn_TMatrix), X=COPY(TArg_TMatrix,0), Y;

  if (dw_GetError())
    err=-1.0;
  else
    if (!R)
      err=(Rank_SVD(X) == ColM(X)) ? 0.0 : -1.0;
    else
      if (Rank_SVD(X) != ColM(X) - ColM(R))
	err=-1.0;
      else
	{
	  Y=ProductMM((TMatrix)NULL,X,R);
	  err=IsZeroMatrix(Y);
	  FreeMatrix(Y);
	}

  return err;
}

//=== GeneralizedSchur_Real()
PRECISION GeneralizedSchurDecompositionError(TMatrix S, TMatrix T, TMatrix Q, TMatrix Z, TMatrix A, TMatrix B)
{
  TMatrix X, Y;
  PRECISION err, tmp;
  X=ProductTransposeMM((TMatrix)NULL,S,Z);
  Y=ProductMM((TMatrix)NULL,Q,X);
  if ((err=EqualMatrices(Y,A)) >= 0)
    {
      X=ProductTransposeMM(X,T,Z);
      Y=ProductMM(Y,Q,X);
      if ((tmp=EqualMatrices(Y,B)) < 0)
	err=tmp;
      else
	if (tmp > err) err=tmp;
    }
  FreeMatrix(X);
  FreeMatrix(Y);
  return err;
}
int TArgInc_EqualPointers_GeneralizedSchur_Real::Next(void)
{
  if (i > 1)
    if (!args->IncrementMinimalIndexes())
      return 0;
    else
      i=0;
  if (i >= 0)
    {
      ComputeActualSizes();
      args->Allocate();
      dynamic_cast<TArg_pointer*>(args->arg(i+4))->EquatePointers(dynamic_cast<TArg_pointer*>(args->arg(i)));
      args->Initialize();
      i++;
      return 1;
    }
  return 0;
}
int GeneralizedSchur_Real_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_int)=GeneralizedSchur_Real(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2),ARG(TArg_TMatrix,3),
			    ARG(TArg_TMatrix,4),ARG(TArg_TMatrix,5),ARG(TArg_TVector,6),ARG(TArg_TVector,7),ARG(TArg_TVector,8));
  SetReturnOwner();
  return RTRN(TReturn_int);
}
PRECISION GeneralizedSchur_Real_T::ResultOK(void)
{
  PRECISION err=0.0, tmp;
  TMatrix S=ARG(TArg_TMatrix,0), T=ARG(TArg_TMatrix,1), Q=ARG(TArg_TMatrix,2), Z=ARG(TArg_TMatrix,3),
    A=COPY(TArg_TMatrix,4), B=COPY(TArg_TMatrix,5), AA, BB, SS, TT, QQ, ZZ, SSS, TTT;
  TVector alpha_r, alpha_i, beta;
  int n;

  if (!RTRN(TReturn_int))
    err=-1.0;
  else
    if (!Q && !Z)
      {
	n=RowM(A);
	AA=EquateMatrix((TMatrix)NULL,A);
	BB=EquateMatrix((TMatrix)NULL,B);
	SS=CreateMatrix(n,n);
	TT=CreateMatrix(n,n);
	SSS=CreateMatrix(n,n);
	TTT=CreateMatrix(n,n);
	QQ=CreateMatrix(n,n);
	ZZ=CreateMatrix(n,n);
	alpha_r=CreateVector(n);
	alpha_i=CreateVector(n);
	beta=CreateVector(n);
	GeneralizedSchur_Real(SS,TT,(TMatrix)NULL,(TMatrix)NULL,AA,BB,alpha_r,alpha_i,beta);
	err=EqualMatrices(SS,S);
	if ((tmp=EqualMatrices(TT,T)) > err) err=tmp;
	if (err > SQRT_MACHINE_EPSILON)
	  printf("Unable to compare differing decompositions - %lf\n",err);
	else
	  {
	    SortGeneralizedSchur_Real(SSS,TTT,(TMatrix)NULL,(TMatrix)NULL,S,T,(TMatrix)NULL,(TMatrix)NULL,alpha_r,alpha_i,beta,1);
	    GeneralizedSchur_Real(SS,TT,QQ,ZZ,AA,BB,alpha_r,alpha_i,beta);
	    SortGeneralizedSchur_Real(SS,TT,QQ,ZZ,SS,TT,QQ,ZZ,alpha_r,alpha_i,beta,1);
	    err=GeneralizedSchurDecompositionError(SSS,TTT,QQ,ZZ,A,B);
	  }
	FreeMatrix(AA);
	FreeMatrix(BB);
	FreeMatrix(SS);
	FreeMatrix(TT);
	FreeMatrix(SSS);
	FreeMatrix(TTT);
	FreeMatrix(QQ);
	FreeMatrix(ZZ);
	FreeVector(alpha_r);
	FreeVector(alpha_i);
	FreeVector(beta);
	if (err > SQRT_MACHINE_EPSILON) printf("Error when Q and Z are NULL\n");
      }
    else if (!Q)
      {
	QQ=ProductTransposeMM((TMatrix)NULL,S,Z);
	ProductInverseMM(QQ,A,QQ);
	err=IsOrthogonal(QQ);
	if ((tmp=GeneralizedSchurDecompositionError(S,T,QQ,Z,A,B)) > err) err=tmp;
	FreeMatrix(QQ);
	if (err > SQRT_MACHINE_EPSILON) printf("Q null\n");
      }
    else if (!Z)
      {
	ZZ=ProductMM((TMatrix)NULL,Q,S);
	InverseProductMM(ZZ,ZZ,A);
	Transpose(ZZ,ZZ);
	err=IsOrthogonal(ZZ);
	if ((tmp=GeneralizedSchurDecompositionError(S,T,Q,ZZ,A,B)) > err) err=tmp;
	FreeMatrix(ZZ);
	if (err > SQRT_MACHINE_EPSILON) printf("Z null\n");;
      }
    else
      err=GeneralizedSchurDecompositionError(S,T,Q,Z,A,B);

  return err;
}
void GeneralizedSchur_Real_T::DefaultTestSizes_InvalidNulls(void)
{
  int ts=4;
  SetTestSizes(1,&ts);
}
int GeneralizedSchur_Real_T::TestEqualPointers(int min, int max)
{
  int ts=4;
  if (inc) delete inc;
  inc=((min <= 0) || (max < min)) ? new TArgInc_EqualPointers_GeneralizedSchur_Real(this,1,&ts) 
    : new TArgInc_EqualPointers_GeneralizedSchur_Real(this,min,max);
  return First();
}

//=== ReorderGeneralizedSchur_Real()
int TArgInc_EqualPointers_ReorderGeneralizedSchur_Real::Next(void)
{
  if (i > 3)
    if (!args->IncrementMinimalIndexes())
      return 0;
    else
      i=0;
  if (i >= 0)
    {
      ComputeActualSizes();
      args->Allocate();
      dynamic_cast<TArg_pointer*>(args->arg(i+4))->EquatePointers(dynamic_cast<TArg_pointer*>(args->arg(i)));
      args->Initialize();
      i++;
      return 1;
    }
  return 0;
}
void ReorderGeneralizedSchur_Real_T::Initialize(void)
{
  TFunction::Initialize();

  // Setup GeneralizedSchur decomposition
  int m=dynamic_cast<TArg_TMatrix*>(arg(0))->GetSize(0);
  if ((m > 0) && (m == dynamic_cast<TArg_pInteger*>(arg(8))->GetSize(0)))
    {
      int *as=ARG(TArg_pInteger,8), *cs=COPY(TArg_pInteger,8), VerboseErrors, TerminalErrors, i;
      PRECISION min=1e300, max=0, e;

      FreeMatrix(A); dw_NormalMatrix(A=CreateMatrix(m,m));
      FreeMatrix(B); dw_NormalMatrix(B=CreateMatrix(m,m));
      FreeMatrix(Q); Q=CreateMatrix(m,m);
      FreeMatrix(Z); Z=CreateMatrix(m,m);
      FreeVector(alpha_r); alpha_r=CreateVector(m);
      FreeVector(alpha_i); alpha_i=CreateVector(m);
      FreeVector(beta); beta=CreateVector(m);
 
      VerboseErrors=dw_SetVerboseErrors(0);
      TerminalErrors=dw_SetTerminalErrors(0);
      if (GeneralizedSchur_Real(ARG(TArg_TMatrix,4),ARG(TArg_TMatrix,5),Q,Z,A,B,alpha_r,alpha_i,beta))
	{				
	  EquateMatrix(COPY(TArg_TMatrix,4),ARG(TArg_TMatrix,4));
	  EquateMatrix(COPY(TArg_TMatrix,5),ARG(TArg_TMatrix,5));
	  if (ARG(TArg_TMatrix,6)) EquateMatrix(COPY(TArg_TMatrix,6),EquateMatrix(ARG(TArg_TMatrix,6),Q));
	  if (ARG(TArg_TMatrix,7)) EquateMatrix(COPY(TArg_TMatrix,7),EquateMatrix(ARG(TArg_TMatrix,7),Z));
	  for (i=m-1; i >= 0; i--)
	    {
	      e=sqrt(ElementV(alpha_r,i)*ElementV(alpha_r,i)+ElementV(alpha_i,i)*ElementV(alpha_i,i));
	      e=(fabs(ElementV(beta,i))*1e300 > e) ? e/fabs(ElementV(beta,i)) : 1e300;
	      if (e > max) max=e;
	      if (e < min) min=e;
	    }
	  div=min+(max-min)*dw_uniform_rnd();
	  for (i=m-1; i >= 0; i--) 
	    as[i]=cs[i]=(div*fabs(ElementV(beta,i)) 
			 < sqrt(ElementV(alpha_r,i)*ElementV(alpha_r,i)+ElementV(alpha_i,i)*ElementV(alpha_i,i))) ? 0 : 1;
	}

      dw_SetVerboseErrors(VerboseErrors);
      dw_SetTerminalErrors(TerminalErrors);
    }
}
int ReorderGeneralizedSchur_Real_T::CallFunction(void)
{
  TArg_pInteger *p=dynamic_cast<TArg_pInteger*>(arg(8));
  dw_ClearError();
  if (p->GetArg() && (dynamic_cast<TArg_TMatrix*>(arg(0))->GetSize(0) != p->GetSize(0)))
    {
      dw_Error(SIZE_ERR);
      RTRN(TReturn_int)=0;
    }
  else
    RTRN(TReturn_int)=ReorderGeneralizedSchur_Real(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2),ARG(TArg_TMatrix,3),
				     ARG(TArg_TMatrix,4),ARG(TArg_TMatrix,5),ARG(TArg_TMatrix,6),ARG(TArg_TMatrix,7),
				     ARG(TArg_pInteger,8),ARG(TArg_TVector,9),ARG(TArg_TVector,10),ARG(TArg_TVector,11));
  SetReturnOwner();
  return RTRN(TReturn_int);
}
PRECISION ReorderGeneralizedSchur_Real_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix SS=ARG(TArg_TMatrix,0), TT=ARG(TArg_TMatrix,1), QQ=ARG(TArg_TMatrix,2), ZZ=ARG(TArg_TMatrix,3), X, Y, S, T, SSp, TTp;
  TVector ra=ARG(TArg_TVector,9), ia=ARG(TArg_TVector,10), b=ARG(TArg_TVector,11);
  int i, k, n, fQQ=0, fZZ=0, fra=0, fia=0, fb=0, *select;

  if (!RTRN(TReturn_int))
    err=-1.0;
  else
    {
      n=RowM(A);
      if (!QQ || !ARG(TArg_TMatrix,6))
	{
	  fQQ=1;
	  QQ=CreateMatrix(n,n);
	}
      if (!ZZ || !ARG(TArg_TMatrix,7))
	{
	  fZZ=1;
	  ZZ=CreateMatrix(n,n);
	}
      if (!ra)
	{
	  fra=1;
	  ra=CreateVector(n);
	}
      if (!ia)
	{
	  fia=1;
	  ia=CreateVector(n);
	}
      if (!b)
	{
	  fb=1;
	  b=CreateVector(n);
	}
      if (fQQ || fZZ || fra || fia || fb)
	{
          S=EquateMatrix((TMatrix)NULL,COPY(TArg_TMatrix,4));
	  T=EquateMatrix((TMatrix)NULL,COPY(TArg_TMatrix,5));
	  memcpy(select=(int*)dw_malloc(n*sizeof(int)),COPY(TArg_pInteger,8),n*sizeof(int));
	  SSp=CreateMatrix(n,n);
	  TTp=CreateMatrix(n,n);
	  ReorderGeneralizedSchur_Real(SSp,TTp,fQQ ? QQ : (TMatrix)NULL,fZZ ? ZZ : (TMatrix)NULL,S,T,Q,Z,select,
				       fra ? ra : (TVector)NULL,fia ? ia : (TVector)NULL,fb ? b : (TVector)NULL);
	  FreeMatrix(S);
	  FreeMatrix(T);
	  FreeMatrix(SSp);
	  FreeMatrix(TTp);
	  dw_free(select);
	}
      err=GeneralizedSchurDecompositionError(SS,TT,QQ,ZZ,A,B);
      select=COPY(TArg_pInteger,8);
      for (k=0, i=n-1; i >= 0; i--) k+=select[i];
      for (i=0; i < k; i++)
	if ((tmp=sqrt(ElementV(ra,i)*ElementV(ra,i)+ElementV(ia,i)*ElementV(ia,i)) - div*fabs(ElementV(b,i))) > err)
	  err=tmp; 
      for ( ; i < n; i++)
	if ((tmp=div*fabs(ElementV(b,i)) - sqrt(ElementV(ra,i)*ElementV(ra,i)+ElementV(ia,i)*ElementV(ia,i))) > err)
	  err=tmp;

      //if (err >= 0) printf("Good case %d  %d  %le\n",k,n,GeneralizedSchurDecompositionError(SS,TT,QQ,ZZ,A,B));
      //if (err < 0) 
      //{
      //  printf("Bad case %d  %d  %le  %le\n",k,n,GeneralizedSchurDecompositionError(SS,TT,QQ,ZZ,A,B));
      //  for (i=0; i < n; i++) printf("  %le\n",
      //			       sqrt(ElementV(ra,i)*ElementV(ra,i)+ElementV(ia,i)*ElementV(ia,i))/ElementV(b,i));
      //}

      if (fQQ) FreeMatrix(QQ);
      if (fZZ) FreeMatrix(ZZ);
      if (fra) FreeVector(ra);
      if (fia) FreeVector(ia);
      if (fb) FreeVector(b);
    }

  return err;
}
void ReorderGeneralizedSchur_Real_T::DefaultTestSizes_InvalidNulls(void)
{
  int ts=4;
  SetTestSizes(1,&ts);
}
int ReorderGeneralizedSchur_Real_T::TestEqualPointers(int min, int max)
{
  int ts=4;
  if (inc) delete inc;
  inc=((min <= 0) || (max < min)) ? new TArgInc_EqualPointers_ReorderGeneralizedSchur_Real(this,1,&ts) 
    : new TArgInc_EqualPointers_ReorderGeneralizedSchur_Real(this,min,max);
  return First();
}
int ReorderGeneralizedSchur_Real_T::TestSpeed(int size)
{
  int ts[1], rtrn;
  TArg_pointer *p;
  if (inc) delete inc;
  ts[0]=(size <= 0) ? 10 : size;
  inc=new TArgInc_Speed(this,1,ts);
  rtrn=First();
  p=dynamic_cast<TArg_pointer*>(arg(2));
  p->Free();
  return rtrn;
}

//=== SortGeneralizedSchur_Real()
int TArgInc_EqualPointers_SortGeneralizedSchur_Real::Next(void)
{
  if (i > 3)
    if (!args->IncrementMinimalIndexes())
      return 0;
    else
      i=0;
  if (i >= 0)
    {
      ComputeActualSizes();
      args->Allocate();
      dynamic_cast<TArg_pointer*>(args->arg(i+4))->EquatePointers(dynamic_cast<TArg_pointer*>(args->arg(i)));
      args->Initialize();
      i++;
      return 1;
    }
  return 0;
}
void SortGeneralizedSchur_Real_T::Initialize(void)
{
  TFunction::Initialize();
  // Setup GeneralizedSchur decomposition
  int m=dynamic_cast<TArg_TMatrix*>(arg(0))->GetSize(0);
  if (m > 0)
    {
      int VerboseErrors, TerminalErrors, i;

      FreeMatrix(A); dw_NormalMatrix(A=CreateMatrix(m,m));
      FreeMatrix(B); dw_NormalMatrix(B=CreateMatrix(m,m));
      FreeMatrix(Q); Q=CreateMatrix(m,m);
      FreeMatrix(Z); Z=CreateMatrix(m,m);
      FreeVector(alpha_r); alpha_r=CreateVector(m);
      FreeVector(alpha_i); alpha_i=CreateVector(m);
      FreeVector(beta); beta=CreateVector(m);
 
      VerboseErrors=dw_SetVerboseErrors(0);
      TerminalErrors=dw_SetTerminalErrors(0);
      if (GeneralizedSchur_Real(ARG(TArg_TMatrix,4),ARG(TArg_TMatrix,5),Q,Z,A,B,alpha_r,alpha_i,beta))
	{				
	  EquateMatrix(COPY(TArg_TMatrix,4),ARG(TArg_TMatrix,4));
	  EquateMatrix(COPY(TArg_TMatrix,5),ARG(TArg_TMatrix,5));
	  if (ARG(TArg_TMatrix,6)) EquateMatrix(COPY(TArg_TMatrix,6),EquateMatrix(ARG(TArg_TMatrix,6),Q));
	  if (ARG(TArg_TMatrix,7)) EquateMatrix(COPY(TArg_TMatrix,7),EquateMatrix(ARG(TArg_TMatrix,7),Z));
	  if (ARG(TArg_TVector,8)) EquateVector(COPY(TArg_TVector,8),EquateVector(ARG(TArg_TVector,8),alpha_r));
	  if (ARG(TArg_TVector,9)) EquateVector(COPY(TArg_TVector,9),EquateVector(ARG(TArg_TVector,9),alpha_i));
	  if (ARG(TArg_TVector,10)) EquateVector(COPY(TArg_TVector,10),EquateVector(ARG(TArg_TVector,10),beta));
	}

      dw_SetVerboseErrors(VerboseErrors);
      dw_SetTerminalErrors(TerminalErrors);
    }
  COPY(TArg_int,11)=ARG(TArg_int,11)=(dw_uniform_rnd() > 0.5) ? 1 : 0;
}
int SortGeneralizedSchur_Real_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_int)=SortGeneralizedSchur_Real(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2),ARG(TArg_TMatrix,3),
				     ARG(TArg_TMatrix,4),ARG(TArg_TMatrix,5),ARG(TArg_TMatrix,6),ARG(TArg_TMatrix,7),
					      ARG(TArg_TVector,8),ARG(TArg_TVector,9),ARG(TArg_TVector,10),ARG(TArg_int,11));
  SetReturnOwner();
  return RTRN(TReturn_int);
}
PRECISION SortGeneralizedSchur_Real_T::ResultOK(void)
{
  PRECISION err=0.0;
  PRECISION tmp;
  TMatrix SS=ARG(TArg_TMatrix,0), TT=ARG(TArg_TMatrix,1), QQ=ARG(TArg_TMatrix,2), ZZ=ARG(TArg_TMatrix,3), X, Y, S, T, SSp, TTp;
  TVector ra, ia, b;
  int i, descend, n, fQQ=0, fZZ=0;
  char ch;

  if (!RTRN(TReturn_int))
    err=-1.0;
  else
    {
      n=RowM(A);
      descend=ARG(TArg_int,11);
      if (!QQ || !ARG(TArg_TMatrix,6))
	{
	  fQQ=1;
	  QQ=CreateMatrix(n,n);
	}
      if (!ZZ || !ARG(TArg_TMatrix,7))
	{
	  fZZ=1;
	  ZZ=CreateMatrix(n,n);
	}
      if (fQQ || fZZ)
	{
          S=EquateMatrix((TMatrix)NULL,COPY(TArg_TMatrix,4));
	  T=EquateMatrix((TMatrix)NULL,COPY(TArg_TMatrix,5));
	  SSp=CreateMatrix(n,n);
	  TTp=CreateMatrix(n,n);
	  ra=EquateVector((TVector)NULL,COPY(TArg_TVector,8));
	  ia=EquateVector((TVector)NULL,COPY(TArg_TVector,9));
	  b=EquateVector((TVector)NULL,COPY(TArg_TVector,10));
	  SortGeneralizedSchur_Real(SSp,TTp,fQQ ? QQ : (TMatrix)NULL,fZZ ? ZZ : (TMatrix)NULL,S,T,Q,Z,ra,ia,b,descend);
	  FreeMatrix(S);
	  FreeMatrix(T);
	  FreeMatrix(SSp);
	  FreeMatrix(TTp);
	  FreeVector(ra);
	  FreeVector(ia);
	  FreeVector(b);
	}
      err=GeneralizedSchurDecompositionError(SS,TT,QQ,ZZ,A,B);
      if (fQQ) FreeMatrix(QQ);
      if (fZZ) FreeMatrix(ZZ);
      ra=ARG(TArg_TVector,8);
      ia=ARG(TArg_TVector,9);
      b=ARG(TArg_TVector,10);
      for (ch=' ', i=1; i < n; ch=' ', i++)
	{
	  tmp=fabs(ElementV(b,i))*sqrt(ElementV(ra,i-1)*ElementV(ra,i-1)+ElementV(ia,i-1)*ElementV(ia,i-1)) - 
	    fabs(ElementV(b,i-1))*sqrt(ElementV(ra,i)*ElementV(ra,i)+ElementV(ia,i)*ElementV(ia,i));
	  if (descend) tmp=-tmp;
	  if (tmp > err) { err=tmp; printf("Sort error - %d  %d  %lf %c\n",i,n,tmp,ch); ch='*'; }
	}
    }

  return err;
}
void SortGeneralizedSchur_Real_T::DefaultTestSizes_InvalidNulls(void)
{
  int ts=4;
  SetTestSizes(1,&ts);
}
int SortGeneralizedSchur_Real_T::TestEqualPointers(int min, int max)
{
  int ts=4;
  if (inc) delete inc;
  inc=((min <= 0) || (max < min)) ? new TArgInc_EqualPointers_SortGeneralizedSchur_Real(this,1,&ts) 
    : new TArgInc_EqualPointers_SortGeneralizedSchur_Real(this,min,max);
  return First();
}
int SortGeneralizedSchur_Real_T::TestSpeed(int size)
{
  int ts[1], rtrn;
  TArg_pointer *p;
  if (inc) delete inc;
  ts[0]=(size <= 0) ? 10 : size;
  inc=new TArgInc_Speed(this,1,ts);
  rtrn=First();
  p=dynamic_cast<TArg_pointer*>(arg(2));
  p->Free();
  return rtrn;
}

//=== CreatePermutation()
//=== Also tests DimP(), ElementP(), and pElementP()
int CreatePermutation_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TPermutation)=CreatePermutation(ARG(TArg_int_size,0));
  SetReturnOwner();
  return RTRN(TReturn_TPermutation) ? 1 : 0;
}
PRECISION CreatePermutation_T::ResultOK(void)
{
  TPermutation R=RTRN(TReturn_TPermutation);
  int m=COPY(TArg_int_size,0);

  if (!R)
    return -1.0;
  else
    {
      for (int i=DimP(R)-1; i >= 0; i--)
	if (pElementP(R)+i != &(ElementP(R,i))) return -1.0;
      return ((DimP(R) != m) || (UseP(R) != 0)) ? -1.0 : 0.0;
    }
}

//=== EquatePermutation()
int EquatePermutation_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TPermutation)=EquatePermutation(ARG(TArg_TPermutation,0),ARG(TArg_TPermutation,1));
  SetReturnOwner();
  return RTRN(TReturn_TPermutation) ? 1 : 0;
}
PRECISION EquatePermutation_T::ResultOK(void)
{
  TPermutation R=RTRN(TReturn_TPermutation), X=COPY(TArg_TPermutation,1);

  if (!R)
    return -1.0;
  else
    {
      for (int i=UseP(R)-1; i >= 0; i--)
	if (ElementP(R,i) != ElementP(X,i)) return -1.0;
    }
    
  return 0.0;
}

//=== PermutationMatrix()
int PermutationMatrix_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=PermutationMatrix(ARG(TArg_TMatrix,0),ARG(TArg_TPermutation,1));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION PermutationMatrix_T::ResultOK(void)
{
  TPermutation X=COPY(TArg_TPermutation,1);
  TMatrix R=RTRN(TReturn_TMatrix);
  int *p, i, j, k;

  if (!R)
    return -1.0;
  else
    {
      p=pElementP(X);
      for (i=DimP(X)-1; i >= 0; i--)
	{
	  for (k=i, j=UseP(X)-1; j >= 0; j--)
	    if (k == j)
	      k=p[j];
	    else
	      if (k == p[j])
		k=j;
	  for (j=ColM(R)-1; j >= 0; j--)
	    if (j == i)
	      { if (ElementM(R,k,j) != 1.0) return -1.0; }
	    else
	      { if (ElementM(R,k,j) != 0.0) return -1.0; }
	}
    }
    
  return 0.0;
}

//=== TranspositionPermutation()
int TranspositionPermutation_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TPermutation)=TranspositionPermutation(ARG(TArg_TPermutation,0),ARG(TArg_int,1),ARG(TArg_int,2),ARG(TArg_int,3));
  SetReturnOwner();
  return RTRN(TReturn_TPermutation) ? 1 : 0;
}
PRECISION TranspositionPermutation_T::ResultOK(void)
{
  PRECISION err=0.0;
  TPermutation R=RTRN(TReturn_TPermutation);
  TMatrix X;
  TVector v;
  int i=COPY(TArg_int,1), j=COPY(TArg_int,2), k, m=COPY(TArg_int,3);

  if (!R)
    return -1.0;
  else
    {
      X=PermutationMatrix((TMatrix)NULL,R);
      v=CreateVector(m);
      for (k=m-1; k >= 0; k--) ElementV(v,k)=k;
      ProductMV(v,X,v);
      for (k=m-1; k >= 0; k--)
	if (k == i)
	  { if (ElementV(v,k) != j) { err=-1.0; break; } }
	else
	  if (k == j)
	    { if (ElementV(v,k) != i) { err=-1.0; break; } }
	  else
	    { if (ElementV(v,k) != k) { err=-1.0; break; } }
      FreeMatrix(X);
      FreeVector(v);
    }

  return err;
}
void TranspositionPermutation_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[1]=rand() % correct_sizes[3];
  correct_sizes[2]=rand() % correct_sizes[3];
}
int TranspositionPermutation_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  return ((0 <= actual_sizes[1]) && (actual_sizes[1] < actual_sizes[3])
	  && (0 <= actual_sizes[2]) && (actual_sizes[2] < actual_sizes[3])) ? 1 : 0;
}
void TranspositionPermutation_T::MakeSizeInvalid(int i)
{
  if ((i == 1) || (i == 2))
    actual_sizes[i]=actual_sizes[3] + (rand() % 3);
  else
    TArgList::MakeSizeInvalid(i);
}

//=== InitializePermutation()
int InitializePermutation_T::CallFunction(void)
{
  dw_ClearError();

  // Generates a random permutation
  int i, j, n, *p=ARG(TArg_pInteger,1), k=dynamic_cast<TArg_pInteger*>(arg(1))->GetSize(0), m=ARG(TArg_int,2);
  if (p && (k == m))
    {
      for (i=k-1; i >= 0; i--) p[i]=i;
      for (i=(k < m) ? k-1 : m-1; i >= 0; i--)
	{
	  j=i + (rand() % (m - i));
	  n=p[j];
	  p[j]=p[i];
	  p[i]=n;
	}
      memcpy(COPY(TArg_pInteger,1),p,k*sizeof(int));

      RTRN(TReturn_TPermutation)=InitializePermutation(ARG(TArg_TPermutation,0),ARG(TArg_pInteger,1),ARG(TArg_int,2));
      SetReturnOwner();
      return RTRN(TReturn_TPermutation) ? 1 : 0;
    }
  else
    return 0;
}
PRECISION InitializePermutation_T::ResultOK(void)
{
  PRECISION err=0.0;
  TPermutation R=RTRN(TReturn_TPermutation);
  TMatrix X;
  TVector v;
  int *p=COPY(TArg_pInteger,1), k, m=COPY(TArg_int,2);

  if (!R)
    return -1.0;
  else
    {
      X=PermutationMatrix((TMatrix)NULL,R);
      v=CreateVector(m);
      for (k=m-1; k >= 0; k--) ElementV(v,k)=k;
      ProductMV(v,X,v);
      for (k=m-1; k >= 0; k--)
	if (ElementV(v,p[k]) != k)
	  { 
	    //printf("k = %d / p[k] = %d / m = %d\n",k,p[k],m);
	    //dw_PrintMatrix(stdout,X,"%.1lf "); printf("\n"); dw_PrintVector(stdout,v,"%.1lf "); printf("\n");
            //for (int i=0; i < m; i++) printf("%d ",p[i]); printf("\n");
	    //for (int i=0; i < UseP(R); i++) printf("%d ",ElementP(R,i)); printf("\n"); getchar();
	    err=-1.0; 
	    break; 
	  }
      FreeMatrix(X);
      FreeVector(v);
    }

  return err;
}

//=== ProductPM()
int ProductPM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ProductPM(ARG(TArg_TMatrix,0),ARG(TArg_TPermutation,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ProductPM_T::ResultOK(void)
{
  PRECISION err=0.0;
  TPermutation X=COPY(TArg_TPermutation,1);
  TMatrix R=RTRN(TReturn_TMatrix), Y=COPY(TArg_TMatrix,2), Z, W;

  if (!R)
    return -1.0;
  else
    {
      Z=PermutationMatrix((TMatrix)NULL,X);
      W=ProductMM((TMatrix)NULL,Z,Y);
      err=EqualMatrices(W,R);
      FreeMatrix(W);
      FreeMatrix(Z);
    }

  return err;
}

//=== ProductPM()
int ProductMP_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ProductMP(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TPermutation,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ProductMP_T::ResultOK(void)
{
  PRECISION err=0.0;
  TPermutation X=COPY(TArg_TPermutation,2);
  TMatrix R=RTRN(TReturn_TMatrix), Y=COPY(TArg_TMatrix,1), Z, W;

  if (!R)
    return -1.0;
  else
    {
      Z=PermutationMatrix((TMatrix)NULL,X);
      W=ProductMM((TMatrix)NULL,Y,Z);
      err=EqualMatrices(W,R);
      FreeMatrix(W);
      FreeMatrix(Z);
    }

  return err;
}

//=== ProductPV()
int ProductPV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=ProductPV(ARG(TArg_TVector,0),ARG(TArg_TPermutation,1),ARG(TArg_TVector,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION ProductPV_T::ResultOK(void)
{
  PRECISION err=0.0;
  TPermutation X=COPY(TArg_TPermutation,1);
  TVector R=RTRN(TReturn_TVector), Y=COPY(TArg_TVector,2), W;
  TMatrix Z;

  if (!R)
    return -1.0;
  else
    {
      Z=PermutationMatrix((TMatrix)NULL,X);
      W=ProductMV((TVector)NULL,Z,Y);
      err=EqualVectors(W,R);
      FreeVector(W);
      FreeMatrix(Z);
    }

  return err;
}

//=== ProductPV()
int ProductVP_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=ProductVP(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_TPermutation,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION ProductVP_T::ResultOK(void)
{
  PRECISION err=0.0;
  TPermutation X=COPY(TArg_TPermutation,2);
  TVector R=RTRN(TReturn_TVector), Y=COPY(TArg_TVector,1), W;
  TMatrix Z;

  if (!R)
    return -1.0;
  else
    {
      Z=PermutationMatrix((TMatrix)NULL,X);
      W=ProductVM((TVector)NULL,Y,Z);
      err=EqualVectors(W,R);
      FreeVector(W);
      FreeMatrix(Z);
    }

  return err;
}

//=== TransposeProductPM()
int TransposeProductPM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=TransposeProductPM(ARG(TArg_TMatrix,0),ARG(TArg_TPermutation,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION TransposeProductPM_T::ResultOK(void)
{
  PRECISION err=0.0;
  TPermutation X=COPY(TArg_TPermutation,1);
  TMatrix R=RTRN(TReturn_TMatrix), Y=COPY(TArg_TMatrix,2), Z, W;

  if (!R)
    return -1.0;
  else
    {
      Z=PermutationMatrix((TMatrix)NULL,X);
      W=TransposeProductMM((TMatrix)NULL,Z,Y);
      err=EqualMatrices(W,R);
      FreeMatrix(W);
      FreeMatrix(Z);
    }

  return err;
}

//=== ProductTransposeMP()
int ProductTransposeMP_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ProductTransposeMP(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TPermutation,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ProductTransposeMP_T::ResultOK(void)
{
  PRECISION err=0.0;
  TPermutation X=COPY(TArg_TPermutation,2);
  TMatrix R=RTRN(TReturn_TMatrix), Y=COPY(TArg_TMatrix,1), Z, W;

  if (!R)
    return -1.0;
  else
    {
      Z=PermutationMatrix((TMatrix)NULL,X);
      W=ProductTransposeMM((TMatrix)NULL,Y,Z);
      err=EqualMatrices(W,R);
      FreeMatrix(W);
      FreeMatrix(Z);
    }

  return err;
}

//=== ProductPV()
int TransposeProductPV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=TransposeProductPV(ARG(TArg_TVector,0),ARG(TArg_TPermutation,1),ARG(TArg_TVector,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION TransposeProductPV_T::ResultOK(void)
{
  PRECISION err=0.0;
  TPermutation X=COPY(TArg_TPermutation,1);
  TVector R=RTRN(TReturn_TVector), Y=COPY(TArg_TVector,2), W;
  TMatrix Z;

  if (!R)
    return -1.0;
  else
    {
      Z=PermutationMatrix((TMatrix)NULL,X);
      W=TransposeProductMV((TVector)NULL,Z,Y);
      err=EqualVectors(W,R);
      FreeVector(W);
      FreeMatrix(Z);
    }

  return err;
}

//=== ProductPV()
int ProductTransposeVP_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=ProductTransposeVP(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_TPermutation,2));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION ProductTransposeVP_T::ResultOK(void)
{
  PRECISION err=0.0;
  TPermutation X=COPY(TArg_TPermutation,2);
  TVector R=RTRN(TReturn_TVector), Y=COPY(TArg_TVector,1), W;
  TMatrix Z;

  if (!R)
    return -1.0;
  else
    {
      Z=PermutationMatrix((TMatrix)NULL,X);
      W=ProductTransposeVM((TVector)NULL,Y,Z);
      err=EqualVectors(W,R);
      FreeVector(W);
      FreeMatrix(Z);
    }

  return err;
}

//=== Norm()
int Norm_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_PRECISION)=Norm(ARG(TArg_TVector,0));
  SetReturnOwner();
  return (RTRN(TReturn_PRECISION) >= 0.0) ? 1 : 0;
}
PRECISION Norm_T::ResultOK(void)
{
  PRECISION err=RTRN(TReturn_PRECISION)*RTRN(TReturn_PRECISION);
  TVector X=COPY(TArg_TVector,0);

  if (!X)
    return -1.0;
  else
    for (int i=DimV(X)-1; i >= 0; i--)
      err-=ElementV(X,i)*ElementV(X,i);

  return fabs(err);
}

//=== MatrixNormEuclidean()
int MatrixNormEuclidean_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_PRECISION)=MatrixNormEuclidean(ARG(TArg_TMatrix,0));
  SetReturnOwner();
  return (RTRN(TReturn_PRECISION) >= 0.0) ? 1 : 0;
}
PRECISION MatrixNormEuclidean_T::ResultOK(void)
{
  PRECISION err=RTRN(TReturn_PRECISION)*RTRN(TReturn_PRECISION);
  TMatrix X=COPY(TArg_TMatrix,0);
  int i, j;

  if (!X)
    return -1.0;
  else
    for (i=RowM(X)-1; i >= 0; i--)
      for (j=ColM(X)-1; j >= 0; j--)
	err-=ElementM(X,i,j)*ElementM(X,i,j);

  return fabs(err);
}

//=== MatrixNorm()
int MatrixNorm_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_PRECISION)=MatrixNorm(ARG(TArg_TMatrix,0));
  SetReturnOwner();
  return (RTRN(TReturn_PRECISION) >= 0.0) ? 1 : 0;
}
PRECISION MatrixNorm_T::ResultOK(void)
{
  PRECISION err=0.0;
  TMatrix X=COPY(TArg_TMatrix,0);
  TVector v;
  int i;

  if (!X)
    return -1.0;
  else
    {
      v=CreateVector((RowM(X) < ColM(X)) ? RowM(X) : ColM(X));
      if (!SVD((TMatrix)NULL,v,(TMatrix)NULL,X))
	err=-1.0;
      else
	{
	  for (i=DimV(v)-1; i >= 0; i--)
	    if (ElementV(v,i) > err) err=ElementV(v,i);
	  err=fabs(err - RTRN(TReturn_PRECISION));
	}
      FreeVector(v);
    }

  return err;
}

//=== DotProduct()
int DotProduct_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_PRECISION)=DotProduct(ARG(TArg_TVector,0),ARG(TArg_TVector,1));
  SetReturnOwner();
  return (dw_GetError() == NO_ERR) ? 1 : 0;
}
PRECISION DotProduct_T::ResultOK(void)
{
  PRECISION err=RTRN(TReturn_PRECISION);
  TVector X=COPY(TArg_TVector,0), Y=COPY(TArg_TVector,1);
  int i;

  if (!X || !Y || (DimV(X) != DimV(Y)))
    return -1.0;
  else
    for (int i=DimV(X)-1; i >= 0; i--)
      err-=ElementV(X,i)*ElementV(Y,i);

  return fabs(err);
}

//=== InnerProduct()
int InnerProduct_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_PRECISION)=InnerProduct(ARG(TArg_TVector,0),ARG(TArg_TVector,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return (dw_GetError() == NO_ERR) ? 1 : 0;
}
PRECISION InnerProduct_T::ResultOK(void)
{
  PRECISION err;
  TMatrix S=COPY(TArg_TMatrix,2);
  TVector X=COPY(TArg_TVector,0), Y=COPY(TArg_TVector,1), v;

  v=ProductMV((TVector)NULL,S,Y);
  err=fabs(DotProduct(X,v) - RTRN(TReturn_PRECISION));
  FreeVector(v);
 
  return (dw_GetError() == NO_ERR) ? err : -1;
}

//=== OuterProduct()
int OuterProduct_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=OuterProduct(ARG(TArg_TMatrix,0),ARG(TArg_TVector,1),ARG(TArg_TVector,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION OuterProduct_T::ResultOK(void)
{
  PRECISION err=0.0, tmp;
  TMatrix R=RTRN(TReturn_TMatrix);
  TVector X=COPY(TArg_TVector,1), Y=COPY(TArg_TVector,2);
  int i, j;

  if (!R)
    return -1.0;
  else
    {
      for (i=DimV(X)-1; i >= 0; i--)
	for (j=DimV(Y)-1; j >= 0; j--)
	  if ((tmp=fabs(ElementM(R,i,j) - ElementV(X,i)*ElementV(Y,j))) > err) err=tmp;
    }

  return err;
}

//=== CrossProduct_LU()
int CrossProduct_LU_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=CrossProduct_LU(ARG(TArg_TVector,0),ARG(TArg_TMatrix,1));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION CrossProduct_LU_T::ResultOK(void)
{
  PRECISION err=0.0, tmp;
  TMatrix X=COPY(TArg_TMatrix,1), Y;
  TVector R=RTRN(TReturn_TVector), v;
  int i, j;

  if (!R)
    return -1.0;
  else
    {
      v=ProductVM((TVector)NULL,R,X);
      err=IsZeroVector(v);
      FreeVector(v);
      Y=CreateMatrix(DimV(R),DimV(R));
      InsertSubMatrix(Y,X,0,0,0,0,DimV(R),DimV(R)-1);
      InsertColumnVector(Y,R,DimV(R)-1);
      tmp=Determinant_LU(Y);
      if (tmp < 0.0)
	err=-1.0;
      else
	if ((tmp=fabs(sqrt(Determinant_LU(Y)) - Norm(R))) > err) err=tmp;
      FreeMatrix(Y);
    }

  return err;
}
void CrossProduct_LU_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[0]=correct_sizes[1]=correct_sizes[2]+1;
}
int CrossProduct_LU_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  return ((actual_sizes[0] !=  actual_sizes[2]+1) || (actual_sizes[1] !=  actual_sizes[2]+1)) ? 0 : 1;
}

//=== Trace()
int Trace_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_PRECISION)=Trace(ARG(TArg_TMatrix,0));
  SetReturnOwner();
  return (dw_GetError() == NO_ERR) ? 1 : 0;
}
PRECISION Trace_T::ResultOK(void)
{
  PRECISION err=RTRN(TReturn_PRECISION);
  TMatrix X=COPY(TArg_TMatrix,0);
  int i;

  if (!X || (RowM(X) != ColM(X)))
    return -1.0;
  else
    {
      for (i=RowM(X)-1; i >= 0; i--)
	err-=ElementM(X,i,i);
    }

  return fabs(err);
}

//=== Vec()
int Vec_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=Vec(ARG(TArg_TVector,0),ARG(TArg_TMatrix,1));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION Vec_T::ResultOK(void)
{
  PRECISION err=0.0, tmp;
  TMatrix X=COPY(TArg_TMatrix,1);
  TVector R=RTRN(TReturn_TVector);
  int i, j, k;

  if (!R)
    return -1.0;
  else
    {
      for (k=j=0; j < ColM(X); j++)
	for (i=0; i < RowM(X); k++, i++)
	  if ((tmp=fabs(ElementM(X,i,j) - ElementV(R,k))) > err) err=tmp;
    }

  return err;
}
void Vec_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[0]=correct_sizes[1]*correct_sizes[2];
}
int Vec_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  return (actual_sizes[0] != actual_sizes[1]*actual_sizes[2]) ? 0 : 1;
}

//=== ReshapeV()
int ReshapeV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=ReshapeV(ARG(TArg_TMatrix,0),ARG(TArg_TVector,1),ARG(TArg_int,2),ARG(TArg_int,3));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION ReshapeV_T::ResultOK(void)
{
  PRECISION err=0.0, tmp;
  TMatrix R=RTRN(TReturn_TMatrix);
  TVector X=COPY(TArg_TVector,1);
  int i, j, k;

  if (!R)
    return -1.0;
  else
    {
      for (k=j=0; j < ColM(R); j++)
	for (i=0; i < RowM(R); k++, i++)
	  if ((tmp=fabs(ElementM(R,i,j) - ElementV(X,k))) > err) err=tmp;
    }

  return err;
}
void ReshapeV_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[2]=correct_sizes[0]*correct_sizes[1];
}
int ReshapeV_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  return (actual_sizes[2] != actual_sizes[0]*actual_sizes[1]) ? 0 : 1;
}

//=== Rank_SVD()
int Rank_SVD_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_int)=Rank_SVD(ARG(TArg_TMatrix,0));
  SetReturnOwner();
  return (RTRN(TReturn_int) < 0) ? 0 : 1;
}
PRECISION Rank_SVD_T::ResultOK(void)
{
  PRECISION err=0.0;
  TMatrix X=COPY(TArg_TMatrix,0);
  TVector d;
  int q, k, R=RTRN(TReturn_int);

  if (R < 0)
    return -1.0;
  else
    {
      q=(RowM(X) < ColM(X)) ? RowM(X) : ColM(X);
      d=CreateVector(q);
      if (!SVD((TMatrix)NULL,d,(TMatrix)NULL,X))
	return -1;
      else
	{
	  for (k=q-1; k >= 0; k--)
	    if (ElementV(d,k) > ElementV(d,0)*SQRT_MACHINE_EPSILON) break;
	  if (k+1 != R) err=-1.0;
	}
      FreeVector(d);
    }

  return err;
}

//=== KroneckerProduct()
int KroneckerProduct_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=KroneckerProduct(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION KroneckerProduct_T::ResultOK(void)
{
  PRECISION err=0.0, tmp;
  TMatrix R=RTRN(TReturn_TMatrix), X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,2);
  int i, j, r, s;

  if (!R)
    return -1.0;
  else
    {
      for (i=0; i < RowM(X); i++)
	for (j=0; j < ColM(X); j++)
	  for (r=0; r < RowM(Y); r++)
	    for (s=0; s < ColM(Y); s++)
	      if ((tmp=fabs(ElementM(R,i*RowM(Y)+r,j*ColM(Y)+s) - ElementM(X,i,j)*ElementM(Y,r,s))) > err) err=tmp;
    }

  return err;
}
void KroneckerProduct_T::ComputeCorrectSizes(void)
{
  TArgList::ComputeCorrectSizes();
  correct_sizes[0]=correct_sizes[2]*correct_sizes[4];
  correct_sizes[1]=correct_sizes[3]*correct_sizes[5];
}
int KroneckerProduct_T::SizesOK(void)
{
  if (!TArgList::SizesOK()) return 0;
  return ((actual_sizes[0] != actual_sizes[2]*actual_sizes[4])
	  || (actual_sizes[1] != actual_sizes[3]*actual_sizes[5])) ? 0 : 1;
}

//=== ComplexProductMM()
int ComplexProductMM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_int)=ComplexProductMM(ARG(TArg_TMatrix,0),ARG(TArg_TMatrix,1),ARG(TArg_TMatrix,2),
				     ARG(TArg_TMatrix,3),ARG(TArg_TMatrix,4),ARG(TArg_TMatrix,5));
  SetReturnOwner();
  return RTRN(TReturn_int);
}
PRECISION ComplexProductMM_T::ResultOK(void)
{
  PRECISION err=0.0, tmp;
  TMatrix rR=ARG(TArg_TMatrix,0), iR=ARG(TArg_TMatrix,1), rX=COPY(TArg_TMatrix,2), iX=COPY(TArg_TMatrix,3), 
    rY=COPY(TArg_TMatrix,4), iY=COPY(TArg_TMatrix,5), U, V;
  int i, j, r, s;

  if (!RTRN(TReturn_int))
    return -1.0;
  else
    {
      U=ProductMM((TMatrix)NULL,rX,rY);
      V=ProductMM((TMatrix)NULL,iX,iY);
      SubtractMM(U,U,V);
      if ((err=EqualMatrices(U,rR)) >= 0.0)
	{
	  ProductMM(U,rX,iY);
	  ProductMM(V,iX,rY);
	  AddMM(U,U,V);
	  if ((tmp=EqualMatrices(U,iR)) < 0.0)
	    err=tmp;
	  else
	    if (tmp > err) err=tmp;
	}
      FreeMatrix(U);
      FreeMatrix(V);
    }

  return err;
}
int ComplexProductMM_T::ArgumentsError(void)
{
  int err=TFunction::ArgumentsError();
  if (dynamic_cast<TArg_pointer*>(args[0])->address() == dynamic_cast<TArg_pointer*>(args[1])->address()) err|=ARG_ERR_GENERAL;
  return err;
}

//=== Determinant_LU()
int Determinant_LU_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_PRECISION)=Determinant_LU(ARG(TArg_TMatrix,0));
  SetReturnOwner();
  return (dw_GetError() == NO_ERR) ? 1 : 0;
}
PRECISION Determinant_LU_T::ResultOK(void)
{
  PRECISION err=0.0, tmp;
  TMatrix X=COPY(TArg_TMatrix,0), Q, R;
  int i;

  if (dw_GetError())
    return -1.0;
  else
    {
      Q=CreateMatrix(RowM(X),RowM(X));
      R=CreateMatrix(RowM(X),RowM(X));
      if (!QR(Q,R,X))
	err=-1.0;
      else
	{
	  tmp=Determinant_LU(Q);
	  err=fabs(fabs(tmp) - 1.0);
	  for (i=RowM(X)-1; i >= 0; i--)
	    tmp*=ElementM(R,i,i);
	  if ((tmp=fabs(tmp - RTRN(TReturn_PRECISION))) > err) err=tmp;
	}
      FreeMatrix(Q);
      FreeMatrix(R);
    }

  return err;
}

//=== LogAbsDeterminant_LU()
int LogAbsDeterminant_LU_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_PRECISION)=LogAbsDeterminant_LU(ARG(TArg_TMatrix,0));
  SetReturnOwner();
  return (dw_GetError() == NO_ERR) ? 1 : 0;
}
PRECISION LogAbsDeterminant_LU_T::ResultOK(void)
{
  PRECISION err;
  TMatrix X=COPY(TArg_TMatrix,0), R;
  int i;

  if (dw_GetError())
    return -1.0;
  else
    {
      R=CreateMatrix(RowM(X),RowM(X));
      if (!QR((TMatrix)NULL,R,X))
	err=-1.0;
      else
	{
	  for (err=RTRN(TReturn_PRECISION), i=RowM(X)-1; i >= 0; i--)
	    err-=log(fabs(ElementM(R,i,i)));
	  err=fabs(err);
	}
      FreeMatrix(R);
    }

  return err;
}

//=== LinearCombinationV()
int LinearCombinationV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=LinearCombinationV(ARG(TArg_TVector,0),ARG(TArg_PRECISION,1),ARG(TArg_TVector,2),ARG(TArg_PRECISION,3),ARG(TArg_TVector,4));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION LinearCombinationV_T::ResultOK(void)
{
  PRECISION err=0.0, tmp;
  TVector R=RTRN(TReturn_TVector), X=COPY(TArg_TVector,2), Y=COPY(TArg_TVector,4);
  PRECISION a=COPY(TArg_PRECISION,1), b=COPY(TArg_PRECISION,3);
  int i;

  if (!R)
    return -1.0;
  else
    {
      for (i=DimV(R)-1; i >= 0; i--)
	if ((tmp=fabs(ElementV(R,i) - (a*ElementV(X,i) + b*ElementV(Y,i)))) > err) err=tmp;
    }

  return err;
}

//=== LinearCombinationM()
int LinearCombinationM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=LinearCombinationM(ARG(TArg_TMatrix,0),ARG(TArg_PRECISION,1),ARG(TArg_TMatrix,2),ARG(TArg_PRECISION,3),ARG(TArg_TMatrix,4));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION LinearCombinationM_T::ResultOK(void)
{
  PRECISION err=0.0, tmp;
  TMatrix R=RTRN(TReturn_TMatrix), X=COPY(TArg_TMatrix,2), Y=COPY(TArg_TMatrix,4);
  PRECISION a=COPY(TArg_PRECISION,1), b=COPY(TArg_PRECISION,3);
  int i, j;

  if (!R)
    return -1.0;
  else
    {
      for (i=RowM(R)-1; i >= 0; i--)
	for (j=ColM(R)-1; j >= 0; j--)
	  if ((tmp=fabs(ElementM(R,i,j) - (a*ElementM(X,i,j) + b*ElementM(Y,i,j)))) > err) err=tmp;
    }

  return err;
}

//=== UpdateV()
int UpdateV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=UpdateV(ARG(TArg_PRECISION,0),ARG(TArg_TVector,1),ARG(TArg_PRECISION,2),ARG(TArg_TVector,3));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION UpdateV_T::ResultOK(void)
{
  PRECISION err=0.0, tmp;
  TVector R=RTRN(TReturn_TVector), X=COPY(TArg_TVector,1), Y=COPY(TArg_TVector,3);
  PRECISION a=COPY(TArg_PRECISION,0), b=COPY(TArg_PRECISION,2);
  int i;

  if (!R)
    return -1.0;
  else
    {
      for (i=DimV(R)-1; i >= 0; i--)
	if ((tmp=fabs(ElementV(R,i) - (a*ElementV(X,i) + b*ElementV(Y,i)))) > err) err=tmp;
    }

  return err;
}

//=== UpdateM()
int UpdateM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=UpdateM(ARG(TArg_PRECISION,0),ARG(TArg_TMatrix,1),ARG(TArg_PRECISION,2),ARG(TArg_TMatrix,3));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION UpdateM_T::ResultOK(void)
{
  PRECISION err=0.0, tmp;
  TMatrix R=RTRN(TReturn_TMatrix), X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,3);
  PRECISION a=COPY(TArg_PRECISION,0), b=COPY(TArg_PRECISION,2);
  int i, j;

  if (!R)
    return -1.0;
  else
    {
      for (i=RowM(R)-1; i >= 0; i--)
	for (j=ColM(R)-1; j >= 0; j--)
	  if ((tmp=fabs(ElementM(R,i,j) - (a*ElementM(X,i,j) + b*ElementM(Y,i,j)))) > err) err=tmp;
    }

  return err;
}

//=== UpdateProductMV()
int UpdateProductMV_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=UpdateProductMV(ARG(TArg_PRECISION,0),ARG(TArg_TVector,1),ARG(TArg_PRECISION,2),ARG(TArg_TMatrix,3),ARG(TArg_TVector,4));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION UpdateProductMV_T::ResultOK(void)
{
  PRECISION err=0.0, tmp;
  TMatrix Y=COPY(TArg_TMatrix,3);
  TVector r=RTRN(TReturn_TVector), x=COPY(TArg_TVector,1), z=COPY(TArg_TVector,4), v;
  PRECISION a=COPY(TArg_PRECISION,0), b=COPY(TArg_PRECISION,2);
  int i, j;

  if (!r)
    return -1.0;
  else
    {
      v=ProductMV((TVector)NULL,Y,z);
      LinearCombinationV(v,a,x,b,v);
      err=EqualVectors(v,r);
      FreeVector(v);
    }

  return err;
}

//=== UpdateProductVM()
int UpdateProductVM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TVector)=UpdateProductVM(ARG(TArg_PRECISION,0),ARG(TArg_TVector,1),ARG(TArg_PRECISION,2),ARG(TArg_TVector,3),ARG(TArg_TMatrix,4));
  SetReturnOwner();
  return RTRN(TReturn_TVector) ? 1 : 0;
}
PRECISION UpdateProductVM_T::ResultOK(void)
{
  PRECISION err=0.0, tmp;
  TMatrix Z=COPY(TArg_TMatrix,4);
  TVector r=RTRN(TReturn_TVector), x=COPY(TArg_TVector,1), y=COPY(TArg_TVector,3), v;
  PRECISION a=COPY(TArg_PRECISION,0), b=COPY(TArg_PRECISION,2);
  int i, j;

  if (!r)
    return -1.0;
  else
    {
      v=ProductVM((TVector)NULL,y,Z);
      LinearCombinationV(v,a,x,b,v);
      err=EqualVectors(v,r);
      FreeVector(v);
    }

  return err;
}


//=== UpdateProductMM()
int UpdateProductMM_T::CallFunction(void)
{
  dw_ClearError();
  RTRN(TReturn_TMatrix)=UpdateProductMM(ARG(TArg_PRECISION,0),ARG(TArg_TMatrix,1),ARG(TArg_PRECISION,2),ARG(TArg_TMatrix,3),ARG(TArg_TMatrix,4));
  SetReturnOwner();
  return RTRN(TReturn_TMatrix) ? 1 : 0;
}
PRECISION UpdateProductMM_T::ResultOK(void)
{
  PRECISION err=0.0, tmp;
  TMatrix R=RTRN(TReturn_TMatrix), X=COPY(TArg_TMatrix,1), Y=COPY(TArg_TMatrix,3), Z=COPY(TArg_TMatrix,4), YZ;
  PRECISION a=COPY(TArg_PRECISION,0), b=COPY(TArg_PRECISION,2);
  int i, j;

  if (!R)
    return -1.0;
  else
    {
      YZ=ProductMM((TMatrix)NULL,Y,Z);
      LinearCombinationM(YZ,a,X,b,YZ);
      err=EqualMatrices(YZ,R);
      FreeMatrix(YZ);
    }

  return err;
}

#undef RTRN
#undef ARG
#undef COPY
#undef MIN
#undef MAX

//===============================================================================

PRECISION EqualMatrices(TMatrix X, TMatrix Y)
{
  int i, j;
  PRECISION tmp, err=0.0;
  if (!X || !Y) return -1.0;
  if ((RowM(X) != RowM(Y)) || (ColM(X) != ColM(Y))) return -1.0;
  for (i=RowM(X)-1; i >= 0; i--)
    for (j=ColM(X)-1; j >= 0; j--)
      if ((tmp=fabs(ElementM(X,i,j)-ElementM(Y,i,j))) > err) err=tmp;
  return err;
}

PRECISION EqualVectors(TVector x, TVector y)
{
  int i;
  PRECISION tmp, err=0.0;
  if (!x || !y) return -1.0;
  if (DimV(x) != DimV(y)) return -1.0;
  for (i=DimV(x)-1; i >= 0; i--)
      if ((tmp=fabs(ElementV(x,i)-ElementV(y,i))) > err) err=tmp;
  return err;
}

PRECISION IsZeroMatrix(TMatrix X)
{
  int i, j;
  PRECISION tmp, err=0.0;
  if (!X) return -1.0;
  for (i=RowM(X)-1; i >= 0; i--)
    for (j=ColM(X)-1; j >= 0; j--)
      if ((tmp=fabs(ElementM(X,i,j))) > err) err=tmp;
  return err;
}

PRECISION IsZeroVector(TVector x)
{
  int i;
  PRECISION tmp, err=0.0;
  if (!x) return -1.0;
  for (i=DimV(x)-1; i >= 0; i--)
    if ((tmp=fabs(ElementV(x,i))) > err) err=tmp;
  return err;
}

PRECISION IsIdentity(TMatrix X)
{
  int i, j;
  PRECISION tmp, err=0.0;
  if (!X || (RowM(X) != ColM(X))) return -1.0;
  for (i=RowM(X)-1; i >= 0; i--)
    {
      if ((tmp=fabs(1.0 - ElementM(X,i,i))) > err) err=tmp;
      for (j=i-1; j >= 0; j--)
	{
	  if ((tmp=fabs(ElementM(X,i,j))) > err) err=tmp;
	  if ((tmp=fabs(ElementM(X,j,i))) > err) err=tmp;
	}
    }
  return err;
}

PRECISION IsSymmetric(TMatrix X)
{
  int i, j;
  PRECISION tmp, err=0.0;
  if (!X || (RowM(X) != ColM(X))) return -1.0;
  for (i=RowM(X)-1; i > 0; i--)
    for (j=i-1; j >= 0; j--) 
      if ((tmp=fabs(ElementM(X,i,j) - ElementM(X,j,i))) > err) err=tmp;
  return err;
}

PRECISION IsOrthogonal(TMatrix X)
{
  TMatrix I=TransposeProductMM((TMatrix)NULL,X,X);
  PRECISION err=IsIdentity(I);
  FreeMatrix(I);
  return err;
}

//===============================================================================

//=== TFunction_Node
TFunction_Node::~TFunction_Node()
{
  if (node) delete node;
  if (next) delete next;
}

TFunction_Node* CreateFunctionList(void)
{
  TFunction_Node *head=(TFunction_Node*)NULL;

  // Updates
  head=new TFunction_Node(new UpdateProductMV_T(),head);
  head=new TFunction_Node(new UpdateProductVM_T(),head);
  head=new TFunction_Node(new UpdateProductMM_T(),head);
  head=new TFunction_Node(new UpdateM_T(),head);
  head=new TFunction_Node(new UpdateV_T(),head);
  head=new TFunction_Node(new LinearCombinationM_T(),head);
  head=new TFunction_Node(new LinearCombinationV_T(),head);

  // Kronecker
  head=new TFunction_Node(new KroneckerProduct_T(),head);

  // Miscelleanous
  head=new TFunction_Node(new LogAbsDeterminant_LU_T(),head);
  head=new TFunction_Node(new Determinant_LU_T(),head);
  head=new TFunction_Node(new Rank_SVD_T(),head);
  head=new TFunction_Node(new ReshapeV_T(),head);
  head=new TFunction_Node(new Vec_T(),head);
  head=new TFunction_Node(new Trace_T(),head);
  head=new TFunction_Node(new CrossProduct_LU_T(),head);
  head=new TFunction_Node(new OuterProduct_T(),head);
  head=new TFunction_Node(new InnerProduct_T(),head);
  head=new TFunction_Node(new DotProduct_T(),head);
  head=new TFunction_Node(new MatrixNormEuclidean_T(),head);
  head=new TFunction_Node(new MatrixNorm_T(),head);
  head=new TFunction_Node(new Norm_T(),head);

  // Permutations
  head=new TFunction_Node(new ProductTransposeVP_T(),head);
  head=new TFunction_Node(new TransposeProductPV_T(),head);
  head=new TFunction_Node(new ProductTransposeMP_T(),head);
  head=new TFunction_Node(new TransposeProductPM_T(),head);
  head=new TFunction_Node(new ProductVP_T(),head);
  head=new TFunction_Node(new ProductPV_T(),head);
  head=new TFunction_Node(new ProductMP_T(),head);
  head=new TFunction_Node(new ProductPM_T(),head);
  head=new TFunction_Node(new InitializePermutation_T(),head);
  head=new TFunction_Node(new TranspositionPermutation_T(),head);
  head=new TFunction_Node(new PermutationMatrix_T(),head);
  head=new TFunction_Node(new EquatePermutation_T(),head);
  head=new TFunction_Node(new CreatePermutation_T(),head);

  // Decompositions
  head=new TFunction_Node(new NullSpace_T(),head);
  head=new TFunction_Node(new Eigenvalues_T(),head);
  head=new TFunction_Node(new Eigen_T(),head);
  head=new TFunction_Node(new SortGeneralizedSchur_Real_T(),head);
  head=new TFunction_Node(new ReorderGeneralizedSchur_Real_T(),head);
  head=new TFunction_Node(new GeneralizedSchur_Real_T(),head);
  head=new TFunction_Node(new LU_SolveCol_T(),head);
  head=new TFunction_Node(new LU_SolveRow_T(),head);
  head=new TFunction_Node(new LU_T(),head);
  head=new TFunction_Node(new CholeskyUT_T(),head);
  head=new TFunction_Node(new CholeskyLT_T(),head);
  head=new TFunction_Node(new QR_T(),head);
  head=new TFunction_Node(new SVD_T(),head);

  // Inverses
  head=new TFunction_Node(new GeneralizedInverse_T(),head);
  head=new TFunction_Node(new Inverse_UT_T(),head);
  head=new TFunction_Node(new Inverse_LT_T(),head);
  head=new TFunction_Node(new Inverse_Cholesky_T(),head);
  head=new TFunction_Node(new Inverse_SVD_T(),head);
  head=new TFunction_Node(new Inverse_LU_T(),head);

  // Products
  head=new TFunction_Node(new ComplexProductMM_T(),head);

  head=new TFunction_Node(new InverseProductLM_T(),head);
  head=new TFunction_Node(new InverseProductLV_T(),head);
  head=new TFunction_Node(new InverseProductUM_T(),head);
  head=new TFunction_Node(new InverseProductUV_T(),head);
  head=new TFunction_Node(new InverseProductMM_T(),head);
  head=new TFunction_Node(new InverseProductMV_T(),head);
  head=new TFunction_Node(new ProductInverseML_T(),head);
  head=new TFunction_Node(new ProductInverseVL_T(),head);
  head=new TFunction_Node(new ProductInverseMU_T(),head);
  head=new TFunction_Node(new ProductInverseVU_T(),head);
  head=new TFunction_Node(new ProductInverseMM_T(),head);
  head=new TFunction_Node(new ProductInverseVM_T(),head);

  head=new TFunction_Node(new TransposeProductMM_T(),head);
  head=new TFunction_Node(new TransposeProductMV_T(),head);
  head=new TFunction_Node(new ProductTransposeMM_T(),head);
  head=new TFunction_Node(new ProductTransposeVM_T(),head);

  head=new TFunction_Node(new ProductMU_T(),head);
  head=new TFunction_Node(new ProductML_T(),head);
  head=new TFunction_Node(new ProductUM_T(),head);
  head=new TFunction_Node(new ProductLM_T(),head);

  head=new TFunction_Node(new ProductMM_T(),head);
  head=new TFunction_Node(new ProductVM_T(),head);
  head=new TFunction_Node(new ProductMV_T(),head);
  head=new TFunction_Node(new ProductSM_T(),head);
  head=new TFunction_Node(new ProductMS_T(),head);
  head=new TFunction_Node(new ProductSV_T(),head);
  head=new TFunction_Node(new ProductVS_T(),head);

  // Sums
  head=new TFunction_Node(new SubtractMM_T(),head);
  head=new TFunction_Node(new SubtractVV_T(),head);
  head=new TFunction_Node(new AddMM_T(),head);
  head=new TFunction_Node(new AddVV_T(),head);

  // Assignment
  head=new TFunction_Node(new MinusM_T(),head);
  head=new TFunction_Node(new MinusV_T(),head);
  head=new TFunction_Node(new AbsM_T(),head);
  head=new TFunction_Node(new AbsV_T(),head);
  head=new TFunction_Node(new DiagonalMatrix_T(),head);
  head=new TFunction_Node(new IdentityMatrix_T(),head);
  head=new TFunction_Node(new Transpose_T(),head);
  head=new TFunction_Node(new EquateMatrix_T(),head);
  head=new TFunction_Node(new EquateVector_T(),head);
  head=new TFunction_Node(new InsertSubMatrix_T(),head);
  head=new TFunction_Node(new InsertColumnVector_T(),head);
  head=new TFunction_Node(new InsertRowVector_T(),head);
  head=new TFunction_Node(new SubVector_T(),head);
  head=new TFunction_Node(new SubMatrix_T(),head);
  head=new TFunction_Node(new ColumnVector_T(),head);
  head=new TFunction_Node(new RowVector_T(),head);
  head=new TFunction_Node(new ColumnMatrix_T(),head);
  head=new TFunction_Node(new RowMatrix_T(),head);

  // Initialization
  head=new TFunction_Node(new InitializeMatrix_T(),head);
  head=new TFunction_Node(new InitializeVector_T(),head);

  // Creation
  head=new TFunction_Node(new CreateMatrix_T(),head);
  head=new TFunction_Node(new CreateVector_T(),head);

  return head;
}

