ngspice/src/maths/sparse/spsmp.c

554 lines
11 KiB
C
Raw Normal View History

2000-04-27 22:03:57 +02:00
/*
* Spice3 COMPATIBILITY MODULE
*
* Author: Advising professor:
* Kenneth S. Kundert Alberto Sangiovanni-Vincentelli
* UC Berkeley
*
* This module contains routines that make Sparse1.3 a direct
* replacement for the SMP sparse matrix package in Spice3c1 or Spice3d1.
* Sparse1.3 is in general a faster and more robust package than SMP.
* These advantages become significant on large circuits.
*
* >>> User accessible functions contained in this file:
* SMPaddElt
* SMPmakeElt
* SMPcClear
* SMPclear
* SMPcLUfac
* SMPluFac
* SMPcReorder
* SMPreorder
* SMPcaSolve
* SMPcSolve
* SMPsolve
* SMPmatSize
* SMPnewMatrix
* SMPdestroy
* SMPpreOrder
* SMPprint
* SMPgetError
* SMPcProdDiag
* LoadGmin
* SMPfindElt
*/
/*
* To replace SMP with Sparse, rename the file spSpice3.h to
* spMatrix.h and place Sparse in a subdirectory of SPICE called
* `sparse'. Then on UNIX compile Sparse by executing `make spice'.
* If not on UNIX, after compiling Sparse and creating the sparse.a
* archive, compile this file (spSMP.c) and spSMP.o to the archive,
* then copy sparse.a into the SPICE main directory and rename it
* SMP.a. Finally link SPICE.
*
* To be compatible with SPICE, the following Sparse compiler options
* (in spConfig.h) should be set as shown below:
*
* EXPANDABLE YES
* TRANSLATE NO
* INITIALIZE NO or YES, YES for use with test prog.
* DIAGONAL_PIVOTING YES
* MODIFIED_MARKOWITZ NO
* DELETE NO
* STRIP NO
* MODIFIED_NODAL YES
* QUAD_ELEMENT NO
* TRANSPOSE YES
* SCALING NO
* DOCUMENTATION YES
* MULTIPLICATION NO
* DETERMINANT YES
* STABILITY NO
* CONDITION NO
* PSEUDOCONDITION NO
* DEBUG YES
*
* spREAL double
*/
/*
* Revision and copyright information.
*
* Copyright (c) 1985,86,87,88,89,90
* by Kenneth S. Kundert and the University of California.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and supporting
* documentation and that the authors and the University of California
* are properly credited. The authors and the University of California
* make no representations as to the suitability of this software for
* any purpose. It is provided `as is', without express or implied warranty.
*/
/*
* IMPORTS
*
* >>> Import descriptions:
* spMatrix.h
* Sparse macros and declarations.
* SMPdefs.h
* Spice3's matrix macro definitions.
*/
#include "ngspice/config.h"
#include <assert.h>
2000-04-27 22:03:57 +02:00
#include <stdio.h>
#include <math.h>
#include "ngspice/spmatrix.h"
#include "spdefs.h"
#include "ngspice/smpdefs.h"
2008-12-07 11:08:11 +01:00
#if defined (_MSC_VER)
extern double scalbn(double, int);
2009-08-22 18:54:03 +02:00
#define logb _logb
extern double logb(double);
2008-12-07 11:08:11 +01:00
#endif
static void LoadGmin(SMPmatrix *Matrix, double Gmin);
2000-04-27 22:03:57 +02:00
/*
* SMPaddElt()
*/
int
SMPaddElt(SMPmatrix *Matrix, int Row, int Col, double Value)
2000-04-27 22:03:57 +02:00
{
*spGetElement( Matrix, Row, Col ) = Value;
return spError( Matrix );
2000-04-27 22:03:57 +02:00
}
/*
* SMPmakeElt()
*/
double *
SMPmakeElt(SMPmatrix *Matrix, int Row, int Col)
2000-04-27 22:03:57 +02:00
{
return spGetElement( Matrix, Row, Col );
2000-04-27 22:03:57 +02:00
}
/*
* SMPcClear()
*/
void
SMPcClear(SMPmatrix *Matrix)
2000-04-27 22:03:57 +02:00
{
spClear( Matrix );
2000-04-27 22:03:57 +02:00
}
/*
* SMPclear()
*/
void
SMPclear(SMPmatrix *Matrix)
2000-04-27 22:03:57 +02:00
{
spClear( Matrix );
2000-04-27 22:03:57 +02:00
}
2010-11-16 21:38:24 +01:00
#define NG_IGNORE(x) (void)x
2010-11-16 20:11:32 +01:00
2000-04-27 22:03:57 +02:00
/*
* SMPcLUfac()
*/
/*ARGSUSED*/
int
SMPcLUfac(SMPmatrix *Matrix, double PivTol)
2000-04-27 22:03:57 +02:00
{
2010-11-16 21:38:24 +01:00
NG_IGNORE(PivTol);
2010-11-16 20:11:32 +01:00
spSetComplex( Matrix );
return spFactor( Matrix );
2000-04-27 22:03:57 +02:00
}
/*
* SMPluFac()
*/
/*ARGSUSED*/
int
SMPluFac(SMPmatrix *Matrix, double PivTol, double Gmin)
2000-04-27 22:03:57 +02:00
{
2010-11-16 21:38:24 +01:00
NG_IGNORE(PivTol);
spSetReal( Matrix );
LoadGmin( Matrix, Gmin );
return spFactor( Matrix );
2000-04-27 22:03:57 +02:00
}
/*
* SMPcReorder()
*/
int
SMPcReorder(SMPmatrix *Matrix, double PivTol, double PivRel,
int *NumSwaps)
2000-04-27 22:03:57 +02:00
{
*NumSwaps = 1;
spSetComplex( Matrix );
2011-04-28 17:59:36 +02:00
return spOrderAndFactor( Matrix, NULL,
PivRel, PivTol, YES );
2000-04-27 22:03:57 +02:00
}
/*
* SMPreorder()
*/
int
SMPreorder(SMPmatrix *Matrix, double PivTol, double PivRel, double Gmin)
2000-04-27 22:03:57 +02:00
{
spSetReal( Matrix );
LoadGmin( Matrix, Gmin );
2011-04-28 17:59:36 +02:00
return spOrderAndFactor( Matrix, NULL,
PivRel, PivTol, YES );
2000-04-27 22:03:57 +02:00
}
/*
* SMPcaSolve()
*/
void
SMPcaSolve(SMPmatrix *Matrix, double RHS[], double iRHS[],
double Spare[], double iSpare[])
2000-04-27 22:03:57 +02:00
{
2010-11-16 21:38:24 +01:00
NG_IGNORE(iSpare);
NG_IGNORE(Spare);
2010-11-16 20:11:32 +01:00
spSolveTransposed( Matrix, RHS, RHS, iRHS, iRHS );
2000-04-27 22:03:57 +02:00
}
/*
* SMPcSolve()
*/
void
SMPcSolve(SMPmatrix *Matrix, double RHS[], double iRHS[],
double Spare[], double iSpare[])
2000-04-27 22:03:57 +02:00
{
2010-11-16 21:38:24 +01:00
NG_IGNORE(iSpare);
NG_IGNORE(Spare);
2010-11-16 20:11:32 +01:00
spSolve( Matrix, RHS, RHS, iRHS, iRHS );
2000-04-27 22:03:57 +02:00
}
/*
* SMPsolve()
*/
void
SMPsolve(SMPmatrix *Matrix, double RHS[], double Spare[])
2000-04-27 22:03:57 +02:00
{
2010-11-16 21:38:24 +01:00
NG_IGNORE(Spare);
2010-11-16 20:11:32 +01:00
2011-04-28 17:59:36 +02:00
spSolve( Matrix, RHS, RHS, NULL, NULL );
2000-04-27 22:03:57 +02:00
}
/*
* SMPmatSize()
*/
int
SMPmatSize(SMPmatrix *Matrix)
2000-04-27 22:03:57 +02:00
{
return spGetSize( Matrix, 1 );
2000-04-27 22:03:57 +02:00
}
/*
* SMPnewMatrix()
*/
int
SMPnewMatrix(SMPmatrix **pMatrix)
2000-04-27 22:03:57 +02:00
{
int Error;
*pMatrix = spCreate( 0, 1, &Error );
2000-04-27 22:03:57 +02:00
return Error;
}
/*
* SMPdestroy()
*/
void
SMPdestroy(SMPmatrix *Matrix)
2000-04-27 22:03:57 +02:00
{
spDestroy( Matrix );
2000-04-27 22:03:57 +02:00
}
/*
* SMPpreOrder()
*/
int
SMPpreOrder(SMPmatrix *Matrix)
2000-04-27 22:03:57 +02:00
{
spMNA_Preorder( Matrix );
return spError( Matrix );
2000-04-27 22:03:57 +02:00
}
2012-02-19 12:11:31 +01:00
/*
* SMPprint()
*/
void
SMPprintRHS(SMPmatrix *Matrix, char *Filename, RealVector RHS, RealVector iRHS)
{
spFileVector( Matrix, Filename, RHS, iRHS );
}
2000-04-27 22:03:57 +02:00
/*
* SMPprint()
*/
2012-02-19 11:23:56 +01:00
2000-04-27 22:03:57 +02:00
void
2012-02-19 11:23:56 +01:00
SMPprint(SMPmatrix *Matrix, char *Filename)
2000-04-27 22:03:57 +02:00
{
2012-02-19 11:23:56 +01:00
if (Filename)
spFileMatrix(Matrix, Filename, "Circuit Matrix", 0, 1, 1 );
else
spPrint( Matrix, 0, 1, 1 );
2000-04-27 22:03:57 +02:00
}
/*
* SMPgetError()
*/
void
SMPgetError(SMPmatrix *Matrix, int *Col, int *Row)
2000-04-27 22:03:57 +02:00
{
spWhereSingular( Matrix, Row, Col );
2000-04-27 22:03:57 +02:00
}
/*
* SMPcProdDiag()
* note: obsolete for Spice3d2 and later
*/
int
SMPcProdDiag(SMPmatrix *Matrix, SPcomplex *pMantissa, int *pExponent)
2000-04-27 22:03:57 +02:00
{
spDeterminant( Matrix, pExponent, &(pMantissa->real),
2000-04-27 22:03:57 +02:00
&(pMantissa->imag) );
return spError( Matrix );
2000-04-27 22:03:57 +02:00
}
/*
* SMPcDProd()
*/
int
SMPcDProd(SMPmatrix *Matrix, SPcomplex *pMantissa, int *pExponent)
2000-04-27 22:03:57 +02:00
{
double re, im, x, y, z;
int p;
spDeterminant( Matrix, &p, &re, &im);
2000-04-27 22:03:57 +02:00
#ifndef M_LN2
#define M_LN2 0.69314718055994530942
#endif
#ifndef M_LN10
#define M_LN10 2.30258509299404568402
#endif
#ifdef debug_print
printf("Determinant 10: (%20g,%20g)^%d\n", re, im, p);
#endif
/* Convert base 10 numbers to base 2 numbers, for comparison */
y = p * M_LN10 / M_LN2;
x = (int) y;
y -= x;
/* ASSERT
* x = integral part of exponent, y = fraction part of exponent
*/
/* Fold in the fractional part */
#ifdef debug_print
printf(" ** base10 -> base2 int = %g, frac = %20g\n", x, y);
#endif
z = pow(2.0, y);
re *= z;
im *= z;
#ifdef debug_print
printf(" ** multiplier = %20g\n", z);
#endif
/* Re-normalize (re or im may be > 2.0 or both < 1.0 */
if (re != 0.0) {
y = logb(re);
if (im != 0.0)
z = logb(im);
else
z = 0;
} else if (im != 0.0) {
z = logb(im);
y = 0;
} else {
/* Singular */
/*printf("10 -> singular\n");*/
y = 0;
z = 0;
}
#ifdef debug_print
printf(" ** renormalize changes = %g,%g\n", y, z);
#endif
if (y < z)
y = z;
2009-08-22 18:54:03 +02:00
*pExponent = (int)(x + y);
x = scalbn(re, (int) -y);
z = scalbn(im, (int) -y);
2000-04-27 22:03:57 +02:00
#ifdef debug_print
printf(" ** values are: re %g, im %g, y %g, re' %g, im' %g\n",
re, im, y, x, z);
#endif
pMantissa->real = scalbn(re, (int) -y);
pMantissa->imag = scalbn(im, (int) -y);
2000-04-27 22:03:57 +02:00
#ifdef debug_print
printf("Determinant 10->2: (%20g,%20g)^%d\n", pMantissa->real,
pMantissa->imag, *pExponent);
#endif
return spError( Matrix );
2000-04-27 22:03:57 +02:00
}
/*
* The following routines need internal knowledge of the Sparse data
* structures.
*/
/*
* LOAD GMIN
*
* This routine adds Gmin to each diagonal element. Because Gmin is
* added to the current diagonal, which may bear little relation to
* what the outside world thinks is a diagonal, and because the
* elements that are diagonals may change after calling spOrderAndFactor,
* use of this routine is not recommended. It is included here simply
* for compatibility with Spice3.
*/
static void
LoadGmin(SMPmatrix *Matrix, double Gmin)
2000-04-27 22:03:57 +02:00
{
int I;
ArrayOfElementPtrs Diag;
ElementPtr diag;
2000-04-27 22:03:57 +02:00
/* Begin `LoadGmin'. */
assert( IS_SPARSE( Matrix ) );
2000-04-27 22:03:57 +02:00
if (Gmin != 0.0) {
Diag = Matrix->Diag;
for (I = Matrix->Size; I > 0; I--) {
if ((diag = Diag[I]) != NULL)
2000-04-27 22:03:57 +02:00
diag->Real += Gmin;
}
}
return;
}
/*
* FIND ELEMENT
*
* This routine finds an element in the matrix by row and column number.
* If the element exists, a pointer to it is returned. If not, then NULL
* is returned unless the CreateIfMissing flag is TRUE, in which case a
* pointer to the new element is returned.
*/
SMPelement *
SMPfindElt(SMPmatrix *Matrix, int Row, int Col, int CreateIfMissing)
2000-04-27 22:03:57 +02:00
{
ElementPtr Element;
2000-04-27 22:03:57 +02:00
/* Begin `SMPfindElt'. */
assert( IS_SPARSE( Matrix ) );
2000-04-27 22:03:57 +02:00
Row = Matrix->ExtToIntRowMap[Row];
Col = Matrix->ExtToIntColMap[Col];
Element = Matrix->FirstInCol[Col];
Element = spcFindElementInCol(Matrix, &Element, Row, Col, CreateIfMissing);
return Element;
2000-04-27 22:03:57 +02:00
}
/* XXX The following should probably be implemented in spUtils */
/*
* SMPcZeroCol()
*/
int
SMPcZeroCol(SMPmatrix *Matrix, int Col)
2000-04-27 22:03:57 +02:00
{
ElementPtr Element;
Col = Matrix->ExtToIntColMap[Col];
for (Element = Matrix->FirstInCol[Col];
Element != NULL;
Element = Element->NextInCol)
{
Element->Real = 0.0;
Element->Imag = 0.0;
}
return spError( Matrix );
2000-04-27 22:03:57 +02:00
}
/*
* SMPcAddCol()
*/
int
SMPcAddCol(SMPmatrix *Matrix, int Accum_Col, int Addend_Col)
2000-04-27 22:03:57 +02:00
{
ElementPtr Accum, Addend, *Prev;
Accum_Col = Matrix->ExtToIntColMap[Accum_Col];
Addend_Col = Matrix->ExtToIntColMap[Addend_Col];
Addend = Matrix->FirstInCol[Addend_Col];
Prev = &Matrix->FirstInCol[Accum_Col];
2013-07-14 15:08:46 +02:00
Accum = *Prev;
2000-04-27 22:03:57 +02:00
while (Addend != NULL) {
while (Accum && Accum->Row < Addend->Row) {
Prev = &Accum->NextInCol;
Accum = *Prev;
}
if (!Accum || Accum->Row > Addend->Row) {
Accum = spcCreateElement(Matrix, Addend->Row, Accum_Col, Prev, 0);
}
Accum->Real += Addend->Real;
Accum->Imag += Addend->Imag;
Addend = Addend->NextInCol;
}
return spError( Matrix );
2000-04-27 22:03:57 +02:00
}
/*
* SMPzeroRow()
*/
int
SMPzeroRow(SMPmatrix *Matrix, int Row)
2000-04-27 22:03:57 +02:00
{
ElementPtr Element;
Row = Matrix->ExtToIntColMap[Row];
if (Matrix->RowsLinked == NO)
spcLinkRows(Matrix);
if (Matrix->PreviousMatrixWasComplex || Matrix->Complex) {
2000-04-27 22:03:57 +02:00
for (Element = Matrix->FirstInRow[Row];
Element != NULL;
Element = Element->NextInRow)
{
Element->Real = 0.0;
Element->Imag = 0.0;
}
} else {
2000-04-27 22:03:57 +02:00
for (Element = Matrix->FirstInRow[Row];
Element != NULL;
Element = Element->NextInRow)
{
Element->Real = 0.0;
}
}
return spError( Matrix );
2000-04-27 22:03:57 +02:00
}