# To unbundle, sh this file
echo mxyzptlk.cc 1>&2
cat >mxyzptlk.cc <<'End of mxyzptlk.cc'
/*************************************************************************
**************************************************************************
**************************************************************************
******                                                                ****
******  MXYZPTLK:  A C++ implementation of differential algebra.      ****
******                                                                ****
******  Copyright (c) 1990  Universities Research Association, Inc.   ****
******                All Rights Reserved                             ****
******                                                                ****
******  Author:    Leo Michelotti                                     ****
******                                                                ****
******             Fermilab                                           ****
******             P.O.Box 500                                        ****
******             Mail Stop 345                                      ****
******             Batavia, IL   60510                                ****
******                                                                ****
******             Phone: (708) 840 4956                              ****
******             Email: michelot@hazel.fnal.gov                     ****
******                    michelotti@adcalc.fnal.gov                  ****
******                    almond::michelotti                          ****
******                                                                ****
******  Release    Version 1.0 : January 31, 1990                     ****
******  Dates:              .1 : October 11, 1990                     ****
******                      .2 : November 6, 1990                     ****
******                      .3 : October  2, 1992                     ****
******                      .4 : July    20, 1993                     ****
******                     2.0   August  12, 1993                     ****
******                                                                ****
**************************************************************************
**************************************************************************
******                                                                ****
******  This material resulted from work developed under a            ****
******  Government Contract and is subject to the following           ****
******  license: The Government retains a paid-up, nonexclusive,      ****
******  irrevocable worldwide license to reproduce, prepare           ****
******  derivative works, perform publicly and display publicly       ****
******  by or for the Government, including the right to distribute   ****
******  to other Government contractors.  Neither the United          ****
******  States nor the United States Department of Energy, nor        ****
******  any of their employees, makes any warranty, express or        ****
******  implied, or assumes any legal liability or responsibility     ****
******  for the accuracy, completeness or usefulness of any           ****
******  information, apparatus, product, or process disclosed, or     ****
******  represents that its use would not infringe privately owned    ****
******  rights.                                                       ****
******                                                                ****
**************************************************************************
**************************************************************************
******                                                                ****
******  Notes:                                                        ****
******                                                                ****
******  11/6/90   .. Leo Michelotti                                   ****
******  DA functions  pow( DA&, double )  and  sqrt( DA& ) have       ****
******  been included in the lexicon.                                 ****
******                                                                ****
******                                                                ****
******  10/11/90  .. Leo Michelotti                                   ****
******  DASetup routines have been changed so that the variable       ****
******  DA__1stEnv.DA__allSet and the array DA__1stEnv.DA__refPoint   ****
******  are set earlier.  This fixes a bug which first arose in       ****
******  an application involving concatenation.                       ****
******                                                                ****
******                                                                ****
******  10/2/92  .. Leo Michelotti                                    ****
******  In   double DA::weightedDerivative( int* ind ), the cast      ****
******  appearing in declaring a dlist_iterator was changed           ****
******  from (dlist) to (dlist&) in order to bypass a call to         ****
******  the dlist copy constructor.  I suspect g++ does not           ****
******  handle casting correctly, but I cannot yet prove it.          ****
******  It may also be true that the copy constructor is not          ****
******  working properly.                                             ****
******                                                                ****
******                                                                ****
******  7/20/93 .. Leo Michelotti                                     ****
******  In an attempt to improve efficiency, functions that           ****
******  previously returned DA have been changed to return            ****
******  DA&.  In conjunction with this, a disposable base             ****
******  class has been defined in order to provide for some           ****
******  primitive garbate collection.                                 ****
******                                                                ****
******  The code sandwiched between #ifdef POOLED and #endif          ****
******  POOLED statements is still under development.  It             ****
******  should not be activated by the Makefile.                      ****
******                                                                ****
******                                                                ****
******  8/12/93 .. Leo Michelotti                                     ****
******  The LieOperator methods .expMap() and .operator^              ****
******  have now been implemented.  The former                        ****
******  integrates equations of motion by developing                  ****
******  exponential maps, and the latter simply                       ****
******  evaluates a Lie derivative.  The one restriction              ****
******  at the moment is the assumption made by                       ****
******  .expMap() that the point of evaluation is a                   ****
******  fixed point of the vector field.  There are ways              ****
******  of getting around this -- but, another day.                   ****
******  Demos are contained in files Lie_X_Test.cc,                   ****
******  where X = A ... E.                                            ****
******                                                                ****
******     __ This upgrade is significant enough to                   ****
******  warrant a version change, from 1.X to 2.0.                    ****
******  Huzzah!                                                       ****
******                                                                ****
******     __ Addition has been modified so that small                ****
******  terms indistinguishable from zero are not                     ****
******  carried.  Further, arithmetic on LieOperators                 ****
******  has been enabled.                                             ****
******                                                                ****
**************************************************************************
*************************************************************************/

#include "mxyzptlk.hxx"
#include "numrecip.hxx"

// ================================================================
//      The environment
//

extern Attic  DA__garbage;
extern struct DA__environment DA__1stEnv;
extern FILE  *DA__scratchFile;
extern dlist  DA__coordPool;
extern dlist  DA__coordPtrs;

// ================================================================
//      External routines
//

extern char nexcom( int, int, int* );  
                                // Computes the next composition
                                //  of an integer into a number of parts.
                                //  Algorithm devised by Herbert Wilf.

extern "C" {
 int bcfRec( int, int );        // Recursive evaluation of binomial
                                //  coefficient.
 int nearestInteger( double );  // Returns the integer nearest to its
                                //  double argument.
}

// ================================================================
//      Global functions

void    DA__monoCode();     // Computes the code of a monomial from its
                            //   exponents.
void    DA__monoDecode();   // The inverse operation to monoCode.
int     DA__monoRank();     // Computes the rank of a monomial.


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

#ifndef MX_SMALL
#define MX_SMALL    1.0e-12 // Used by DA::addTerm to decide 
                            //   removal of a DAterm.
#endif  MX_SMALL

#ifndef MX_MAXITER
#define MX_MAXITER  100     // Maximum number of iterations allowed
                            //   in iterative routines
#endif  MX_MAXITER


//***************************************************************
//***************************************************************
//***************************************************************
//
//      Initialization routines DASetup.
//      Must be called first by any program in order to establish the
//      number of (scalar) variables, n,
//      maximum weight of derivatives, w,
//      dimension of phase space, s,
//      default reference point, r.

void DASetup( const int n, const int w ) {
 int i, j;
 DA* p;
 LieOperator* q;
 
 if( DA__1stEnv.DA__allSet == 137 )
   printf( "\n*** DA ERROR *** Attempt to call DASetup twice.\n" );
 
 else {
 
   // Some error checking ..
   if( n < 1 ) {
     printf("\n*** DASetup requires at least one variable.");
     exit(0);
     }
 
   if( w < 1 ) {
     printf("\n*** DASetup requires a minimal maximum weight of 1.");
     exit(0);
     }
 
   DA__1stEnv.DA__allSet = 137;
 
   // The default reference point is set to the origin.
   DA__1stEnv.DA__refPoint = new double[ n ];
   for( i = 0; i < n; i++ ) DA__1stEnv.DA__refPoint[i] = 0.0;
 
   DA__1stEnv.DA__NumVar = n;
   DA__1stEnv.DA__MaxWeight = w;
   DA__1stEnv.DA__exponent = new int[ n ];
   DA__1stEnv.DA__expCode = new char[ w + n ];
   DA__1stEnv.DA__monomial = new double[ bcfRec( w + n, n ) ];
   DA__1stEnv.DA__SpaceDim = 0;             // No DA vectors will be allowed.
   DA__1stEnv.DA__PBOK = 0;                 // No Poisson brackets allowed.
 
   DA__1stEnv.DA__AllZeroes = new int[ n ];
   for( i = 0; i < n; i++ ) DA__1stEnv.DA__AllZeroes[i] = 0;
 
   // Go through all predefined DA variables: set the reference
   // and weight accuracy.
   while( p = (DA*) DA__1stEnv.DA__predefDA.get() ) {
     p->refPoint = new double[ DA__1stEnv.DA__NumVar ];
     for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) (p->refPoint)[i] = DA__1stEnv.DA__refPoint[i];
     p->accuWgt = DA__1stEnv.DA__MaxWeight;
     }
   while( q = (LieOperator*) DA__1stEnv.DA__predefLieOp.get() ) {
     q->v = new DA[ DA__1stEnv.DA__NumVar ];
     q->refPoint = new double[ DA__1stEnv.DA__NumVar ];
     for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) (q->refPoint)[i] = DA__1stEnv.DA__refPoint[i];
     }
 
   // Load the DA__1stEnv.DA__numPaths array with binomial coefficients;
   // required by Wilf's algorithm for ranking monomials.
   DA__1stEnv.DA__numPaths = imatrix( 0, w, 1, n );
   for( i = 0; i <= w; i++ )
     for( j = 1; j <= n; j++ )
       DA__1stEnv.DA__numPaths[i][j] = bcfRec( i + j - 1, i );
 
   // Initialize the DA__coordPool dlist
   int* counter;
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
     counter = new int(i);
     DA__coordPool.append( counter );
     }
 
   }
 
 DACSetup( n, w );     // ??? This should be integrated more smoothly.

}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DASetup( const int n, const int w, const double* r ) {
 int i, j;
 DA* p;
 LieOperator* q;
 
 if( DA__1stEnv.DA__allSet == 137 )
   printf( "\n*** DA ERROR *** Attempt to call DASetup twice.\n" );
 
 else {
 
   // Some error checking ..
   if( n < 1 ) {
     printf("\n*** DASetup requires at least one variable.");
     exit(0);
     }
 
   if( w < 1 ) {
     printf("\n*** DASetup requires a minimal maximum weight of 1.");
     exit(0);
     }
 
   DA__1stEnv.DA__allSet = 137;
 
   // The default reference point is set.
   DA__1stEnv.DA__refPoint = new double[ n ];
   for( i = 0; i < n; i++ ) DA__1stEnv.DA__refPoint[i] = r[i];
 
   DA__1stEnv.DA__NumVar = n;
   DA__1stEnv.DA__MaxWeight = w;
   DA__1stEnv.DA__exponent = new int[ n ];
   DA__1stEnv.DA__expCode = new char[ w + n ];
   DA__1stEnv.DA__monomial = new double[ bcfRec( w + n, n ) ];
   DA__1stEnv.DA__SpaceDim = 0;             // No DA vectors will be allowed.
   DA__1stEnv.DA__PBOK = 0;                 // No Poisson brackets allowed.
 
   DA__1stEnv.DA__AllZeroes = new int[ n ];
   for( i = 0; i < n; i++ ) DA__1stEnv.DA__AllZeroes[i] = 0;
 
   // Go through all predefined DA variables: set the reference
   // and weight accuracy.
   while( p = (DA*) DA__1stEnv.DA__predefDA.get() ) {
     p->refPoint = new double[ DA__1stEnv.DA__NumVar ];
     for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) (p->refPoint)[i] = DA__1stEnv.DA__refPoint[i];
     p->accuWgt = DA__1stEnv.DA__MaxWeight;
     }
   while( q = (LieOperator*) DA__1stEnv.DA__predefLieOp.get() ) {
     q->v = new DA[ DA__1stEnv.DA__NumVar ];
     q->refPoint = new double[ DA__1stEnv.DA__NumVar ];
     for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) (q->refPoint)[i] = DA__1stEnv.DA__refPoint[i];
     }
 
   // Load the DA__1stEnv.DA__numPaths array with binomial coefficients;
   // required by Wilf's algorithm for ranking monomials.
   DA__1stEnv.DA__numPaths = imatrix( 0, w, 1, n );
   for( i = 0; i <= w; i++ )
     for( j = 1; j <= n; j++ )
       DA__1stEnv.DA__numPaths[i][j] = bcfRec( i + j - 1, i );
 
   // Initialize the DA__coordPool dlist
   int* counter;
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
     counter = new int(i);
     DA__coordPool.append( counter );
     }
 
   }
 
 // DACSetup( n, w, r );     ??? Needs to be done!!!

}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DASetup( const int n, const int w, const int s ) {
 int i, j;
 DA* p;
 LieOperator* q;
 
 
 if( DA__1stEnv.DA__allSet == 137 )
   printf( "\n*** DA ERROR: Attempt to call DASetup twice.\n" );
 
 else {
 
   // Some error checking ..
   if( n < 1 ) {
     printf("\n*** DA ERROR: DASetup requires at least one variable.");
     exit(0);
     }
 
   if( w < 1 ) {
     printf("\n*** DA ERROR: DASetup requires minimal maximum weight of 1.");
     exit(0);
     }
 
   if ( n < s ) {
     printf( "\n*** DA ERROR: DASetup called with incompatible parameters." );
     printf( "\n**********************************************************\n" );
     exit(0);
     }
 
   DA__1stEnv.DA__allSet = 137;
 
   // The default reference point is set to the origin.
   DA__1stEnv.DA__refPoint = new double[ n ];
   for ( i = 0; i < n; i++ ) DA__1stEnv.DA__refPoint[i] = 0.0;
 
   // Set global variables.
   DA__1stEnv.DA__NumVar = n;
   DA__1stEnv.DA__MaxWeight = w;
   DA__1stEnv.DA__exponent = new int[ n ];
   DA__1stEnv.DA__expCode = new char[ w + n ];
   DA__1stEnv.DA__monomial = new double[ bcfRec( w + n, n ) ];
   DA__1stEnv.DA__DAmonomial = new DA[ bcfRec( w + n, n ) ];
   DA__1stEnv.DA__SpaceDim = s;
   DA__1stEnv.DA__dof = s/2;
   DA__1stEnv.DA__PBOK = ( 2*DA__1stEnv.DA__dof == s );
 
   DA__1stEnv.DA__AllZeroes = new int[ n ];
   for( i = 0; i < n; i++ ) DA__1stEnv.DA__AllZeroes[i] = 0;
 
   // Go through all predefined DA variables: set the reference
   // and weight accuracy.
   while( p = (DA*) DA__1stEnv.DA__predefDA.get() ) {
     p->refPoint = new double[ DA__1stEnv.DA__NumVar ];
     for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) (p->refPoint)[i] = DA__1stEnv.DA__refPoint[i];
     p->accuWgt = DA__1stEnv.DA__MaxWeight;
     }
   while( q = (LieOperator*) DA__1stEnv.DA__predefLieOp.get() ) {
     q->v = new DA[ DA__1stEnv.DA__NumVar ];
     q->refPoint = new double[ DA__1stEnv.DA__NumVar ];
     for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) (q->refPoint)[i] = DA__1stEnv.DA__refPoint[i];
     }
 
   // Load the DA__1stEnv.DA__numPaths array with binomial coefficients;
   // required by Wilf's algorithm for ranking monomials.
   DA__1stEnv.DA__numPaths = imatrix( 0, w, 1, n );
   for( i = 0; i <= w; i++ )
     for( j = 1; j <= n; j++ )
       DA__1stEnv.DA__numPaths[i][j] = bcfRec( i + j - 1, i );
 
   // Initialize the DA__coordPool dlist
   int* counter;
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
     counter = new int(i);
     DA__coordPool.append( counter );
     }
 
   }
 
 DACSetup( n, w, s );     // ??? This should be integrated more smoothly.

}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DASetup( const int n, const int w, const int s, const double* r ) {
 int i, j;
 DA* p;
 LieOperator* q;
 
 if( DA__1stEnv.DA__allSet == 137 )
   printf( "\n*** DA ERROR: Attempt to call DASetup twice.\n" );
 
 else {
 
   // Some error checking ..
   if( n < 1 ) {
     printf("\n*** DA ERROR: DASetup requires at least one variable.");
     exit(0);
     }
 
   if( w < 1 ) {
     printf("\n*** DA ERROR: DASetup requires minimal maximum weight of 1.");
     exit(0);
     }
 
   if( s < 2 ) {
     printf("\n*** DA ERROR: DASetup requires minimum vector size of 2.");
     exit(0);
     }
 
   if ( n < s ) {
     printf( "\n*** DA ERROR: DASetup called with incompatible parameters." );
     printf( "\n**********************************************************\n" );
     exit(0);
     }
 
   DA__1stEnv.DA__allSet = 137;
 
   // The default reference point is set.
   DA__1stEnv.DA__refPoint = new double[ n ];
   for( i = 0; i < n; i++ ) DA__1stEnv.DA__refPoint[i] = r[i];
 
   // Set global variables.
   DA__1stEnv.DA__NumVar = n;
   DA__1stEnv.DA__MaxWeight = w;
   DA__1stEnv.DA__exponent = new int[ n ];
   DA__1stEnv.DA__expCode = new char[ w + n ];
   DA__1stEnv.DA__monomial = new double[ bcfRec( w + n, n ) ];
   DA__1stEnv.DA__DAmonomial = new DA[ bcfRec( w + n, n ) ];
   DA__1stEnv.DA__SpaceDim = s;
   DA__1stEnv.DA__dof = s/2;
   DA__1stEnv.DA__PBOK = ( 2*DA__1stEnv.DA__dof == s );
 
   DA__1stEnv.DA__AllZeroes = new int[ n ];
   for( i = 0; i < n; i++ ) DA__1stEnv.DA__AllZeroes[i] = 0;
 
   // Go through all predefined DA variables: set the reference
   // and weight accuracy.
   while( p = (DA*) DA__1stEnv.DA__predefDA.get() ) {
     p->refPoint = new double[ DA__1stEnv.DA__NumVar ];
     for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) (p->refPoint)[i] = DA__1stEnv.DA__refPoint[i];
     p->accuWgt = DA__1stEnv.DA__MaxWeight;
     }
   while( q = (LieOperator*) DA__1stEnv.DA__predefLieOp.get() ) {
     q->v = new DA[ DA__1stEnv.DA__NumVar ];
     q->refPoint = new double[ DA__1stEnv.DA__NumVar ];
     for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) (q->refPoint)[i] = DA__1stEnv.DA__refPoint[i];
     }
 
   // Load the DA__1stEnv.DA__numPaths array with binomial coefficients;
   // required by Wilf's algorithm for ranking monomials.
   DA__1stEnv.DA__numPaths = imatrix( 0, w, 1, n );
   for( i = 0; i <= w; i++ )
     for( j = 1; j <= n; j++ )
       DA__1stEnv.DA__numPaths[i][j] = bcfRec( i + j - 1, i );
 
   // Initialize the DA__coordPool dlist
   int* counter;
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
     counter = new int(i);
     DA__coordPool.append( counter );
     }
 
   }
 
 // DACSetup( n, w, s, r );     ??? Needs to be done!!!

}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAFixReference( double* r ) {
 int i;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) DA__1stEnv.DA__refPoint[i] = r[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAFixReferenceAtEnd( LieOperator& x ) {
 int i;
 double* u = new double [ DA__1stEnv.DA__NumVar ];
 x.standardPart( u );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) DA__1stEnv.DA__refPoint[i] = u[i];
 delete [] u;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAFixReferenceAtStart( LieOperator& x ) {
 int i;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) DA__1stEnv.DA__refPoint[i] = x.refPoint[i];
}
 
 
 //***************************************************************
 //***************************************************************
 //***************************************************************
 //
 //     Implementation of struct DA__environment
 
 
DA__environment::DA__environment() {
  DA__monomial           = 0;
  DA__DAmonomial         = 0;
  DA__exponent           = 0;
  DA__expCode            = 0;
  DA__numPaths           = 0;
  DA__NumVar             = 0;
  DA__MaxWeight          = 0;
  DA__allSet             = 0;
  DA__weightLimit        = 0;    
  DA__SpaceDim           = -1;
  DA__dof                = 0;            
  DA__refPoint           = 0;       
  DA__AllZeroes          = 0;      
}
 
 
DA__environment::~DA__environment() {
  if( DA__allSet == 137 ) {
   delete [] DA__monomial;       
   if( DA__DAmonomial ) delete [] DA__DAmonomial;     
   delete [] DA__exponent;       
   delete [] DA__expCode;        
  
   free_imatrix( DA__numPaths, 0, DA__MaxWeight, 1, DA__NumVar ); // ???
                                 // ??? Carrying this around is stupid!!
   delete [] DA__refPoint;       
   delete [] DA__AllZeroes;      
  
   // ??? DA* p;
   // ??? while( p = (DA*) DA__predefDA.get() ) delete p;
   // ??? LieOperator* q;
   // ??? while( q = (LieOperator*) DA__predefLieOp.get() ) delete q;
  }
}



//***************************************************************
//***************************************************************
//***************************************************************
//
//      Implementation of Class DA

//    Constructors and destructors    |||||||||||||||||||||||||||

DA::DA() {
 int i;
 
 weight = -1;
 count = 0;
 accuWgt = DA__1stEnv.DA__MaxWeight;
 
 if( DA__1stEnv.DA__allSet == 137 ) {
   refPoint = new double[ DA__1stEnv.DA__NumVar ];
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = DA__1stEnv.DA__refPoint[i];
   }
 else {
   DA__1stEnv.DA__predefDA.insert( this );
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA::DA( double x ) {
 int* ndx;
 int i;
 
 if( DA__1stEnv.DA__allSet != 137 ) {
   printf( "\n*** DA::DA( double ) ERROR *** " );
   printf( "Prior call to DASetup required.\n" );
   exit(0);
   }
 
 clear();
 weight = 0;
 count = 0;
 accuWgt = DA__1stEnv.DA__MaxWeight;
 
 refPoint = new double[ DA__1stEnv.DA__NumVar ];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = DA__1stEnv.DA__refPoint[i];
 
                             // ??? There is some danger here!  This constructor
                             //     governs the conversion of double into DA.
                             //     In an expression like 3.0 * z, where z is a DA,
                             //     the multiplication may not go through if the
                             //     current reference point has changed since z
                             //     was created.  One way around this is to overload
                             //     all arithmetic operators explicitly so conversion
                             //     is never necessary.
 
 ndx = new int[ DA__1stEnv.DA__NumVar ];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) ndx[i] = 0;
 insert( new DAterm( ndx, x ) );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA::DA( DA& x ) {
 dlist_iterator getNext( (dlist&) x );
 DAterm* p;
 DAterm* q;
 int i;
 
 if( DA__1stEnv.DA__allSet != 137 ) {
   printf( "\n*** DA::DA( DA& ) ERROR *** " );
   printf( "Prior call to DASetup required.\n" );
   exit(0);
   }
 
 if( DA__1stEnv.DA__allSet != 137 ) {
   printf( "\n*** DA::DA( DA& ) ERROR *** " );
   printf( "Prior call to DASetup required.\n" );
   exit(0);
   }
 
 while( p = (DAterm*) getNext() ) {
   q = new DAterm( p );
   append( q );
   }
 count    = x.count;
 weight   = x.weight;
 accuWgt  = x.accuWgt;
 refPoint = new double[ DA__1stEnv.DA__NumVar ];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = x.refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA::~DA() {
 clear();
 delete [] refPoint;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//     Member functions(public)  |||||||||||||||||||||||||||||||

void DA::addTerm( DAterm* a) {
 dlist_traversor getNext( *(dlist*) this );
 dlink* p;
 
 // If the value of *a is 0, don't bother with it unless
 // the weight is also 0.
 if( ( a -> value == 0.0 ) && ( a -> weight != 0 ) ) return;
 
 //
 // In the event that the candidate is lighter than the first
 // element in the DA dlist ... or the list is empty
 //
 p = getNext();
 
 if( p == 0 ) {
   insert( a );
   return;
   }
 
 if(     *a   <=   ( *(DAterm*) (p->info()) )   ) {
   if(   *a   %=   ( *(DAterm*) (p->info()) )   ) {
 
     (( (DAterm*) (p->info()) ) -> value ) += ( a -> value );
 
     if(
         (
           fabs( ( (DAterm*) (p->info()) ) -> value ) < MX_SMALL*fabs( a -> value )
         )
         // REMOVE ??? &&
         // REMOVE ??? (
         // REMOVE ???   p != ( dlist::lastPtr() ) -> nextPtr()
         // REMOVE ??? )
       )
 
         delete remove( p );
 
     delete a;
     return;
     }
 
   else {
     insert( a );
     return;
     }
 
   }
 
 //
 // Otherwise, search through the list
 //
 while( p = getNext() ){
 
   if(     *a   <=   ( *(DAterm*) (p->info()) )   ) {
     if(   *a   %=   ( *(DAterm*) (p->info()) )   ) {
 
       (( (DAterm*) (p->info()) ) -> value ) += ( a -> value );
 
       if(
	   (
	     fabs( ( (DAterm*) (p->info()) ) -> value ) < MX_SMALL*fabs( a -> value )
	   )
	   // REMOVE ??? &&
	   // REMOVE ??? (
	   // REMOVE ???   p != ( dlist::lastPtr() ) -> nextPtr()
	   // REMOVE ??? )
	 )
 
         delete remove( p );
 
       delete a;
       return;
       }
 
     else {
       p -> putAbove( new dlink( a, 0, 0 ) );
       (this->count)++;
       if( (this->weight) < (a->weight) ) this->weight = a->weight;
       return;
       }
 
     }
   }
 
 //
 //  The new entry is heavier than existing ones.
 //
 append( a );
 return;
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::fixReference( double* r ) {
 int i;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = r[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::fixReference() {
 int i;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = DA__1stEnv.DA__refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::fixReference( DA& x ) {
 int i;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = x.refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::fixReferenceAtEnd( LieOperator& x ) {
 int i;
 double* u = new double [ DA__1stEnv.DA__NumVar ];
 x.standardPart( u );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = u[i];
 delete [] u;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::fixReferenceAtStart( LieOperator& x ) {
 int i;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = x.refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::getReference( double* r ) {
 int i;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) r[i] = refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char DA::isNilpotent() {
 dlist_iterator getNext( *(dlist*) this );
 DAterm* p = (DAterm*) getNext();
 if( p->weight == 0 && p->value != 0.0 ) return 0;
 else                                    return 1;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::peekAt() {
 dlist_traversor getNext( *(dlist*) this );
 int i;
 DAterm* p;
 dlink* q;
 printf( "\nCount  = %d, Weight = %d, Max accurate weight = %d\n",
          count, weight, accuWgt );
 printf( "Reference point:  \n" );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) printf( "%e  ", refPoint[i] );
 printf( "\n" );
 while( q = getNext() ) {
   p = (DAterm*) q->info();
   printf( "Weight: %d   Value: %e  || ",
           p -> weight, p -> value );
   printf("Addresses: %d %d %d : %d\n", q->prevPtr(), q, q->nextPtr(), p );
   printf("Index:  ");
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
     printf( "%d  ", (p -> index)[i] );
   printf("\n\n");
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::printCoeffs() {
 dlist_traversor getNext( *(dlist*) this );
 int i;
 DAterm* p;
 dlink* q;
 printf( "\nCount  = %d, Weight = %d, Max accurate weight = %d\n",
          count, weight, accuWgt );
 printf( "Reference point: " );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) printf( "%e  ", refPoint[i] );
 printf( "\n\n" );
 while( q = getNext() ) {
   p = (DAterm*) q->info();
   printf("Index:  ");
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
     printf( "%3d ", (p -> index)[i] );
   printf( "   Value: %14.6le  ", p -> value );
   printf("\n");
   }
 printf( "\n\n" );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::peekAt( int dummyInteger ) {
 dlist_traversor getNext( *(dlist*) this );
 int i;
 DAterm* p;
 dlink* q;
 fprintf( DA__scratchFile,
          "\nCount  = %d, Weight = %d, Max accurate weight = %d\n",
          count, weight, accuWgt );
 fprintf( DA__scratchFile, "Reference point:  \n" );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
   fprintf( DA__scratchFile, "%e  ", refPoint[i] );
 fprintf( DA__scratchFile, "\n" );
 while( q = getNext() ) {
   p = (DAterm*) q->info();
   fprintf( DA__scratchFile, "Weight: %d   Value: %e  || ",
           p -> weight, p -> value );
   fprintf( DA__scratchFile, "Addresses: %d %d %d : %d\n",
                  q->prevPtr(), q, q->nextPtr(), p );
   fprintf( DA__scratchFile, "Index:  ");
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
     fprintf( DA__scratchFile, "%d  ", (p -> index)[i] );
   fprintf( DA__scratchFile, "\n\n");
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::printCoeffs( int dummyInteger ) {
 dlist_traversor getNext( *(dlist*) this );
 int i;
 DAterm* p;
 dlink* q;
 fprintf( DA__scratchFile, "\nCount  = %d, Weight = %d, Max accurate weight = %d\n",
          count, weight, accuWgt );
 fprintf( DA__scratchFile, "Reference point:  " );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) fprintf( DA__scratchFile, "%e  ", refPoint[i] );
 fprintf( DA__scratchFile, "\n\n" );
 while( q = getNext() ) {
   p = (DAterm*) q->info();
   fprintf( DA__scratchFile,"Index:  ");
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
     fprintf( DA__scratchFile, "%3d ", (p -> index)[i] );
   fprintf( DA__scratchFile, "   Value: %14.6e  ", p -> value );
   fprintf( DA__scratchFile,"\n");
   }
 fprintf( DA__scratchFile, "\n\n" );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

dlist DA::image() {       // ??? Problem: nothing is recorded about the
                          // ??? reference point.

 dlist_iterator getNext( *(dlist*) this );
 DAterm* q;
 dlist ret;

 // ??? for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) fprintf( DA__scratchFile, "%e  ", refPoint[i] );

 while( q = (DAterm*) getNext() )
   ret.append( new DAtermData( *q ) );

 return ret;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::writeToFile( char* fileName ) {
 dlist_traversor getNext( *(dlist*) this );
 int i;
 DAterm* p;
 dlink* q;
 
 DA__scratchFile = fopen( fileName, "w" );
 
 fprintf( DA__scratchFile,
          "\nCount  = %d, Weight = %d, Max accurate weight = %d\n",
          count, weight, accuWgt );
 fprintf( DA__scratchFile, "Reference point:  \n" );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
   fprintf( DA__scratchFile, "%e  ", refPoint[i] );
 fprintf( DA__scratchFile, "\n" );
 while( q = getNext() ) {
   p = (DAterm*) q->info();
   fprintf( DA__scratchFile, "Weight: %d   Value: %e  || ",
           p -> weight, p -> value );
   fprintf( DA__scratchFile, "Addresses: %d %d %d : %d\n",
                  q->prevPtr(), q, q->nextPtr(), p );
   fprintf( DA__scratchFile, "Index:  ");
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
     fprintf( DA__scratchFile, "%d  ", (p -> index)[i] );
   fprintf( DA__scratchFile, "\n\n");
   }
 
 fclose( DA__scratchFile );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::writeToFile( FILE* filePtr ) {
 dlist_traversor getNext( *(dlist*) this );
 int i;
 DAterm* p;
 dlink* q;
 
 fprintf( filePtr,
          "\nCount  = %d, Weight = %d, Max accurate weight = %d\n",
          count, weight, accuWgt );
 fprintf( filePtr, "Reference point:  \n" );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
   fprintf( filePtr, "%e  ", refPoint[i] );
 fprintf( filePtr, "\n" );
 while( q = getNext() ) {
   p = (DAterm*) q->info();
   fprintf( filePtr, "Weight: %d   Value: %e  || ",
           p -> weight, p -> value );
   fprintf( filePtr, "Addresses: %d %d %d : %d\n",
                  q->prevPtr(), q, q->nextPtr(), p );
   fprintf( filePtr, "Index:  ");
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
     fprintf( filePtr, "%d  ", (p -> index)[i] );
   fprintf( filePtr, "\n\n");
   }
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::scaleBy( double y ) {
 DAterm* p;
 dlist_iterator getNext( *(dlist*) this );
 
 if ( this->count < 1 ) {
   printf( "\n\n*** WARNING::DA::scaleBy: function invoked " );
   printf(          "by null DA variable with address %d.\n",   this );
   return;
   }
 
 while( p = (DAterm*) getNext() )   p->value *= y;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::setVariable( double x, int j ) {
 int* ndx;
 int i;
 
 clear();
 if( ( j < 0 ) || ( j >= DA__1stEnv.DA__NumVar ) ) return;
 
 ndx = new int[ DA__1stEnv.DA__NumVar ];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) ndx[i] = 0;
 ndx[j] = 1;
 insert( new DAterm( ndx, 1.0 ) );
 delete [] ndx;
 
 ndx = new int[ DA__1stEnv.DA__NumVar ];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) ndx[i] = 0;
 insert( new DAterm( ndx, x ) );
 delete [] ndx;
 
 DA__1stEnv.DA__refPoint[j] = x;
 refPoint[j] = x;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::setVariable( int j ) {
 int* ndx;
 int i;
 double x;
 
 clear();
 if( ( j < 0 ) || ( j >= DA__1stEnv.DA__NumVar ) ) return;
 
 x = DA__1stEnv.DA__refPoint[j];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = DA__1stEnv.DA__refPoint[i];
 
 ndx = new int[ DA__1stEnv.DA__NumVar ];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) ndx[i] = 0;
 ndx[j] = 1;
 insert( new DAterm( ndx, 1.0 ) );
 
 ndx = new int[ DA__1stEnv.DA__NumVar ];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) ndx[i] = 0;
 insert( new DAterm( ndx, x ) );
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::insert( DAterm* a) {
 dlist::insert(a);
 count++;
 if( weight < (a->weight) ) weight = a->weight;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAterm* DA::get() {
 DAterm* p;
 if( count <= 0 ) return 0;
 p = ((DAterm*) dlist::get());
 if( --count == 0 ) weight = -1;
 return p;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::append( DAterm* a) {
 dlist::append(a);
 count++;
 if( weight < (a->weight) ) weight = a->weight;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAterm* DA::remove( dlink* w ) {
 DAterm* a;
 dlink* predecessor;
 dlink* successor;
 int predWeight;
 int succWeight;
 
 predecessor = w->prevPtr();
 successor   = w->nextPtr();
 
 a = (DAterm*) dlist::remove( w );
 count--;
 
 if( count == 0 ) {
   weight = -1;
   return a;
   }
 
 if ( weight > a->weight ) return a;
 
 predWeight = ( (DAterm*) ( predecessor->info() ) ) -> weight;
 succWeight = ( (DAterm*) ( successor->info() ) ) -> weight;
 weight = predWeight;
 if( succWeight > weight ) weight = succWeight;
 return a;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

double DA::standardPart() {
 dlist_iterator g( (dlist&) *this );
 DAterm* p; 
 if( count < 1 )       return 0.0;
 p = (DAterm*) g();
 if( p->weight  == 0 ) return p->value;
                       return 0.0;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA::clear() {
 DAterm* p;
 while( p = get() )  
   delete p;
 dlist::clear();
 count   = 0;
 weight  = -1;
 accuWgt = DA__1stEnv.DA__MaxWeight;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

double DA::weightedDerivative( int* ind ) {
 int i, w;
 DA z;
 DAterm* p;
 char theOne;
 
 w = 0;
 for ( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) w += ind[i];
 z = filter( w, w );
 if ( z.count < 1 ) return 0.0;
 
 // --- Old code ------
 // dlist_iterator getNext( (dlist) z );
 // --- New code ------    Oct 2, 1992
 dlist_iterator getNext( (dlist&) z );
 // -------------------
 while( p = (DAterm*) getNext() ) {
   theOne = 1;
   for ( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
     theOne = theOne && ( (p->index)[i] == ind[i] );
   if( theOne ) return p->value;
   }
 
 return 0.0;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

double DA::derivative( int* ind ) {
 double n;
 double multiplier;
 double d;
 int i;
 
 d = weightedDerivative( ind );
 if ( d == 0.0 ) return 0.0;
 
 multiplier = 1.0;
 for ( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   n = ind[i];
   while(n)  multiplier *= n--;
   }
 
 return multiplier*d;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& DA::filter( int wgtLo, int wgtHi ) { 
 DA* z = new DA;
 dlist_iterator getNext( *(dlist*) this );
 DAterm* p;
 DAterm* q;
 int numTerms;
 int wgt, upperWgt;
 
 if( ( wgtLo <= 0 ) && ( wgtHi > DA__1stEnv.DA__MaxWeight ) )
   return *this;
 
 numTerms = 0;
 upperWgt = 0;
 
 while( p = (DAterm*) getNext() ) {
   wgt = p->weight;
   if( ( wgt >= wgtLo ) && ( wgt <= wgtHi ) ) {
     q = new DAterm( p );
     z->append( q );
     if( wgt > upperWgt ) upperWgt = wgt;
     numTerms++;
     }
   }
 
 z->count = numTerms;   // ??? Is this necessary?
 z->weight = upperWgt;
 z->accuWgt = accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& DA::filter( char (*f) ( int*, double ) ) { 
 DA* z = new DA;
 dlist_iterator getNext( *(dlist*) this );
 DAterm* p;
 DAterm* q;

 int i;
 int nv = DA__1stEnv.DA__NumVar;
 int* oldIndex = new int[ nv ];

 while( p = (DAterm*) getNext() ) {
  for( i = 0; i < nv; i++ ) oldIndex[i] = p->index[i];

  if( (*f)( p->index, p->value ) ) {
   q = new DAterm( p );
   z->append( q );
  }

  for( i = 0; i < nv; i++ ) 
   if( oldIndex[i] != p->index[i] ) {
    printf( "\n" );
    printf( "*** ERROR ***                                      \n" );
    printf( "*** ERROR *** DA& DA::filter( char (*f) ( int*, double ) \n" );
    printf( "*** ERROR *** The test routine is not allowed      \n" );
    printf( "*** ERROR *** to change the values in the index    \n" );
    printf( "*** ERROR *** array!!                              \n" );
    printf( "*** ERROR ***                                      \n" );
    exit(0);
   }
 }

 delete [] oldIndex;
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& DA::operator()( DA* y ) { 
 DA* z = new DA;
 DA* u;
 DA term;
 int i;
 int j;
 int w;
 DAterm* p;
 
 u = new DA [ DA__1stEnv.DA__NumVar ];
 
 // Check consistency of reference points.
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   for( j = 0; j < DA__1stEnv.DA__NumVar; j++ )
     if( y[i].refPoint[j] != y[0].refPoint[j] ){
       printf( "\n*** DA DA::operator() ERROR: Inconsistent reference points.\n" );
       printf("y[%d].refPoint[%d] != y[0].refPoint[%d]\n", i, j, j);
       printf("%lf != %lf\n", y[i].refPoint[j], y[0].refPoint[j]);
       exit(1);
     }
   if( this -> refPoint[i] != y[i].weightedDerivative( DA__1stEnv.DA__AllZeroes ) ) {
     printf( "\n*** DA DA::operator() ERROR: Inconsistent reference points.\n" );
     printf("this -> refPoint[%d] != y[%d].weightedDerivative( DA__1stEnv.DA__AllZeroes )\n",
             i, i);
     printf("%lf != %lf\n",
             this -> refPoint[i], y[i].weightedDerivative( DA__1stEnv.DA__AllZeroes ));
     exit(1);
   }
 }
 
 // Subtract reference point prior to concatenation.
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   u[i] = y[i];
   p    = ( u[i] ).get();
   if( p->weight != 0 ) {
     printf( "\n*** DA DA::operator() ERROR: Argument has no nonstandard part!!\n" );
     exit(0);
   }
 }
 
 // Evaluate and store monomials.
 
 // The zeroth one.
 DA__1stEnv.DA__DAmonomial[0] = 1.0;
 DA__1stEnv.DA__DAmonomial[0].fixReference( y[0] );
 
 // For all higher weights ...
 for( w = 1; w <= ( this->weight ); w++ )
 
   // Get the next set of exponents of weight w.
   while( nexcom( w, DA__1stEnv.DA__NumVar, DA__1stEnv.DA__exponent ) ) {
 
     // Find the first non-zero exponent.
     i = 0;
     while( !( DA__1stEnv.DA__exponent[i++] ) ) ;
     i--;
 
     // The value of the monomial associated with this composition
     // is obtained by multiplying a factor into a previously
     // computed monomial.
     ( DA__1stEnv.DA__exponent[i] )--;
     DA__monoCode();
     term = DA__1stEnv.DA__DAmonomial[ DA__monoRank() ];
     ( DA__1stEnv.DA__exponent[i] )++;
     DA__monoCode();
     DA__1stEnv.DA__DAmonomial[ DA__monoRank() ] = term * u[i];   // ??? Is this OK???
 
     } // End while loop.
 
 // Monomials have been stored.
 // Now traverse the DA variable and evaluate.
 
 *z = concat( *this );
 
 // Set the correct reference point in z.
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = y[0].refPoint[i];
 
 delete [] u;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& DA::operator()( LieOperator& y ) { 
 DA* z = new DA;
 LieOperator u;
 DA term;
 int i;
 int w;
 dlist_iterator getNext( *(dlist*) this );
 DAterm* p;
 
 u = y;
 u.reset();

 // Check consistency of reference points.
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
   if( this -> refPoint[i] != ( y.v[i] ).weightedDerivative( DA__1stEnv.DA__AllZeroes ) ) {
     printf( "\n*** DA DA::operator() ERROR: Inconsistent reference points.\n" );
     exit(0);
     }
 
 // In the event that the argument y is null
 if( u.weight <= 0 ) {
  if( ( p = (DAterm*) getNext() ) == 0 ) {   // ??? Should this be an error
   DA__garbage.store( z );                   // ??? condition instead?
   return *z;
  }
  if( p->weight == 0 ) *z = 0.0;
  else                 *z = p->value;
  DA__garbage.store( z );
  return *z;
 }

 // Subtract reference point prior to concatenation.
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
  p = ( u.v[i] ).get();
  if( p->weight != 0 ) {
    printf( "\n*** DA DA::operator() ERROR: Argument has no nonstandard part!!\n" );
    exit(0);
  }
 }
 
 // Evaluate and store monomials.
 
 // The zeroth one.
 DA__1stEnv.DA__DAmonomial[0] = 1.0;
 DA__1stEnv.DA__DAmonomial[0].fixReferenceAtStart( y );
 
 // For all higher weights ...
 for( w = 1; w <= ( this->weight ); w++ )
 
   // Get the next set of exponents of weight w.
   while( nexcom( w, DA__1stEnv.DA__NumVar, DA__1stEnv.DA__exponent ) ) {
 
     // Find the first non-zero exponent.
     i = 0;
     while( !( DA__1stEnv.DA__exponent[i++] ) ) ;
     i--;
 
     // The value of the monomial associated with this composition
     // is obtained by multiplying a factor into a previously
     // computed monomial.
     ( DA__1stEnv.DA__exponent[i] )--;
     DA__monoCode();
     term = DA__1stEnv.DA__DAmonomial[ DA__monoRank() ];
     ( DA__1stEnv.DA__exponent[i] )++;
     DA__monoCode();
     DA__1stEnv.DA__DAmonomial[ DA__monoRank() ] = term * u.v[i];   // ??? Is this OK???
 
     } // End while loop.
 
 // Monomials have been stored.
 // Now traverse the DA variable and evaluate.
 
 *z = concat( *this );
 
 // Set the correct reference point in z.
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = y.refPoint[i];
 
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

double DA::operator()( double* x ) {
 DAterm* p;
 double v;
 int w;
 int i;
 double term;
 double* u;
 dlist_iterator getNext( *(dlist*) this );
 
 u = new double[ DA__1stEnv.DA__NumVar ];   // ??? Check other places in the source
                                 // code where this was not done correctly!!
 
 // Subtract off the reference point.
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) u[i] = x[i] - refPoint[i];
 
 // Evaluate and store monomials.
 
 // The zeroth one.
 DA__1stEnv.DA__monomial[0] = 1.0;
 
 // For all higher weights ...
 for( w = 1; w <= weight; w++ )
 
   // Get the next set of exponents of weight w.
   while( nexcom( w, DA__1stEnv.DA__NumVar, DA__1stEnv.DA__exponent ) ) {
 
     // Find the first non-zero exponent.
     i = 0;
     while( !( DA__1stEnv.DA__exponent[i++] ) ) ;
     i--;
 
     // The value of the monomial associated with this composition
     // is obtained by multiplying a factor into a previously
     // computed monomial.
     ( DA__1stEnv.DA__exponent[i] )--;
     DA__monoCode();
     term = DA__1stEnv.DA__monomial[ DA__monoRank() ];
     ( DA__1stEnv.DA__exponent[i] )++;
     DA__monoCode();
     DA__1stEnv.DA__monomial[ DA__monoRank() ] = term * u[i];
 
     } // End while loop.
 
 // Monomials have been now stored at this point.
 // Now traverse the DA variable and evaluate.
 
 v = 0.0;
 
 while( p = (DAterm*) getNext() ) {
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) DA__1stEnv.DA__exponent[i] = (p->index)[i];
   DA__monoCode();
   v += ( p->value ) * ( DA__1stEnv.DA__monomial[ DA__monoRank() ] );
   }
 
 delete [] u;
 
 return v;
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& DA::D( int* n ) { 
 char noTermAdded;
 int f, i, j, k, w;
 DA* z = new DA;
 dlist_iterator getNext( *(dlist*) this );
 DAterm* p;
 DAterm* q;
 
 noTermAdded = 1;
 
 // --- Preliminary check of index set.
 
 w = 0;
 
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   if( n[i] < 0 ) {
     printf( "\n*** DA ERROR: Cannot differentiate with negative index." );
     printf( "\n*******************************************************\n" );
     exit(0);
     }
   w += n[i];
   }
 
 if( w > accuWgt ) {
   printf( "\n*** DA ERROR: Differentiation request beyond accuracy allowed." );
   printf( "\n**************************************************************\n" );
   exit(0);
   }
 
 if( w == 0 ) return *this;      // ??? Will this work, or should I set z = *this
                                 // and then return z ???
 
 // --- Construct the derivative one link at a time.
 // --- ( See note Obs.4 )
 
 while( p = (DAterm*) getNext() ) {
 
   q = new DAterm( p );
 
   char doit = 1;
   // -- Reset the index.
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) doit = doit && ( ( q->index[i] -= n[i] ) >= 0 );
 
   if( doit ) {
     // -- Build factorial multiplier.
     f = 1;
     for( k = 0; k < DA__1stEnv.DA__NumVar; k++ ) {
       j = q->index[k];
       for( i = 0; i < n[k]; i++ ) f *= ++j;
       }
     if( f <= 0 ) {
       printf( "\n*** DA ERROR: Horrible, unexplainable error while differentiating!" );
       printf( "\n******************************************************************\n" );
       exit(0);
       }                           // Super fussbudget!! ( f "must" be positive )
   
     // -- Make final changes in private data of the DAterm and
     //    absorb it into the answer.
     (q->value) *= f;              // OK. So I'm a fussbudget with parentheses again ..
     (q->weight ) -= w;
   
     noTermAdded = 0;
     /* DGN    if( abs(q->coeff()) < MX_SMALL && abs(q->coeff()) > 0.0 ) printf( "\nDGN> From DA& DA::D( int* n )\n" ); */
     z->addTerm( q );               // ??? This also may be unnecessarily conservative.
                                    // The append function may be adequate, if the
                                    // ordering is preserved. ???
   
     } 
   }
 
 if( noTermAdded ) *z = 0.0;
 
 
 // --- Finally, adjust accuWgt and return value
 
 z->accuWgt = accuWgt - w;       // ??? Is this correct ???

 DA__garbage.store( z );
 return *z;
}
 

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& DA::inverse() {
 if( DA__1stEnv.DA__SpaceDim != 1 ) {
  printf( "\n" );
  printf( "*** ERROR ***                                     \n" );
  printf( "*** ERROR ***  DA& DA::inverse()                  \n" );
  printf( "*** ERROR ***  This method can be called only     \n" );
  printf( "*** ERROR ***  if there is one and only one       \n" );
  printf( "*** ERROR ***  coordinate.  You have %d.          \n", DA__1stEnv.DA__SpaceDim );
  printf( "*** ERROR ***                                     \n" );
  exit(0);
 }

 DA* z = new DA;

 DA x, v;
 DA  g;
 int d = 1;

 x.setVariable(0.0, 0);   // ??? Work on this!!!
 g = D(&d);
 
 int i = 0;
 *z = x;
 v = ( operator()(z) - x ) / g(z);
 while( ( i++ < MX_MAXITER ) &&  ( v != 0.0 ) ) {
  *z -= v;
  v = ( operator()(z) - x ) / g(z);
 }

 DA__garbage.store( z );
 return *z;
}



//***************************************************************
//***************************************************************
//***************************************************************
//
//      The overloaded operators for class DA
//
ostream& operator<<(ostream& os, DA& x) {
 dlist_traversor getNext( (dlist&) x );
 int i;
 DAterm* p;
 dlink* q;

 os << "\n Count = " << x.count << ", Weight = " << x.weight;
 os << ", Max accurate weight = " << x.accuWgt << endl;
 os << "Reference point: ";
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) 
   os << x.refPoint[i];
 os << "\n\n";

 while( q = getNext() ) {
   p = (DAterm*) q->info();
   os << "Index: ";
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
     os << p -> index[i];
  os << "   Value: " << p -> value << endl;
 }
 return os << "\n" << endl;
}

char operator==( DA& x, DA& y ) {
 dlist_iterator getNextX( (dlist&) x );
 dlist_iterator getNextY( (dlist&) y );
 DAterm* p;
 DAterm* q;
 int i;
 
 if( ( x.count   != y.count )   ||
     ( x.weight  != y.weight )  ||
     ( x.accuWgt != y.accuWgt )
   ) return 0;
 
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
   if( x.refPoint[i] != y.refPoint[i] ) return 0;
 
 while( p = (DAterm*) getNextX() ) {
   if( !( q = (DAterm*) getNextY() ) ) return 0;
   if( !( *p == *q ) ) return 0;
   }
 
 if( (DAterm*) getNextY() ) {
   printf( "\n*** ERROR: Inconsistency in DA operator==\n" );
     // This point should never be reached, since that would imply that
     // x.count != y.count
   return 0;
   }
 
 return 1;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator==( DA& x, double& y ) {
 char result = 1;
 dlist_iterator getNext( (dlist&) x );
 DAterm* p;

 if( x.count < 1 ) {
  if( y == 0.0 ) return 1;
  else           return 0;
 }

 while( p = (DAterm*) getNext() ) 
  result = result && ( p->weight == 0 ? p->value == y : 
                                        p->value == 0.0 );

  // REMOVE ??? result = result && ( ( ( p->weight == 0 ) && ( p->value == y   ) )
  // REMOVE ???                      ||
  // REMOVE ???                      ( ( p->weight != 0 ) && ( p->value == 0.0 ) )
  // REMOVE ???                    )
  // REMOVE ??? 
 return result;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator==( double& y, DA& x ){
 return x == y;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator!=( DA& x, DA& y ) {
 return !( x == y );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator!=( DA& x, double& y ) {
 return !( x == y );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator!=( double& x, DA& y ) {
 return !( x == y );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& DA::operator=( DA& x ) {
 dlist_iterator getNext( (dlist&) x );
 DAterm* p;
 DAterm* q;
 int i;
 
 if( this == &x ) return *this;
 
 clear();
 while( p = (DAterm*) getNext() ) {
   q = new DAterm( p );
   append( q );
   }
 count   = x.count;
 weight  = x.weight;
 accuWgt = x.accuWgt;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = x.refPoint[i];
 return *this;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& DA::operator+=( double& x ) {   // ??? Untested!!
 int i;
 dlist_iterator getNext( *(dlist*) this );
 DAterm* p;
 DAterm* q;
 p = (DAterm*) getNext();

 if ( p->weight == 0 ) { 
  p->value += x;
  if( fabs( p->value ) <  MX_SMALL*fabs(x) ) p->value = 0.0;
 }

 else {
   q = new DAterm;
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) q->index[i] = 0;
   q->weight = 0;
   q->value = x;
   insert( q );
 }

 return *this;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& operator+( DA& x, DA& y ) {        // ??? This should be modified so that
 DA* z = new DA;                       // terms beyond the accurate weight of
 DAterm* p;                            // x or y are not computed and carried
 DAterm* q;                            // into the answer.
 dlist_iterator gx( (dlist&) x );
 dlist_iterator gy( (dlist&) y );
 int i;
 
 // Check for consistency and set reference point of the sum.
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   if( x.refPoint[i] != y.refPoint[i] ) {
     printf( "\n*** DA ADDITION ERROR: Inconsistent reference points.\n" );
     exit(0);
     }
   z->refPoint[i] = x.refPoint[i];
   }
 
 // If one of the arguments is void, then return the other ..
 if( x.count < 1 ) return y;
 if( y.count < 1 ) return x;
 
 // .. otherwise, continue normal operations.
 if( x.count > y.count ) {
   *z = x;
   while( p = (DAterm*) gy() ) {
     q = new DAterm( p );
     /* DGN    if( abs(q->coeff()) < MX_SMALL && abs(q->coeff()) > 0.0 ) printf( "\nDGN> (1) From DA& operator+( DA& x, DA& y )\n" ); */
     z->addTerm( q );
     }
   }
 
 else {
   *z = y;
   while( p = (DAterm*) gx() ) {
     q = new DAterm( p );
     /* DGN    if( abs(q->coeff()) < MX_SMALL && abs(q->coeff()) > 0.0 ) printf( "\nDGN> (2) From DA& operator+( DA& x, DA& y )\n" ); */
     z->addTerm( q );
     }
   }
 
 // Determine the maximum weight computed accurately.
 if( x.accuWgt < y.accuWgt ) z->accuWgt = x.accuWgt;
 else                        z->accuWgt = y.accuWgt;
 
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& operator+( DA& x, double& y ) {
 DA* z = new DA;
 
 *z = x;
 *z += y;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& operator+( double& y, DA&  x ) {
 DA* z = new DA;
 
 *z = x;
 *z += y;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& operator-( DA& y ) {  
 DA* z = new DA;
 dlist_iterator getNext( (dlist&) y );
 DAterm* p;
 DAterm* q;
 int i;
 
 // If the argument is void, then return it ..
 if( y.count < 1 ) return y;
 
 // .. otherwise continue normal operations.
 z->clear();
 
 // Insert the first one
 p = (DAterm*) getNext();
 q = new DAterm;
 *q = *p;
 q->value = - ( p->value );
 z->insert( q );
 
 // and append the rest
 while( p = (DAterm*) getNext() ){
   q = new DAterm;
   *q = *p;
   q->value = - ( p->value );
   z->append( q );
   }
 
 z->weight  = y.weight;
 z->accuWgt = y.accuWgt;
 z->count   = y.count;
 
 // Set the reference point.
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = y.refPoint[i];
 
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& operator-( DA& x, DA& y ) {  
 DA* z = new DA;
 DAterm* p;
 DAterm* q;
 dlist_iterator gx( (dlist&) x );
 dlist_iterator gy( (dlist&) y );
 int i;
 
 // Check for consistency and set reference point of the difference.
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   if( x.refPoint[i] != y.refPoint[i] ) {
     printf( "\n*** DA SUBTRACTION ERROR: Inconsistent reference points.\n" );
     exit(0);
     }
   z->refPoint[i] = x.refPoint[i];
   }
 
 // If one of the arguments is void, then return the other ..
 if( x.count < 1 ) return -y;
 if( y.count < 1 ) return x;
 
 // .. otherwise, continue normal operations.
 if( x.count > y.count ) {
   *z = x;
   while( p = (DAterm*) gy() ) {
     q = new DAterm( p );
     ( q->value ) = - ( q->value );
     /* DGN    if( abs(q->coeff()) < MX_SMALL && abs(q->coeff()) > 0.0 ) printf( "\nDGN (1) From DA& operator-( DA& x, DA& y )\n" ); */
     z->addTerm( q );
     }
   }
 
 else {
   *z = - y;
   while( p = (DAterm*) gx() ) {
     q = new DAterm( p );
     /* DGN    if( abs(q->coeff()) < MX_SMALL && abs(q->coeff()) > 0.0 ) printf( "\nDGN (1) From DA& operator-( DA& x, DA& y )\n" ); */
     z->addTerm( q );
     }
   }
 
 // Determine the maximum weight computed accurately.
 if( x.accuWgt < y.accuWgt ) z->accuWgt = x.accuWgt;  // ??? Change this too, as in
 else                        z->accuWgt = y.accuWgt;  // ??? operaotr+
 
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& operator*( DA& x, DA& y ) {        // ??? This should be modified so that
 DA* z = new DA;                       // terms beyond the accurate weight of
 DAterm* p;                            // x or y are not computed and carried
 DAterm* q;                            // into the answer.
 DAterm* r;
 dlist_looper gx( (dlist&) x );
 dlist_looper gy( (dlist&) y );
 int i;
 
 // Check for consistency and set reference point of the product.
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   if( x.refPoint[i] != y.refPoint[i] ) {
     printf( "\n*** DA MULTIPLICATION ERROR: Inconsistent reference points.\n" );
     exit(0);
     }
   z->refPoint[i] = x.refPoint[i];
   }
 
 // If one of the arguments is void, return it ..
 if ( x.count < 1 ) return x;
 if ( y.count < 1 ) return y;
 
 // .. otherwise continue normal operations.
 while( p = (DAterm*) gy() ) {
 while( q = (DAterm*) gx() ) {
 
   if( ( p->weight + q->weight ) > DA__1stEnv.DA__MaxWeight ) continue;
                                   // ??? Change this: compute z->accuWgt earlier 
   r = new DAterm;                 // ??? and use it.
   *r = (*p)*(*q);
   /* DGN    if( abs(r->value) < MX_SMALL && abs(r->value) > 0.0 ) { */
   /* DGN     printf( "\nDGN> From DA& operator*( DA& x, DA& y )\n" ); */
   /* DGN     printf( "\nDGN>          p = %le\n", p->value ); */
   /* DGN     printf( "\nDGN>          q = %le\n", q->value ); */
   /* DGN     printf( "\nDGN>          r = %le\n", r->value ); */
   /* DGN    } */
   z->addTerm( r );
   }}
 
 // Determine the maximum weight computed accurately.
 if( x.accuWgt < y.accuWgt ) z->accuWgt = x.accuWgt;
 else                        z->accuWgt = y.accuWgt;
 
 DA__garbage.store(z); 
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& operator*( DA& x, double y ) {  
 DA* z = new DA;
 DAterm* p;
 DAterm* q;
 dlist_iterator gx( (dlist&) x );
 int i;
 
 if ( x.count < 1 ) return x;
 
 if( y == 0.0 ) {
   *z = 0.0;
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
   DA__garbage.store(z); 
   return *z;
   }
 
 while( p = (DAterm*) gx() ) {
   q = new DAterm( p );
   q->value *= y;
   /* DGN    if( abs(q->coeff()) < MX_SMALL && abs(q->coeff()) > 0.0 ) printf( "\nDGN> From DA& operator*( DA& x, double y )\n" ); */
   z->addTerm( q );
   }
 
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 
 z->accuWgt = x.accuWgt;
 
 DA__garbage.store(z); 
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& operator*( DA& x, int j ) { 
 DA* z = new DA;
 DAterm* p;
 DAterm* q;
 dlist_iterator gx( (dlist&) x );
 int i;
 double y;
 
 if ( x.count < 1 ) return x;
 
 if( ( y = (double) j ) == 0.0 ) {
   *z = 0.0;
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
   DA__garbage.store( z );
   return *z;
   }
 
 while( p = (DAterm*) gx() ) {
   q = new DAterm( p );
   q->value *= y;
   /* DGN    if( abs(q->coeff()) < MX_SMALL && abs(q->coeff()) > 0.0 ) printf( "\nDGN> From DA& operator*( DA& x, int j )\n" ); */
   z->addTerm( q );
   }
 
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 
 z->accuWgt = x.accuWgt;
 DA__garbage.store( z );
 return *z;
}


// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& operator*( double y, DA& x ) {  
 DA* z = new DA;
 DAterm* p;
 DAterm* q;
 dlist_iterator gx( (dlist&) x );
 int i;
 
 if ( x.count < 1 ) return x;
 
 if( y == 0.0 ) {
   *z = 0.0;
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
   DA__garbage.store(z); 
   return *z;
   }
 
 while( p = (DAterm*) gx() ) {
   q = new DAterm( p );
   q->value *= y;
   /* DGN    if( abs(q->coeff()) < MX_SMALL && abs(q->coeff()) > 0.0 ) { */
   /* DGN     printf( "\nDGN> From DA& operator*( double y, DA& x ) \n" ); */
   /* DGN     printf( "\nDGN>                   y = %le             \n", y ); */
   /* DGN     printf( "\nDGN>                   p = %le             \n", p->value ); */
   /* DGN     printf( "\nDGN>                   q = %le             \n", q->value ); */
   /* DGN    } */
   z->addTerm( q );
   }
 
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 
 z->accuWgt = x.accuWgt;
 
 DA__garbage.store(z); 
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& operator*( int j, DA& x ) { 
 DA* z = new DA;
 DAterm* p;
 DAterm* q;
 dlist_iterator gx( (dlist&) x );
 int i;
 double y;
 
 if ( x.count < 1 ) return x;
 
 if( ( y = (double) j ) == 0.0 ) {
   *z = 0.0;
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
   DA__garbage.store( z );
   return *z;
   }
 
 while( p = (DAterm*) gx() ) {
   q = new DAterm( p );
   q->value *= y;
   /* DGN    if( abs(q->coeff()) < MX_SMALL && abs(q->coeff()) > 0.0 ) printf( "\nDGN> From DA& operator*( int j, DA& x )\n" ); */
   z->addTerm( q );
   }
 
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 
 z->accuWgt = x.accuWgt;
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& operator|( DA& u, DA& v ) { 
 /*
 Truncated multiplication: used only by the division operator.
 No checks are made on the reference point.
 */
 DA* z = new DA;
 DAterm* p;
 DAterm* q;
 DAterm* r;
 dlist_looper gu( (dlist&) u );
 dlist_looper gv( (dlist&) v );
 
 // If one of the arguments is void, return it ..
 if ( u.count < 1 ) return u;
 if ( v.count < 1 ) return v;
 
 // .. otherwise continue normal operations.
 while( p = (DAterm*) gv() ) {
 while( q = (DAterm*) gu() ) {
 
   if( ( p->weight + q->weight ) > DA__1stEnv.DA__weightLimit ) continue;
 
   r = new DAterm;
   *r = (*p)*(*q);
   /* DGN    if( abs(r->value) < MX_SMALL && abs(r->value) > 0.0 )printf( "\nDGN> From DA& operator|( DA& u, DA& v ) \n" ); */
   z->addTerm( r );
 
   }}
 
 // Determine the maximum weight computed accurately.
 if( u.accuWgt < v.accuWgt ) z->accuWgt = u.accuWgt;
 else                        z->accuWgt = v.accuWgt;
 
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& operator/( DA& x, double& y ) { 
 DA* z = new DA;
 DAterm* p;
 DAterm* q;
 dlist_iterator gx( (dlist&) x );
 int i;
 
 // Check for void operators ..
 if ( x.count < 1 ) return x;
 
 // Check for division by zero ..
 if( y == 0.0 ) {
   printf("\n*** DA ERROR *** ");
   printf("Attempt to divide by a scalar zero.\n");
   exit(0);
   }
 
 // .. and continue.
 while( p = (DAterm*) gx() ) {
   q = new DAterm( p );
   q->value /= y;
   /* DGN    if( abs(q->coeff()) < MX_SMALL && abs(q->coeff()) > 0.0 ) printf( "\nDGN> From DA& operator/( DA& x, double& y ) \n" ); */
   z->addTerm( q );
   }
 
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 
 z->accuWgt = x.accuWgt;
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& operator/( DA& x, int& j ) { 
 DA* z = new DA;
 DAterm* p;
 DAterm* q;
 dlist_iterator gx( (dlist&) x );
 int i;
 double y;
 
 // Check for void operators ..
 if ( x.count < 1 ) return x;
 
 // Check for division by zero ..
 if( ( y = (double) j ) == 0.0 ) {
   printf("\n*** DA ERROR *** ");
   printf("Attempt to divide by a scalar zero.\n");
   exit(0);
   }
 
 // .. and continue.
 while( p = (DAterm*) gx() ) {
   q = new DAterm( p );
   q->value /= y;
   /* DGN    if( abs(q->coeff()) < MX_SMALL && abs(q->coeff()) > 0.0 ) printf( "\nDGN> From DA& operator/( DA& x, int& j ) \n" ); */
   z->addTerm( q );
   }
 
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 
 z->accuWgt = x.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& operator/( DA& wArg, DA& uArg ) { 
 dlist_looper gu( (dlist&) uArg );
 dlist_looper gw( (dlist&) wArg );
 DA* vptr;
 DA* v = new DA;
 DA vn;
 DA w, u;
 DAterm* qu;
 DAterm* qw;
 double u0, w0;
 int wgt;
 int i;
 
 // Check for void operators ..
 if ( wArg.count < 1 ) return wArg;
 if ( uArg.count < 1 ) {
   printf("\n*** DA ERROR *** ");
   printf("Attempt to divide by a void DA variable.\n");
   exit(0);
   }
 
 // Check for consistency and set reference point of the quotient.
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   if( wArg.refPoint[i] != uArg.refPoint[i] ) {
     printf( "\n*** DA DIVISION ERROR: Inconsistent reference points.\n" );
     exit(0);
     }
   v->refPoint[i] = wArg.refPoint[i];
   }
 
 // Normalize the denominator
 if( ( qu = (DAterm*) gu() ) == 0 ) {
   printf( "\n*** DA ERROR ***  Division algorithm called with uninitialized DA.\n" );
   exit(0);
   }
 if( ( wgt = qu->weight ) != 0 ) {
   printf( "\n*** DA ERROR ***  Attempt to divide by nilpotent element.\n" );
   exit(0);
   }
 if( ( u0 = qu->value ) == 0.0 ) {
   printf( "\n*** DA ERROR ***  Attempt to divide by zero.\n" );
   exit(0);
   }
 u = uArg / u0;
 
 // Recursive algorithm
 qw = (DAterm*) gw();
 w0 = ( qw->value );
 // --- Old code ------
 // *v = (DA) w0;
 // --- New code ------    This is done to control growth
 vptr = new DA( w0 );   // It seems and probably is horribly
 *v = *vptr;            // inefficient.
 delete vptr;
 // -------------------
 
 DA__1stEnv.DA__weightLimit = 0;
 while ( DA__1stEnv.DA__weightLimit < DA__1stEnv.DA__MaxWeight ) {
   DA__1stEnv.DA__weightLimit++;
   vn = u|*v;
   vn = vn.filter( DA__1stEnv.DA__weightLimit, DA__1stEnv.DA__weightLimit );
   w = wArg.filter( DA__1stEnv.DA__weightLimit, DA__1stEnv.DA__weightLimit );
   *v = *v + ( w - vn );
   }
 
 // Correct normalization of the answer ..
 *v = *v / u0;
 
 // .. set the reference point ..
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) v->refPoint[i] = wArg.refPoint[i];
 
 // Determine the maximum weight computed accurately.
 if( wArg.accuWgt < uArg.accuWgt ) v->accuWgt = wArg.accuWgt;
 else                              v->accuWgt = uArg.accuWgt;
 
 // .. and return value.
 DA__garbage.store( v );
 return *v;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& operator^( DA& x, DA& y ) { 
 DA* z = new DA;
 int i;
 int* m = new int [ DA__1stEnv.DA__NumVar ];
 int* n = new int [ DA__1stEnv.DA__NumVar ];
 
 if( DA__1stEnv.DA__PBOK ) {
 
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
     m[i] = 0;
     n[i] = 0;
     }
 
   for( i = 0; i < DA__1stEnv.DA__dof; i++ ) {
     m[ i ] = 1;
     n[ i + DA__1stEnv.DA__dof ] = 1;
 
     *z = *z + ( ( x.D(m) * y.D(n) ) - ( x.D(n) * y.D(m) ) );
 
     m[ i ] = 0;
     n[ i + DA__1stEnv.DA__dof ] = 0;
     }
 
   delete [] m;
   delete [] n;
   DA__garbage.store( z );
   return *z;
   }
 
 printf( "\n*** ERROR ***                                \n" );
 printf(   "*** ERROR *** DA operator^( DA&, DA& )       \n" );
 printf(   "*** ERROR *** Wrong DASetup used; cannot     \n" );
 printf(   "*** ERROR *** perform bracket.               \n" );
 printf(   "*** ERROR ***                                \n" );
 
 if( 2 + 3 == 5 ) exit(1);       // Done to avoid compiler warnings
 delete [] m;                    // about leaving the function.
 delete [] n;
 return x;                       
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void operator+=( DA& x, DA& y ) {
 x = x + y;  // ??? Come up with a more efficient implementation SOON.
}

void operator-=( DA& x, DA& y ) {
 x = x - y;
}

void operator*=( DA& x, DA& y ) {
 x = x * y;
}

void operator/=( DA& x, DA& y ) {
 x = x / y;
}


//***************************************************************
//***************************************************************
//***************************************************************
//
//      Implementation of Class DAterm

DAterm::DAterm() {
 weight = 0;
 index = new int[ DA__1stEnv.DA__NumVar ];
 value = 0.0;
}

/*
 *   Pool functions written by Michael Allen
 *   February, 1993
 */

#ifdef POOLED
_DAterm_Shell* _DAterm_Pool::top = 0;
_DAterm_Pool::_DAterm_Pool()
{
  register int i = _DAterm_BLOCK_COUNT;
  _DAterm_Shell* p = slot;
  _DAterm_Shell* q;
  while (--i)
    {
      q = p++;
      q->next = p;
    }
  p->next = top;
  top = slot;
}
#endif POOLED


// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAterm::DAterm( int* l, double x ) {
 int i, dpt;
 
 dpt = 0;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   if( (l[i] < 0) ) {
     printf( "\n*** DA ERROR *** Bad index in DATerm.\n" );
     exit(0);
     }
   dpt += l[i];
   }
 if( dpt > DA__1stEnv.DA__MaxWeight ) {
   printf("\n*** DA ERROR *** Attempt to load a DATerm with too large a weight.\n");
   exit(0);
   }
 
 index = new int[ DA__1stEnv.DA__NumVar ];
 
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) index[i] = l[i];
 weight = dpt;
 value = x;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAterm::DAterm( DAterm* x ) {
 int i;
 
 weight = x->weight;
 value = x->value;
 index = new int[ DA__1stEnv.DA__NumVar ];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) index[i] = (x->index)[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAterm::DAterm( DAterm& x ) {
 int i;
 
 weight = x.weight;
 value = x.value;
 index = new int[ DA__1stEnv.DA__NumVar ];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) index[i] = (x.index)[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAterm::DAterm( DAtermData& x ) {
 int i;
 
 weight = x.weight;
 value = x.value;
 index = new int[ DA__1stEnv.DA__NumVar ];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) index[i] = (x.index)[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAterm::~DAterm() {
 delete [] index;
}



//***************************************************************
//***************************************************************
//***************************************************************
//
//      Implementation of struct DAtermData

DAtermData::DAtermData() {
 printf( "\n" );
 printf( "*** ERROR ***                                   \n" );
 printf( "*** ERROR *** DAtermData::DAtermData()          \n" );
 printf( "*** ERROR *** Cannot declare a DAtermData       \n" );
 printf( "*** ERROR *** in this way.                      \n" );
 printf( "*** ERROR ***                                   \n" );
 exit(0);
}

DAtermData::DAtermData( DAterm& x ) {
 numvar = DA__1stEnv.DA__NumVar;   // ??? This has got to be changed!!
 index = new int[ numvar ];
 for( int i = 0; i < numvar; i++ ) index[i] = x.index[i];
 weight = x.weight;
 value = x.value;
}

DAtermData::~DAtermData() {
 if( index != 0 ) delete [] index;
}



//***************************************************************
//***************************************************************
//***************************************************************
//
//      Overloaded operators for class DAterm

void DAterm::operator=( DAterm& x ) {
 int i;
 weight = x.weight;
 value = x.value;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) index[i] = (x.index)[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator==( DAterm& a, DAterm& b ) {
 int i;
 if( ( a.weight != b.weight) || ( a.value != b.value)  ) return 0;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
   if( ( a.index[i] != b.index[i]) ) return 0;
 return 1;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator!=( DAterm& a, DAterm& b ) {
 return !( a == b );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator<=( DAterm& a, DAterm& b ) {
 int i;
 if( a.weight != b.weight ) return ( a.weight < b.weight );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   if( a.index[i] == b.index[i] ) continue;
   return ( a.index[i] < b.index[i] );
   }
 return 1;  // when all indices are the same.
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator%=( DAterm& a, DAterm& b ) {
 int i;
 if( a.weight != b.weight ) return 0;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
   if( ( a.index[i] != b.index[i]) ) return 0;
 return 1;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAterm& operator*( DAterm& x, DAterm& y ) {  
 DAterm* z = new DAterm;
 int i;
 z->weight = x.weight + y.weight;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->index[i] = x.index[i] + y.index[i];
 z->value = x.value * y.value;
 DA__garbage.store( z );
 return *z;
}


//***************************************************************
//***************************************************************
//***************************************************************
//
//      Overloaded analytic functions

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& acos( DA& x ) { 
 DA* z = new DA;
 printf( "DA& acos( DA& x ) to be written.\n" );
 exit(0);
 DA__garbage.store( z );
 return *z;
}
 
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& asin( DA& x ) { 
 DA* z = new DA;
 DA dz;
 *z = x;
 dz = ( sin(*z) - x ) / cos(*z);
 int iter = 0;
 while( ( dz != 0.0 ) && ( iter++ < MX_MAXITER ) ) {
  *z -= dz;
  dz = ( sin(*z) - x ) / cos(*z);
 }
 if( iter >= MX_MAXITER ) {
  printf( "*** WARNING ***                             \n" );
  printf( "*** WARNING *** DA& asin( DA& x ) {         \n" );
  printf( "*** WARNING *** Over %d iterations used;    \n", MX_MAXITER );
  printf( "*** WARNING *** result may be incorrect.    \n" );
  printf( "*** WARNING ***                             \n" );
 }
 DA__garbage.store( z );
 return *z;
}
 
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& atan( DA& x ) { 
 DA* z = new DA;
 DA c, dz;
 *z = x;
 c = cos( *z );
 dz = c*( sin(*z) - x*c );
 int iter = 0;
 while( ( dz != 0.0 ) && ( iter++ < MX_MAXITER ) ) {
  *z -= dz;
  c = cos( *z );
  dz = c*( sin(*z) - x*c );
 }
 if( iter >= MX_MAXITER ) {
  printf( "*** WARNING ***                             \n" );
  printf( "*** WARNING *** DA& atan( DA& x ) {         \n" );
  printf( "*** WARNING *** Over %d iterations used;    \n", MX_MAXITER );
  printf( "*** WARNING *** result may be incorrect.    \n" );
  printf( "*** WARNING ***                             \n" );
 }
 DA__garbage.store( z );
 return *z;
}
 
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& cos( DA& x ) { 
 
 DA& epsSin( DA& );
 DA& epsCos( DA& );
 DA epsilon;
 double cs, sn;
 dlist_iterator getNext( (dlist&) x );
 DAterm* p;
 
 if( x.count == 0 ) {
   printf("\n*** WARNING ***  exp called with unevaluated DA.\n");
   return x;
   }
 
 p = (DAterm*) getNext();
 if( ( p -> weight ) == 0 ) {         // x has non-zero standard part
   cs = cos( p -> value );
   sn = sin( p -> value );
   epsilon = x;                       // x must not be altered by the routine
   p = epsilon.get();                 // pops the standard part off epsilon
   return cs*epsCos( epsilon ) - sn*epsSin( epsilon );
   }
 else {                               // x is pure infinitesimal
   return epsCos( x );
   }
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& cosh( DA& x ) { 
 DA* z = new DA;
 *z = exp(x);
 *z = ( *z + ( 1.0 / *z ) ) / 2.0;
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& exp( DA& x ) { 
 
 DA& epsExp( DA& );
 DA epsilon;
 double factor;
 dlist_iterator getNext( (dlist&) x );
 DAterm* p;
 
 if( x.count == 0 ) {
   printf("\n*** WARNING ***  exp called with unevaluated DA.\n");
   return x;
   }
 
 p = (DAterm*) getNext();
 if( ( p -> weight ) == 0 ) {         // x has non-zero standard part
   factor = exp( p -> value );
   epsilon = x;                       // x must not be altered by the routine
   p = epsilon.get();                 // pops the standard part off epsilon
   return factor*epsExp( epsilon );
   }
 else {                               // x is pure infinitesimal
   return epsExp( x );
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& log ( DA& x ) { 
 DA*             dummy;
 DA*             epsilon = new DA;
 DA              u, w;
 double          std, n;
 DAterm*         p;
 dlist_iterator  getNext( (dlist&) x );
 
 
 if( x.count == 0 ) {
   printf("\n*** WARNING ***  log called with unevaluated DA.\n");
   return x;
   }
 
 p = (DAterm*) getNext();
 if( ( ( p -> weight      ) ==  0   ) &&
     ( ( std = p -> value ) !=  0.0 )
   )                                  // x has non-zero standard part
   {
   *epsilon = x;                      // x must not be altered by the routine
   p = epsilon->get();                //   pops the standard part off epsilon
   epsilon->scaleBy( - 1.0/std );
   w = *epsilon;
   u = *epsilon;                     // We use here the formulae
   n = 1.0;                          // ln( s + e )   = ln s + ln( 1 + e/s ), and
   while( u.count > 0 ) {            // ln( 1 + e/s ) = ln( 1 - ( -e/s )) 
     u = u*(*epsilon);               //               = - sum ( - e/s )^n / n
     w = w + ( u / ++n );
     }
 
 // --- Old code ------
 //  return ( (DA) ( log( std ) ) ) - w;
 // --- New code ------            This is done to control memory growth
   dummy = new DA( log(std) );  // by avoiding a constructor.
   *epsilon = *dummy - w;       // WARNING: This is a dummy use of epsilon.
   delete dummy;
   DA__garbage.store( epsilon );
   return *epsilon;
 // -------------------
 
   }
 else                                 // x has zero standard part
   {
   printf( "\n\n*** ERROR *** \n"                                  );
   printf(     "*** ERROR *** DA log called with argument whose\n" );
   printf(     "*** ERROR *** standard part vanishes.\n"           );
   printf(     "*** ERROR *** \n\n"                                );
   if( 1 + 1 == 2 ) exit(1);
   return x;
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& log10( DA& x ) {
 static const double logE = 0.4342944819032518276511289;
 return  logE*log(x);
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& pow( DA& x, double s ) { 
 DA& epsPow( DA&, double );
 DA* epsilon = new DA;
 double factor;
 double std;
 dlist_iterator getNext( (dlist&) x );
 DAterm* p;
 int u;
 
 if( x.count == 0 ) {
   printf("\n*** WARNING ***  pow called with unevaluated DA.\n");
   delete epsilon;
   return x;
   }
 
 p = (DAterm*) getNext();
 if( ( ( p -> weight      ) ==  0   ) &&
     ( ( std = p -> value ) !=  0.0 )
   )                                  // x has non-zero standard part
   {
   factor = pow( std, s );
   *epsilon = x;                      // x must not be altered by the routine
   p = epsilon->get();                //   pops the standard part off epsilon
   epsilon->scaleBy( 1.0/std );
   *epsilon = factor*epsPow( *epsilon, s );
   DA__garbage.store( epsilon );
   return *epsilon;
   }
 else                                 // x is pure infinitesimal
   {
   u = nearestInteger( s );
   if( s != (double) u ) {
     printf( "\n*** ERROR::DA pow: attempt to use infinitesimal " );
     printf( "as base with non-integer exponent.\n" );
     exit(1);
     }
   *epsilon = 1.0;
   if ( u == 0 ) {
     DA__garbage.store( epsilon );
     return *epsilon;
   }
   if ( u > 0 ) {
     while( u-- > 0 ) *epsilon = (*epsilon)*x;
     DA__garbage.store( epsilon );
     return *epsilon;
     }
   else {
     while( u++ < 0 ) *epsilon = (*epsilon)*x;
     *epsilon = 1.0 / *epsilon;
     DA__garbage.store( epsilon );
     return *epsilon;
     }
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& sin( DA& x ) { 
 
 DA& epsSin( DA& );
 DA& epsCos( DA& );
 DA epsilon;
 double cs, sn;
 dlist_iterator getNext( (dlist&) x );
 DAterm* p;
 
 if( x.count == 0 ) {
   printf("\n*** WARNING ***  exp called with unevaluated DA.\n");
   return x;
   }
 
 p = (DAterm*) getNext();
 if( ( p -> weight ) == 0 ) {         // x has non-zero standard part
   cs = cos( p -> value );
   sn = sin( p -> value );
   epsilon = x;                       // x must not be altered by the routine
   p = epsilon.get();                 // pops the standard part off epsilon
   return sn*epsCos( epsilon ) + cs*epsSin( epsilon );
   }
 else {                               // x is pure infinitesimal
   return epsSin( x );
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& sinh( DA& x ) {
 DA z;
 z = exp(x);
 return ( z - (1.0/z))/2.0;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& sqrt( DA& x ) {
 DA& epsSqrt( DA& );
 DA epsilon;
 double factor;
 double std;
 dlist_iterator getNext( (dlist&) x );
 DAterm* p;
 
 if( x.count == 0 ) {
   printf("\n*** WARNING ***  pow called with unevaluated DA.\n");
   return x;
   }
 
 p = (DAterm*) getNext();
 if( ( ( p -> weight      ) ==  0   ) &&
     ( ( std = p -> value ) !=  0.0 )
   )                                  // x has non-zero standard part
   {
   factor = sqrt( std );
   epsilon = x;                       // x must not be altered by the routine
   p = epsilon.get();                 //   pops the standard part off epsilon
   epsilon.scaleBy( 1.0/std );
   return factor*epsSqrt( epsilon );
   }
 else                                 // x is pure infinitesimal
   {
   printf( "\n*** ERROR::DA sqrt: attempt to use infinitesimal argument." );
   if( 1 + 1 == 2 ) exit(1);
   return x;
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& tan( DA& x ) { 
 return sin(x) / cos(x) ;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& tanh( DA& x ) { 
 return sinh(x) / cosh(x);
}
 

//***************************************************************
//***************************************************************
//***************************************************************
//
//      Auxiliary functions which operate on infinitesimals.
//      It is assumed that the calling program checks to be sure
//      that the argument has zero standard part.
 
DA& epsCos( DA& epsilon ) { 
 
 DA* dummy;
 DA* z = new DA;
 DA epsq, term;
 double n;
 int i;
 
 epsq = - epsilon*epsilon;
 
 // --- Old code ------
 // *z = (DA) 1.0;
 // --- New code ------            This is done to control memory growth
 dummy = new DA( 1.0 );
 *z = *dummy;
 delete dummy;
 // -------------------
 
 term = epsq / 2.0;
 n = 2.0;
 
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = epsilon.refPoint[i];
 
 while( term.count > 0 ) {
   *z = *z + term;
   term = ( ( term*epsq ) / ++n ) / ++n;
   }
 
 z->accuWgt = epsilon.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& epsExp( DA& epsilon ) { 
 DA* dummy;
 DA* z = new DA;
 DA  term;
 double n;
 int i;
 
 // --- Old code ------
 // *z = (DA) 1.0;
 // --- New code ------            This is done to control memory growth
 dummy = new DA( 1.0 );
 *z = *dummy;
 delete dummy;
 // -------------------
 
 term = epsilon;
 n = 1.0;
 
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = epsilon.refPoint[i];
 
 while( term.count > 0 ) {
   *z = *z + term;
   term = ( term*epsilon ) / ++n;
   }
 
 z->accuWgt = epsilon.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& epsPow( DA& epsilon, double s ) { 
 DA* dummy;
 DA* z = new DA;
 DA  term;
 double f, n;
 int i;
 
 // --- Old code ------
 // *z = (DA) 1.0;
 // --- New code ------            This is done to control memory growth
 dummy = new DA( 1.0 );
 *z = *dummy;
 delete dummy;
 // -------------------
 
 f = s;
 n = 1.0;
 term = s*epsilon;
 
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
          z->refPoint[i] = epsilon.refPoint[i];
 
 while( term.count > 0 ) {
   *z = *z + term;
   term = ( (--f) * term * epsilon ) / ++n;
   }
 
 z->accuWgt = epsilon.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& epsSin( DA& epsilon ) { 
 
 DA* z = new DA;
 DA  epsq, term;
 double n;
 
 epsq = - epsilon*epsilon;
 *z = epsilon;
 term = ( epsilon*epsq ) / 6.0;
 n = 3.0;
 
 while( term.count > 0 ) {
   *z = *z + term;
   term = ( ( term*epsq ) / ++n ) / ++n;
   }
 
 z->accuWgt = epsilon.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& epsSqrt( DA& epsilon ) {  // This function is identical to epsPow
                              // with the substitution  s = 1/2
 DA*     dummy;
 DA*     z = new DA;
 DA      term;
 double  f, n;
 int     i;
 
 // --- Old code ------
 // *z = (DA) 1.0;
 // --- New code ------            This is done to control memory growth
 dummy = new DA( 1.0 );
 *z = *dummy;
 delete dummy;
 // -------------------
 
 f    = 1.0 / 2.0;
 n    = 1.0;
 term = f*epsilon;
 
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
          z->refPoint[i] = epsilon.refPoint[i];
 
 while( term.count > 0 ) {
   *z = *z + term;
   term = ( (--f) * term * epsilon ) / ++n;
   }
 
 z->accuWgt = epsilon.accuWgt;

 DA__garbage.store( z );
 return *z;
 }
 

//***************************************************************
//***************************************************************
//***************************************************************
//
//      Functions which rank and unrank monomials.  Developed from
//      algorithms provided by Nijenhuis and Wilf, Combinatorial
//      Algorithms. (2nd ed.)
 
void DA__monoCode() {
 int c;
 int i, j;
 j = 0;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   for( c = 0; c < DA__1stEnv.DA__exponent[i]; c++ ) DA__1stEnv.DA__expCode[j++] = 1;
   DA__1stEnv.DA__expCode[j++] = 0;
   }
}

//    |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DA__monoDecode() {
 int c;
 int i, j;
 j = 0;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   c = 0;
   while( DA__1stEnv.DA__expCode[j++] ) ++c;
   DA__1stEnv.DA__exponent[i] = c;
   }
}

//    |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

int DA__monoRank() {
 //  This function assumes DA__monoCode has been run,
 //  so that the path is appropriately coded into DA__1stEnv.DA__expCode.
 char edge;
 int w, n;
 int rank;
 int zeroCount;
 int i;
 
 i = 0;
 rank = 0;
 w = 0;
 n = 1;
 
 if( edge = DA__1stEnv.DA__expCode[i++] ) zeroCount = 0;
 else                          zeroCount = 1;
 
 while( zeroCount < DA__1stEnv.DA__NumVar ) {
 
   if( edge ) {
     w++;
     if( ( w > 0 ) && ( n > 1 ) )  rank += DA__1stEnv.DA__numPaths[w][n-1];
     }
   else  n++;
 
   if( !( edge = DA__1stEnv.DA__expCode[i++] ) ) zeroCount++;
 
   }
 
 rank += ( w * DA__1stEnv.DA__numPaths[w][n] ) / n;
 
 return rank;
}


//***************************************************************
//***************************************************************
//***************************************************************
//
//    Implementation of class LieOperator
//

//    Constructors and destructors    |||||||||||||||||||||||||||

LieOperator::LieOperator() {
 int i;
 
 if( DA__1stEnv.DA__SpaceDim == 0 ) {
   printf( "\n*** ERROR: LieOperator::LieOperator called " );
   printf( "after DASetup declared no vectors.\n" );
   exit(0);
   }
 
 weight = -1;
 accuWgt = DA__1stEnv.DA__MaxWeight;
 
 if( DA__1stEnv.DA__allSet == 137 ) {
   v = new DA[ DA__1stEnv.DA__NumVar ];
   refPoint = new double[ DA__1stEnv.DA__NumVar ];
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = DA__1stEnv.DA__refPoint[i];
   }
 else {
   v = 0;
   refPoint = 0;
   DA__1stEnv.DA__predefLieOp.insert( this );
   }
}

//    |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator::LieOperator( LieOperator& x ) {
 int i;
 
 if( DA__1stEnv.DA__allSet != 137 ) {
   printf( "\n*** LieOperator::LieOperator( LieOperator& ) ERROR *** " );
   printf( "Prior call to DASetup required.\n" );
   exit(0);
   }
 
 v = new DA[ DA__1stEnv.DA__NumVar ];
 for ( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) v[i] = x.v[i];
 weight = x.weight;
 accuWgt = x.accuWgt;
 
 refPoint = new double[ DA__1stEnv.DA__NumVar ];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = x.refPoint[i];
}

//    |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator::LieOperator( DA* x ) {    // A dangerous routine.
 int i, j;                             // It assumes the correct number
                                       // of components in the argument.

 static char firstCall = 1;

 if( firstCall ) {
  firstCall = 0;
  printf( "\n" );
  printf( "*** WARNING ***					\n" );
  printf( "*** WARNING *** LieOperator::LieOperator( DA* x )	\n" );
  printf( "*** WARNING *** A dangerous routine.			\n" );
  printf( "*** WARNING *** It assumes the correct number	\n" );
  printf( "*** WARNING *** of components in the argument.	\n" );
  printf( "*** WARNING *** I highly recommend against its use!	\n" );
  printf( "*** WARNING ***					\n" );
 }

 if( DA__1stEnv.DA__SpaceDim == 0 ) {
  printf( "\n*** ERROR: LieOperator::LieOperator called " );
  printf( "after DASetup declared no vectors.\n" );
  exit(0);
 }
 
 if( DA__1stEnv.DA__allSet != 137 ) {
  printf( "\n*** LieOperator::LieOperator( LieOperator& ) ERROR *** " );
  printf( "Prior call to DASetup required.\n" );
  exit(0);
 }
 
 weight = -1;
 accuWgt = DA__1stEnv.DA__MaxWeight;

 refPoint = new double[ DA__1stEnv.DA__NumVar ];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = x[0].refPoint[i];

 v = new DA[ DA__1stEnv.DA__NumVar ];
 for ( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) setVariable( x[i], i );
}

//    |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator::LieOperator( char* flag ) { 
 int i;
 int nv;
 
 if( DA__1stEnv.DA__SpaceDim == 0 ) {
   printf( "\n*** ERROR: LieOperator::LieOperator called " );
   printf( "after DASetup declared no vectors.\n" );
   exit(0);
   }
 
 if( DA__1stEnv.DA__allSet != 137 ) {
   printf( "\n*** LieOperator::LieOperator( char* ) ERROR *** " );
   printf( "Prior call to DASetup required.\n" );
   exit(0);
   }
 
 nv = DA__1stEnv.DA__NumVar;
 v = new DA[ nv ];

 refPoint = new double[ nv ];
 for( i = 0; i < nv; i++ ) {
  refPoint[i] = DA__1stEnv.DA__refPoint[i];
  v[i].setVariable( i );
 }

 weight = 1;
 accuWgt = DA__1stEnv.DA__MaxWeight;
}

//    |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

// ??? REMOVE  LieOperator::LieOperator( int size ) {
// ??? REMOVE  int i;
// ??? REMOVE  
// ??? REMOVE  if( DA__1stEnv.DA__allSet != 137 ) {
// ??? REMOVE    printf( "\n*** LieOperator::LieOperator( int ) ERROR *** " );
// ??? REMOVE    printf( "Prior call to DASetup required.\n" );
// ??? REMOVE    exit(0);
// ??? REMOVE    }
// ??? REMOVE  
// ??? REMOVE  if( size <= 0 ) {
// ??? REMOVE    printf( "\n*** ERROR: LieOperator::LieOperator called with size = %d.\n", size );
// ??? REMOVE    exit(0);
// ??? REMOVE    }
// ??? REMOVE  
// ??? REMOVE  if( DA__1stEnv.DA__SpaceDim == 0 ) {
// ??? REMOVE    printf( "\n*** ERROR: LieOperator::LieOperator called " );
// ??? REMOVE    printf( "after DASetup declared no vectors.\n" );
// ??? REMOVE    exit(0);
// ??? REMOVE    }
// ??? REMOVE  
// ??? REMOVE  if ( DA__1stEnv.DA__SpaceDim == -1 ) {
// ??? REMOVE    printf( "\n*** ERROR: LieOperator::LieOperator called " );
// ??? REMOVE    printf( "with DA__1stEnv.DA__SpaceDim == -1.\n" );
// ??? REMOVE    exit(0);         // In fact, this should never happen.
// ??? REMOVE    // DA__1stEnv.DA__SpaceDim = size;
// ??? REMOVE    // v = new DA[ DA__1stEnv.DA__NumVar ];
// ??? REMOVE    // weight = -1;
// ??? REMOVE    }
// ??? REMOVE  
// ??? REMOVE  else {
// ??? REMOVE    if( size != DA__1stEnv.DA__SpaceDim ) {
// ??? REMOVE      printf( "\n*** ERROR: LieOperator::LieOperator discrepancy in vector size.\n" );
// ??? REMOVE      exit(0);
// ??? REMOVE      }
// ??? REMOVE    else {
// ??? REMOVE      v = new DA[ DA__1stEnv.DA__NumVar ];
// ??? REMOVE      weight = -1;
// ??? REMOVE      }
// ??? REMOVE    }
// ??? REMOVE  
// ??? REMOVE  refPoint = new double[ DA__1stEnv.DA__NumVar ];
// ??? REMOVE  for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = DA__1stEnv.DA__refPoint[i];
// ??? REMOVE  }
// ??? REMOVE  
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator::~LieOperator() {
 if( v ) { delete [] v;
           delete [] refPoint; }
}

void LieOperator::reset() {
 int i, j;
 weight = -1;
 accuWgt = DA__1stEnv.DA__MaxWeight;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
  if( weight < v[i].weight ) weight = v[i].weight;
  if( accuWgt > v[i].accuWgt ) accuWgt = v[i].accuWgt;
  refPoint[i] = v[0].refPoint[i];
 }
 i = 1;
 while( i < DA__1stEnv.DA__NumVar ) {
  for( j = 0; j < DA__1stEnv.DA__NumVar; j++ ) 
   if( refPoint[j] != v[i].refPoint[j] ) {
    printf( "\n" );
    printf( "*** ERROR ***                                      \n" );
    printf( "*** ERROR *** void LieOperator::reset()            \n" );
    printf( "*** ERROR *** refPoint error for i = %d            \n", i );
    printf( "*** ERROR ***                                      \n" );
    exit(0);
   }
  i++;
 }
}


//     Member functions(public)  |||||||||||||||||||||||||||||||

void LieOperator::fixReference( double* r ) {
 int i;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = r[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void LieOperator::fixReference() {
 int i;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = DA__1stEnv.DA__refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void LieOperator::fixReference( DA& x ) {
 int i;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = x.refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void LieOperator::fixReferenceAtEnd( LieOperator& x ) {
 int i;
 double* u = new double [ DA__1stEnv.DA__NumVar ];
 x.standardPart( u );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = u[i];
 delete [] u;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void LieOperator::fixReferenceAtStart( LieOperator& x ) {
 int i;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) refPoint[i] = x.refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void LieOperator::setVariable( DA& x, int j ) {
 int i;
 
 // REMOVE ??? dlist_iterator getNext( (dlist&) x );
 // REMOVE ??? DAterm* p = (DAterm*) getNext();
 // REMOVE ??? if( ( p->weight  < 1 ) && ( p->value != 0.0 ) ) {
 // REMOVE ???  printf( "\n" );
 // REMOVE ???  printf( "*** ERROR *** LieOperator::setVariable( DA&, int )          \n" );
 // REMOVE ???  printf( "*** ERROR *** The LieOperator vector fields must be         \n" );
 // REMOVE ???  printf( "*** ERROR *** at least linear in the coordinates.           \n" );
 // REMOVE ???  printf( "*** ERROR ***                                               \n" );
 // REMOVE ???  printf( "\n" );
 // REMOVE ???  exit(0);
 // REMOVE ??? }
 // REMOVE ??? 
 if( j < 0 || DA__1stEnv.DA__NumVar <= j ) {
  printf( "\n***ERROR ***                                              \n" );
  printf(   "***ERROR *** LieOperator::setVariable( DA&, int )         \n" );
  printf(   "***ERROR *** It is certainly not true                     \n" );
  printf(   "***ERROR *** that 0 <= %d < %d                            \n",
            j, DA__1stEnv.DA__NumVar );
  printf(   "***ERROR ***                                              \n" );
  printf(   "***ERROR *** Sorry.  Good bye.                            \n" );
  printf(   "***ERROR ***                                              \n" );
  exit(0);
 }
 
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) if( refPoint[i] != x.refPoint[i] ) {
  printf( "\n*** LieOperator::setVariable ERROR: Incompatible references.\n" );
  exit(0);
 }
 
 v[j] = x;
 if ( weight  < x.weight  ) weight  = x.weight;
 if ( accuWgt > x.accuWgt ) accuWgt = x.accuWgt;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void LieOperator::setVariable( double x, int j ) {
 int* ndx;
 int i;
 
 if( j < 0 || DA__1stEnv.DA__NumVar <= j ) {
  printf( "\n***ERROR ***                                              \n" );
  printf(   "***ERROR *** LieOperator::setVariable( double, int )         \n" );
  printf(   "***ERROR *** It is certainly not true                     \n" );
  printf(   "***ERROR *** that 0 <= %d < %d                            \n",
            j, DA__1stEnv.DA__NumVar );
  printf(   "***ERROR ***                                              \n" );
  printf(   "***ERROR *** Sorry.  Good bye.                            \n" );
  printf(   "***ERROR ***                                              \n" );
  exit(0);
 }
 
 v[j].clear();
 // if( ( j < 0 ) || ( j >= DA__1stEnv.DA__NumVar ) ) return;  ??? Old form.
 
 refPoint[j] = x;
 DA__1stEnv.DA__refPoint[j] = x;
 
 ndx = new int[ DA__1stEnv.DA__NumVar ];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) ndx[i] = 0;
 ndx[j] = 1;
 v[j].insert( new DAterm( ndx, 1.0 ) );
 
 ndx = new int[ DA__1stEnv.DA__NumVar ];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) ndx[i] = 0;
 v[j].insert( new DAterm( ndx, x ) );
                            // ??? How about delete ndx ???
 if ( weight < 1 ) weight = 1;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void LieOperator::getReference( double* r ) {
 int i;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) r[i] = refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char LieOperator::isNilpotent() {
 for( int i = 0; i <  DA__1stEnv.DA__SpaceDim; i++ ) 
  if( !(v[i].isNilpotent()) ) return 0;
 return 1;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void LieOperator::peekAt() {
 int i;
 printf( "\n******************\nLieOperator::peekAt ********\n" );
 printf( "Weight: %d   Address: %d\n", weight, this );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   printf( "\n******************\n**** Component index = %d:\n", i );
   v[i].peekAt();
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

dlist* LieOperator::image() {
 dlist* ret = new dlist[ DA__1stEnv.DA__NumVar ];  // ??? Change this!!!
 for( int i = 0; i < DA__1stEnv.DA__NumVar; i++ ) 
  ret[i] = v[i].image();
 return ret;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void LieOperator::printCoeffs() {
 int i;
 printf( "\n************ Begin LieOperator::printCoeffs ********\n" );
 printf( "Weight: %d \n", weight );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   printf( "\n******************\n**** Component index = %d:\n", i );
   v[i].printCoeffs();
   }
 printf( "\n************ End   LieOperator::printCoeffs ********\n" );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void LieOperator::peekAt( char* fileName ) {
 int i;
 DA__scratchFile = fopen( fileName, "w" );
 fprintf( DA__scratchFile,
          "\n******************\nLieOperator::peekAt ********\n" );
 fprintf( DA__scratchFile, "Weight: %d   Address: %d\n", weight, this );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   fprintf( DA__scratchFile,
            "\n******************\n**** Component index = %d:\n", i );
   v[i].peekAt( 1 );
   }
 fclose( DA__scratchFile );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void LieOperator::printCoeffs( char* fileName ) {
 int i;
 DA__scratchFile = fopen( fileName, "w" );
 fprintf( DA__scratchFile,
          "\n************ Begin LieOperator::printCoeffs ********\n" );
 fprintf( DA__scratchFile, "Weight: %d \n", weight );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   fprintf( DA__scratchFile, "\n******************\n**** Component index = %d:\n", i );
   v[i].printCoeffs( 1 );
   }
 fprintf( DA__scratchFile, 
          "\n************ End   LieOperator::printCoeffs ********\n" );
 fclose( DA__scratchFile );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void LieOperator::standardPart( double* x ) {
 int i;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )  x[i] = v[i].standardPart();
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void LieOperator::weightedDerivative( int* m, double* x ) {
 int i;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) x[i] = v[i].weightedDerivative( m );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void LieOperator::derivative( int* m, double* x ) {
 int i;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) x[i] = v[i].derivative( m );
}


// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& LieOperator::filter( MX_R_FUNCPTR f [] ) {
 LieOperator* z = new LieOperator;     // ??? Could this be simplified by using
 int i;                                // ??? LieOperator* z = new LieOperator( *this );

 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
  z->v[i] = v[i].filter( f[i] );

 z->reset();

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& LieOperator::filter( int lower, int upper ) {
 LieOperator* z = new LieOperator;     // ??? Could this be simplified by using
 int i;                                // ??? LieOperator* z = new LieOperator( *this );

 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
  z->v[i] = v[i].filter( lower, upper );

 z->reset();

 DA__garbage.store( z );
 return *z;
}


//     Operators   |||||||||||||||||||||||||||||||||||||||||||||

ostream& operator<<(ostream& os,  LieOperator& x) {
 int i;
 os << "\n************ Begin LieOperator  printCoeffs ********\n";
 os << "Weight: " << x.weight << endl;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   os << "\n******************\n**** Component index = " << i << endl;
   os << x.v[i];
   }
 return  os << "\n************ End   LieOperator  printCoeffs ********\n";
}

char operator==( LieOperator& x, LieOperator& y ) {
 int i;
 if( x.weight  != y.weight  ) return 0;
 if( x.accuWgt != y.accuWgt ) return 0;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) if( x.refPoint[i] != y.refPoint[i] ) return 0;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) if( !( x.v[i] == y.v[i] ) ) return 0;
 return 1;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator!=( LieOperator& x, LieOperator& y ) {
 return !( x == y );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char LieOperator::operator==( double x ) {
 char answer = 1;
 for( int i = 0; i < DA__1stEnv.DA__SpaceDim; i++ ) 
  answer = answer && ( v[i] == x );
 return answer;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char LieOperator::operator!=( double x ) {
 return !( this->operator==( x ) );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

doublematrix LieOperator::Jacobian() {
 int            i, j;
 int            nsd = DA__1stEnv.DA__SpaceDim;
 int*           d = new int[ nsd ];
 doublematrix   M( nsd, nsd, 0.0 );

 for( i = 0; i < nsd; i++  ) d[i] = 0;
 for( j = 0; j < nsd; j++ ) {
  d[j] = 1;
  for( i = 0; i < nsd; i++ ) M( i, j ) = v[i].derivative( d );
  d[j] = 0;
 }

 return M;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& LieOperator::inverse() {          // ??? Fundamental limitation:
 LieOperator* z    = new LieOperator;          // ??? This only works on differentials!
 LieOperator  id( "ident" );                   // ??? Enlarge scope!!!
 LieOperator  v;
 int          nsd  = DA__1stEnv.DA__SpaceDim;
 int          i = 0;
 doublematrix M( nsd, nsd, 0.0 );

 M = ( this->Jacobian() ).inverse();

 *z = M*id;
 v = ( operator()(*z) - id );
 while ( ( i++ < MX_MAXITER ) && ( v != 0.0 ) ) {
  *z = *z - M*v;
  v = ( operator()(*z) - id );
 }

 if( i >= MX_MAXITER ) {
  printf( "*** WARNING ***                                        \n" );
  printf( "*** WARNING *** LieOperator& LieOperator::inverse()    \n" );
  printf( "*** WARNING *** Over %d iterations used;               \n", MX_MAXITER );
  printf( "*** WARNING *** result may be incorrect.               \n" );
  printf( "*** WARNING ***                                        \n" );
 }

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& LieOperator::operator()( LieOperator& x ) {
 int i;
 LieOperator* z = new LieOperator;
 for( i = 0; i < DA__1stEnv.DA__SpaceDim; i++) {
  z->v[i] = v[i]( x );
 }
 while( i < DA__1stEnv.DA__NumVar ) z->v[i] = x.v[i++];
 z->reset();

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& LieOperator::operator=( LieOperator& x ) {
 int i;
 int w;
 weight = -1;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   v[i] = x.v[i];
   if ( weight < ( w = v[i].weight ) ) weight = w;
   refPoint[i] = x.refPoint[i];
   }
 accuWgt = x.accuWgt;
 return *this;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA LieOperator::operator[]( int i ) {
 return v[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& LieOperator::operator^( DA& x ) { 
 DA*  answer = new DA;
 int  s      = DA__1stEnv.DA__SpaceDim;
 int* ndx    = DA__1stEnv.DA__AllZeroes;
 int aw, i, jw;
 char adjustWeight = 1;

 aw = DA__1stEnv.DA__MaxWeight;
 ndx[0] = 1;
 *answer = v[0]*x.D( ndx );
 ndx[0] = 0;

        // Differentiation will normally lower 
        //  the maximum accurate order by one.  This is 
        //  offset if the constant term in v[] vanishes.
        //
        if( v[0].standardPart() == 0.0 ) {
         jw = v[0].accuWgt;
         if( jw > x.accuWgt ) jw = x.accuWgt;
         if( jw < aw ) aw = jw;
        }
        else adjustWeight = 0;

 if( s > 1 ) for( i = 1; i < s; i++ ) {
  ndx[i] = 1;
  *answer += v[i]*x.D( ndx );
  ndx[i] = 0;

        if( v[i].standardPart() == 0.0 ) {
         jw = v[i].accuWgt;
         if( jw > x.accuWgt ) jw = x.accuWgt;
         if( jw < aw ) aw = jw;
        }
        else adjustWeight = 0;

 }

 // The accuracy of the answer is adjusted only if
 //  all components of v[] are differentials.
 // 
 if( adjustWeight ) answer->accuWgt = aw;

 DA__garbage.store( answer );
 return *answer;
}


// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& LieOperator::expMap( double t, DA& x ) { 
 DA* answer = new DA;
 DA u;
 double f;
 int count;
 
 *answer = x;
 u     = x;
 f     = 1.0;
 count = 0;

 u = ( t/f++ )*( operator^( u ) );
 while( ( count++ < MX_MAXITER ) && ( u != 0.0 ) ) {
  *answer += u;                      // ??? How does this
  u = ( t/f++ )*( operator^( u ) );  // ??? affect efficiency?
 }

 if( count >= MX_MAXITER ) {
  printf( "\n" );
  printf( "*** WARNING ***                                         \n" );
  printf( "*** WARNING *** DA& LieOperator::expMap()               \n" );
  printf( "*** WARNING *** Number of iterations has exceeded %d    \n", MX_MAXITER );
  printf( "*** WARNING *** without achieving convergence.          \n" );
  printf( "*** WARNING *** Results may be incorrect.               \n" );
  printf( "*** WARNING ***                                         \n" );
  printf( "\n" );
 }

 DA__garbage.store( answer );
 return *answer;
}


// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& LieOperator::expMap( DA& t, DA& x ) { 
 DA* answer = new DA;
 DA u;
 double f;
 int count;
 
 *answer = x;
 u     = x;
 f     = 1.0;
 count = 0;

 u = ( t/f++ )*( operator^( u ) );
 while( ( count++ < MX_MAXITER ) && ( u != 0.0 ) ) {
  *answer += u;                      // ??? How does this
  u = ( t/f++ )*( operator^( u ) );  // ??? affect efficiency?
 }

 if( count >= MX_MAXITER ) {
  printf( "\n" );
  printf( "*** WARNING ***                                         \n" );
  printf( "*** WARNING *** DA& LieOperator::expMap()               \n" );
  printf( "*** WARNING *** Number of iterations has exceeded %d    \n", MX_MAXITER );
  printf( "*** WARNING *** without achieving convergence.          \n" );
  printf( "*** WARNING *** Results may be incorrect.               \n" );
  printf( "*** WARNING ***                                         \n" );
  printf( "\n" );
 }

 DA__garbage.store( answer );
 return *answer;
}


// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& LieOperator::expMap( double t , LieOperator& x ) {
 LieOperator* z = new LieOperator;

 for( int i = 0; i < DA__1stEnv.DA__SpaceDim; i++) 
  z->v[i] = expMap( t, x.v[i] );
 while( i < DA__1stEnv.DA__NumVar ) z->v[i] = x.v[i++];
 z->reset();

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& LieOperator::expMap( DA& t, LieOperator& x ) {
 LieOperator* z = new LieOperator;

 for( int i = 0; i < DA__1stEnv.DA__SpaceDim; i++) 
  z->v[i] = expMap( t, x.v[i] );
 while( i < DA__1stEnv.DA__NumVar ) z->v[i] = x.v[i++];
 z->reset();

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& operator+ ( LieOperator& x, LieOperator& y ) { 
 LieOperator* z = new LieOperator;
 int i;

 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   if( x.refPoint[i] != ( z->refPoint[i] = y.refPoint[i] ) ) {
     printf( "\n*** LieOperator ADDITION ERROR: Inconsistency in reference points.\n" );
     exit(0);
     }
   }
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];

 z->weight = 0;
 z->accuWgt = DA__1stEnv.DA__MaxWeight;
 for( i = 0; i < DA__1stEnv.DA__SpaceDim; i++ )  {
  z->v[i] = x.v[i] + y.v[i];
  if( z->weight  < z->v[i].weight  ) z->weight  = z->v[i].weight;
  if( z->accuWgt > z->v[i].accuWgt ) z->accuWgt = z->v[i].accuWgt;
 }
 
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& operator- ( LieOperator& x, LieOperator& y ) {
 LieOperator* z = new LieOperator;
 int i;

 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   if( x.refPoint[i] != ( z->refPoint[i] = y.refPoint[i] ) ) {
     printf( "\n*** LieOperator ADDITION ERROR: Inconsistency in reference points.\n" );
     exit(0);
     }
   }
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];

 z->weight = 0;
 z->accuWgt = DA__1stEnv.DA__MaxWeight;
 for( i = 0; i < DA__1stEnv.DA__SpaceDim; i++ )  { 
  z->v[i] = x.v[i] - y.v[i];
  if( z->weight  < z->v[i].weight  ) z->weight  = z->v[i].weight;
  if( z->accuWgt > z->v[i].accuWgt ) z->accuWgt = z->v[i].accuWgt;
 }

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& operator- ( LieOperator& x ) {
 LieOperator* z = new LieOperator;
 int i;

 for( i = 0; i < DA__1stEnv.DA__SpaceDim; i++ )  z->v[i] = - x.v[i];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 z->weight  = x.weight;
 z->accuWgt = x.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& operator* ( double& c, LieOperator& x ) {
 LieOperator* z;
 int i;

 for( i = 0; i < DA__1stEnv.DA__SpaceDim; i++ )  z->v[i] = c*x.v[i];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 z->weight  = x.weight;
 z->accuWgt = x.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& operator* ( LieOperator& x, double& c ) {
 LieOperator* z;
 int i;

 for( i = 0; i < DA__1stEnv.DA__SpaceDim; i++ )  z->v[i] = c*x.v[i];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 z->weight  = x.weight;
 z->accuWgt = x.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& operator* ( DA& c, LieOperator& x ) {
 LieOperator* z;
 int i;

 z->weight = 0;
 z->accuWgt = DA__1stEnv.DA__MaxWeight;
 for( i = 0; i < DA__1stEnv.DA__SpaceDim; i++ )  {
  z->v[i] = c*x.v[i];
  if( z->weight  < z->v[i].weight  ) z->weight  = z->v[i].weight;
  if( z->accuWgt > z->v[i].accuWgt ) z->accuWgt = z->v[i].accuWgt;
  }

 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& operator* ( LieOperator& x, DA& c ) {
 return c*x;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& operator*(  doublematrix& M, LieOperator& x ) {
 LieOperator* z = new LieOperator;
 int i, j;

 z->weight = x.weight;
 z->accuWgt = x.accuWgt;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];

 int nsd = DA__1stEnv.DA__SpaceDim;

 if( ( M.rows() != nsd ) || 
     ( M.cols() != nsd )) {
  printf( "\n" );
  printf( "*** ERROR ***                                           \n" );
  printf( "*** ERROR *** LieOperator& operator*(  doublematrix& M, LieOperator& x ) \n" );
  printf( "*** ERROR *** Rows and/or columns of the matrix         \n" );
  printf( "*** ERROR *** are not correct.                          \n" );
  printf( "*** ERROR ***                                           \n" );
  exit(0);
 }

 for( i = 0; i < nsd; i++ ) {
  z->v[i] = M( i, 0 ) * x.v[0];
  j = 1;
  while( j < nsd )   z->v[i] += M( i, j ) * x.v[j++];
 }

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

LieOperator& operator*( LieOperator& x, LieOperator& y ) { 
 LieOperator* z = new LieOperator;
 LieOperator u;
 DA term;
 int i;
 int j;
 int w;
 DAterm* p;
 
 // Check consistency of reference points.
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
   if( x.refPoint[i] != ( y.v[i] ).weightedDerivative( DA__1stEnv.DA__AllZeroes ) ) {
     printf( "\n*** LieOperator CONCATENATION ERROR: Inconsistent reference points.\n" );
     exit(0);
     }
 
 // Subtract reference point prior to concatenation.
 u = y;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) p = ( u.v[i] ).get();
 if( p->weight != 0 ) {
   printf( "\n*** LieOperator CONCATENATION ERROR: Argument has no nonstandard part!!\n" );
   exit(0);
   }
 
 // Evaluate and store monomials.
 
 // The zeroth one.
 DA__1stEnv.DA__DAmonomial[0] = 1.0;
 DA__1stEnv.DA__DAmonomial[0].fixReferenceAtStart( y );
 
 // For all higher weights ...
 for( w = 1; w <= x.weight; w++ )
 
   // Get the next set of exponents of weight w.
   while( nexcom( w, DA__1stEnv.DA__NumVar, DA__1stEnv.DA__exponent ) ) {
 
     // Find the first non-zero exponent.
     i = 0;
     while( !( DA__1stEnv.DA__exponent[i++] ) ) ;
     i--;
 
     // The value of the monomial associated with this composition
     // is obtained by multiplying a factor into a previously
     // computed monomial.
     ( DA__1stEnv.DA__exponent[i] )--;
     DA__monoCode();
     term = DA__1stEnv.DA__DAmonomial[ DA__monoRank() ];
     ( DA__1stEnv.DA__exponent[i] )++;
     DA__monoCode();
     DA__1stEnv.DA__DAmonomial[ DA__monoRank() ] = term * u.v[i];   // ??? Is this OK???
 
     } // End while loop.
 
 // Monomials have been stored.
 // Now traverse the DA variable and evaluate.
 
 for( i = 0; i < DA__1stEnv.DA__SpaceDim; i++ )  {
   z->v[i] = concat( x.v[i] );
   for( j = 0; j < DA__1stEnv.DA__NumVar; j++ ) ( z->v[i] ).refPoint[j] = y.refPoint[j];
   }
 
 for( i = DA__1stEnv.DA__SpaceDim; i < DA__1stEnv.DA__NumVar; i++ ) {
   if( x.v[i] != y.v[i] )
     printf( "\n*** LieOperator CONCATENATION ERROR!!! Horrible!!!\n" );
   z->v[i] = y.v[i];
   }
 
 // Set the correct reference point and weights.
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = y.refPoint[i];
 
 z->weight = 0;
 z->accuWgt = DA__1stEnv.DA__MaxWeight;
 for( i = 0; i < DA__1stEnv.DA__SpaceDim; i++ )  {
  if( z->weight  < z->v[i].weight  ) z->weight  = z->v[i].weight;
  if( z->accuWgt > z->v[i].accuWgt ) z->accuWgt = z->v[i].accuWgt;
 }
 
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DA& concat( DA& x ) { 
 DA* v = new DA;
 dlist_iterator getNext( (dlist&) x );
 DAterm* p;
 int i;
 
 *v = 0.0;
 v->fixReference( DA__1stEnv.DA__DAmonomial[0] );
 
 while( p = (DAterm*) getNext() ) {
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) DA__1stEnv.DA__exponent[i] = (p->index)[i];
   DA__monoCode();
   *v += ( p->value ) * ( DA__1stEnv.DA__DAmonomial[ DA__monoRank() ] );
   }
 
 DA__garbage.store( v );
 return *v;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void operator*=( LieOperator& x, LieOperator& y ) {
 x = x*y;
}
 
 

//***************************************************************
//***************************************************************
//***************************************************************
//
//    Implementation of class coord
//
 
coord::coord( double x ) : DA() {
 int* n;
 coord* y;
 
 if( DA__1stEnv.DA__allSet != 137 ) {
   printf( "\n*** ERROR ***                                       \n" );
   printf(   "*** ERROR *** coord::coord( double )                \n" );
   printf(   "*** ERROR *** DASetup must be invoked first.        \n" );
   printf(   "*** ERROR ***                                       \n" );
   exit(1);
   }
 
 if( ( n = (int*) DA__coordPool.get() ) == 0 ) {
   printf( "\n*** ERROR ***                                       \n" );
   printf(   "*** ERROR *** coord::coord( double )                \n" );
   printf(   "*** ERROR *** Attempt made to declare too many      \n" );
   printf(   "*** ERROR *** coordinates, according to what was    \n" );
   printf(   "*** ERROR *** declared in DASetup.                  \n" );
   printf(   "*** ERROR ***                                       \n" );
   exit(1);
   }
 
 index = *n;
 DA::setVariable( x, index );
 delete n;
 
 DA__coordPtrs.append( this );
 dlist_iterator getNext( DA__coordPtrs );
 while( y = (coord*) getNext() ) y->fixReference();
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

coord::~coord() {
 int* n;
 char c;
 n = new int( index );
 DA__coordPool.insert( n );
 c = DA__coordPtrs.remove( this );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

coord::coord( coord& x ) {
 printf( "\n*** ERROR ***                                       \n" );
 printf(   "*** ERROR *** coord::coord( coord& )                \n" );
 printf(   "*** ERROR *** Coordinate copy constructor called.   \n" );
 printf(   "*** ERROR ***                                       \n" );
 exit(1);
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void coord::set( double x ) {
 coord* y;
 DA::setVariable( x, index );
 dlist_iterator getNext( DA__coordPtrs );
 while( y = (coord*) getNext() ) y->fixReference();
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

coord& coord::operator=( coord& ) {
 printf( "\n*** ERROR ***                                       \n" );
 printf(   "*** ERROR *** coord::operator=                      \n" );
 printf(   "*** ERROR *** Attempt made to change the value      \n" );
 printf(   "*** ERROR *** of a coordinate.                      \n" );
 printf(   "*** ERROR ***                                       \n" );
 if( 3 + 8 == 11 ) exit(1);  // To avoid compiler warnings.
 return *this;
}


// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

coord& coord::operator=( DA& ) {
 printf( "\n*** ERROR ***                                       \n" );
 printf(   "*** ERROR *** coord::operator=                      \n" );
 printf(   "*** ERROR *** Attempt made to change the value      \n" );
 printf(   "*** ERROR *** of a coordinate.                      \n" );
 printf(   "*** ERROR ***                                       \n" );
 if( 3 + 8 == 11 ) exit(1);  // To avoid compiler warnings.
 return *this;
}



//***************************************************************
//***************************************************************
//***************************************************************
//
//    DAAbout() and DANews
//

void DAAbout() {
 printf("\n\n");
 printf("MXYZPTLK:  A C++ implementation of differential algebra.      \n");
 printf("                                                              \n");
 printf("Copyright (c) 1990  Universities Research Association, Inc.   \n");
 printf("              All Rights Reserved                             \n");
 printf("                                                              \n");
 printf("Author:    Leo Michelotti                                     \n");
 printf("                                                              \n");
 printf("           Fermilab                                           \n");
 printf("           P.O.Box 500                                        \n");
 printf("           Mail Stop 345                                      \n");
 printf("           Batavia, IL   60510                                \n");
 printf("                                                              \n");
 printf("           Phone: (708) 840 4956                              \n");
 printf("           Email: michelot@hazel.fnal.gov                     \n");
 printf("                  michelotti@adcalc.fnal.gov                  \n");
 printf("                  almond::michelotti                          \n");
 printf("                                                              \n");
 printf("Release    Version 1.0 : January 31, 1990                     \n");
 printf("Dates:              .1 : October 11, 1990                     \n");
 printf("                    .2 : November 6, 1990                     \n");
 printf("                    .3 : October  2, 1992                     \n");
 printf("                    .4 : July    20, 1993                     \n");
 printf("\n");
}

void DANews() {
 printf( "\n\n" );
 printf( "11/6/90   .. Leo Michelotti                                   \n" );
 printf( "DA functions  pow( DA&, double )  and  sqrt( DA& ) have       \n" );
 printf( "been included in the lexicon.                                 \n" );
 printf( "\n" );
}


//***************************************************************
//***************************************************************
//***************************************************************
//
//    Complex DA
//

#include "mxyzptlk_complex.cc"
#include "mxyzptlk_DAC.cc"
End of mxyzptlk.cc
echo mxyzptlk_complex.cc 1>&2
cat >mxyzptlk_complex.cc <<'End of mxyzptlk_complex.cc'
// ||||||| Constructors and destructors ||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

ComplexDA::ComplexDA() {
 re = 0.0;
 im = 0.0;
}


ComplexDA::ComplexDA( DA& x, DA& y ) {
 re = x;
 im = y;
}


ComplexDA::ComplexDA( ComplexDA& x ) {
 re = x.re;
 im = x.im;

 DA__garbage.store( this );
}

ComplexDA::~ComplexDA() {
}



// ||||||| Arithmetic operations |||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

ComplexDA& ComplexDA::operator=( ComplexDA& y ) { 
 if( this == &y ) {
   printf( "*** WARNING *** \n" );
   printf( "*** WARNING *** ComplexDA::operator=\n" );
   printf( "*** WARNING *** Why are you trying to set x = x???\n" );
   printf( "*** WARNING *** \n" );
   return *this;
 }
 re = y.re;
 im = y.im;
 return *this; 
} 


// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

ComplexDA&  conj( ComplexDA& x ) {
 ComplexDA* z = new ComplexDA ( x.re, - x.im );
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

ComplexDA&  operator-( ComplexDA& x ) {
 ComplexDA* z = new ComplexDA ( - x.re, - x.im );
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

ComplexDA&  operator+( ComplexDA& x, ComplexDA& y ) {
 ComplexDA* z = new ComplexDA ( x.re + y.re, x.im + y.im );
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

ComplexDA&  operator+( ComplexDA& x, DA& y ) {
 ComplexDA* z = new ComplexDA ( x.re + y, x.im );
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

ComplexDA&  operator+( DA& x, ComplexDA& y ) {
 ComplexDA* z = new ComplexDA ( x + y.re, y.im );
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

ComplexDA&  operator-( ComplexDA& x, ComplexDA& y ) {
 ComplexDA* z = new ComplexDA ( x.re - y.re, x.im - y.im );
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

ComplexDA&  operator-( ComplexDA& x, DA& y ) {
 ComplexDA* z = new ComplexDA ( x.re - y, x.im );
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

ComplexDA&  operator-( DA& x, ComplexDA& y ) {
 ComplexDA* z = new ComplexDA ( x - y.re, y.im );
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

ComplexDA&  operator*( ComplexDA& x, ComplexDA& y ) {
 DA xr, xi, yr, yi;
 xr = x.re;
 xi = x.im;
 yr = y.re;
 yi = y.im;
 ComplexDA* z = new ComplexDA ( xr*yr - xi*yi, xi*yr + xr*yi );
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

ComplexDA&  operator*( ComplexDA& x, DA& y ) {
 ComplexDA* z = new ComplexDA ( x.re * y, x.im );
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

ComplexDA&  operator*( DA& x, ComplexDA& y ) {
 ComplexDA* z = new ComplexDA ( x * y.re, y.im );
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

ComplexDA&   operator/( ComplexDA& x, DA& y ) {
 ComplexDA* z = new ComplexDA ( x.re/y, x.im/y );
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

ComplexDA&   operator/( ComplexDA& x, ComplexDA& y ) {
 return  ( x*conj(y) / ( y.re*y.re + y.im*y.im ) );
}


// ||||||| Utilities |||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void ComplexDA::peekAt()  {
 dlist_traversor getNext( *(dlist*) this );
 printf( "\n___ ComplexDA::peekAt() __ ( begin ) _____\n" );
 printf(   "___ Real part: ___________________________\n" );
 re.peekAt();
 printf( "\n___ Imag part: ___________________________\n" );
 im.peekAt();
 printf( "\n___ ComplexDA::peekAt() __ ( end )________\n" );
}
End of mxyzptlk_complex.cc
echo mxyzptlk_DAC.cc 1>&2
cat >mxyzptlk_DAC.cc <<'End of mxyzptlk_DAC.cc'
/*************************************************************************
**************************************************************************
**************************************************************************
******                                                                ****
******  MXYZPTLK:  A C++ implementation of differential algebra.      ****
******                                                                ****
******  Copyright (c) 1990  Universities Research Association, Inc.   ****
******                All Rights Reserved                             ****
******                                                                ****
******  Author:    Leo Michelotti                                     ****
******                                                                ****
******             Fermilab                                           ****
******             P.O.Box 500                                        ****
******             Mail Stop 345                                      ****
******             Batavia, IL   60510                                ****
******                                                                ****
******             Phone: (708) 840 4956                              ****
******             Email: michelot@hazel.fnal.gov                     ****
******                    michelotti@adcalc.fnal.gov                  ****
******                    almond::michelotti                          ****
******                                                                ****
******  Release    Version 1.0 : January 31, 1990                     ****
******  Dates:              .1 : October 11, 1990                     ****
******                      .2 : November 6, 1990                     ****
******                      .3 : October  2, 1992                     ****
******                      .4 : July    20, 1993                     ****
******                     2.0   August  12, 1993                     ****
******                                                                ****
**************************************************************************
**************************************************************************
******                                                                ****
******  This material resulted from work developed under a            ****
******  Government Contract and is subject to the following           ****
******  license: The Government retains a paid-up, nonexclusive,      ****
******  irrevocable worldwide license to reproduce, prepare           ****
******  derivative works, perform publicly and display publicly       ****
******  by or for the Government, including the right to distribute   ****
******  to other Government contractors.  Neither the United          ****
******  States nor the United States Department of Energy, nor        ****
******  any of their employees, makes any warranty, express or        ****
******  implied, or assumes any legal liability or responsibility     ****
******  for the accuracy, completeness or usefulness of any           ****
******  information, apparatus, product, or process disclosed, or     ****
******  represents that its use would not infringe privately owned    ****
******  rights.                                                       ****
******                                                                ****
**************************************************************************
**************************************************************************
******                                                                ****
******  Notes:                                                        ****
******                                                                ****
******  11/6/90   .. Leo Michelotti                                   ****
******  DA functions  pow( DA&, double )  and  sqrt( DA& ) have       ****
******  been included in the lexicon.                                 ****
******                                                                ****
******                                                                ****
******  10/11/90  .. Leo Michelotti                                   ****
******  DASetup routines have been changed so that the variable       ****
******  DA__1stEnv.DA__allSet and the array DA__1stEnv.DA__refPoint   ****
******  are set earlier.  This fixes a bug which first arose in       ****
******  an application involving concatenation.                       ****
******                                                                ****
******                                                                ****
******  10/2/92  .. Leo Michelotti                                    ****
******  In   double DA::weightedDerivative( int* ind ), the cast      ****
******  appearing in declaring a dlist_iterator was changed           ****
******  from (dlist) to (dlist&) in order to bypass a call to         ****
******  the dlist copy constructor.  I suspect g++ does not           ****
******  handle casting correctly, but I cannot yet prove it.          ****
******  It may also be true that the copy constructor is not          ****
******  working properly.                                             ****
******                                                                ****
******                                                                ****
******  7/20/93 .. Leo Michelotti                                     ****
******  In an attempt to improve efficiency, functions that           ****
******  previously returned DA have been changed to return            ****
******  DA&.  In conjunction with this, a disposable base             ****
******  class has been defined in order to provide for some           ****
******  primitive garbate collection.                                 ****
******                                                                ****
******  The code sandwiched between #ifdef POOLED and #endif          ****
******  POOLED statements is still under development.  It             ****
******  should not be activated by the Makefile.                      ****
******                                                                ****
******                                                                ****
******  8/12/93 .. Leo Michelotti                                     ****
******  The LieOperator methods .expMap() and .operator^              ****
******  have now been implemented.  The former                        ****
******  integrates equations of motion by developing                  ****
******  exponential maps, and the latter simply                       ****
******  evaluates a Lie derivative.  The one restriction              ****
******  at the moment is the assumption made by                       ****
******  .expMap() that the point of evaluation is a                   ****
******  fixed point of the vector field.  There are ways              ****
******  of getting around this -- but, another day.                   ****
******  Demos are contained in files Lie_X_Test.cc,                   ****
******  where X = A ... E.                                            ****
******                                                                ****
******     __ This upgrade is significant enough to                   ****
******  warrant a version change, from 1.X to 2.0.                    ****
******  Huzzah!                                                       ****
******                                                                ****
******     __ Addition has been modified so that small                ****
******  terms indistinguishable from zero are not                     ****
******  carried.  Further, arithmetic on LieOperators                 ****
******  has been enabled.                                             ****
******                                                                ****
**************************************************************************
*************************************************************************/

#include "mxyzptlk.hxx"


// ================================================================
//      The environment
//

extern Attic  DA__garbage;
extern struct DAC__environment DAC__1stEnv;
extern struct DA__environment DA__1stEnv;
extern FILE  *DA__scratchFile;
extern dlist  DAC__coordPool;
extern dlist  DAC__coordPtrs;

// ================================================================
//      External routines
//

extern char nexcom( int, int, int* );  // Computes the next composition
                                 // of an integer into a number of parts.

extern "C" {
  int bcfRec( int, int );   // Recursive evaluation of binomial
                            // coefficient.
  int nearestInteger( double );  // Returns the integer nearest to its
                            // double argument.
  }

// ================================================================
//      Global functions

void    DAC__monoCode();     // Computes the code of a monomial from its
                            //   exponents.
void    DAC__monoDecode();   // The inverse operation to monoCode.
int     DAC__monoRank();     // Computes the rank of a monomial.


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

#define CARRIAGERETURN printf("\n")
static const complex complex_one(1.0,0.0);

//***************************************************************
//***************************************************************
//***************************************************************
//
//      Initialization routines DACSetup.
//      Must be called first by any program in order to establish the
//      number of (scalar) variables, n,
//      maximum weight of derivatives, w,
//      dimension of phase space, s,
//      default reference point, r.

void DACSetup( int n, int w ) {
 int i, j;
 DAC* p;
 CLieOperator* q;
 
 if( DAC__1stEnv.DAC__allSet == 137 )
   printf( "\n*** DAC ERROR *** Attempt to call DACSetup twice.\n" );
 
 else {
 
   // Some error checking ..
   if( n < 1 ) {
     printf("\n*** DACSetup requires at least one variable.");
     printf("\n*** Number of variables is reset to 1.\n");
     n = 1;
     }
 
   if( w < 1 ) {
     printf("\n*** DACSetup requires a minimal maximum weight of 1.");
     printf("\n*** Maximum weight is reset to 2.\n");
     w = 2;
     }
 
   DAC__1stEnv.DAC__allSet = 137;
 
   // The default reference point is set to the origin.
   DAC__1stEnv.DAC__refPoint = new complex[ n ];
   for( i = 0; i < n; i++ ) DAC__1stEnv.DAC__refPoint[i] = complex_zero;
 
   DAC__1stEnv.DAC__NumVar = n;
   DAC__1stEnv.DAC__MaxWeight = w;
   DAC__1stEnv.DAC__exponent = new int[ n ];
   DAC__1stEnv.DAC__expCode = new char[ w + n ];
   DAC__1stEnv.DAC__monomial = new complex[ bcfRec( w + n, n ) ];
   DAC__1stEnv.DAC__SpaceDim = 0;             // No DAC vectors will be allowed.
   DAC__1stEnv.DAC__PBOK = 0;                 // No Poisson brackets allowed.
 
   DAC__1stEnv.DAC__AllZeroes = new int[ n ];
   for( i = 0; i < n; i++ ) DAC__1stEnv.DAC__AllZeroes[i] = 0;
 
   // Go through all predefined DAC variables: set the reference
   // and weight accuracy.
   while( p = (DAC*) DAC__1stEnv.DAC__predefDA.get() ) {
     p->refPoint = new complex[ DAC__1stEnv.DAC__NumVar ];
     for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) (p->refPoint)[i] = DAC__1stEnv.DAC__refPoint[i];
     p->accuWgt = DAC__1stEnv.DAC__MaxWeight;
     }
   while( q = (CLieOperator*) DAC__1stEnv.DAC__predefLieOp.get() ) {
     q->v = new DAC[ DAC__1stEnv.DAC__NumVar ];
     q->refPoint = new complex[ DAC__1stEnv.DAC__NumVar ];
     for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) (q->refPoint)[i] = DAC__1stEnv.DAC__refPoint[i];
     }
 
   // Load the DAC__1stEnv.DAC__numPaths array with binomial coefficients;
   // required by Wilf's algorithm for ranking monomials.
   DAC__1stEnv.DAC__numPaths = imatrix( 0, w, 1, n );
   for( i = 0; i <= w; i++ )
     for( j = 1; j <= n; j++ )
       DAC__1stEnv.DAC__numPaths[i][j] = bcfRec( i + j - 1, i );
 
   // Initialize the DAC__coordPool dlist
   int* counter;
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
     counter = new int(i);
     DAC__coordPool.append( counter );
     }
 
   }
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DACSetup( int n, int w, complex* r ) {
 int i, j;
 DAC* p;
 CLieOperator* q;
 
 if( DAC__1stEnv.DAC__allSet == 137 )
   printf( "\n*** DAC ERROR *** Attempt to call DACSetup twice.\n" );
 
 else {
 
   // Some error checking ..
   if( n < 1 ) {
     printf("\n*** DACSetup requires at least one variable.");
     printf("\n*** Number of variables is reset to 1.\n");
     n = 1;
     }
 
   if( w < 1 ) {
     printf("\n*** DACSetup requires a minimal maximum weight of 1.");
     printf("\n*** Maximum weight is reset to 2.\n");
     w = 2;
     }
 
   DAC__1stEnv.DAC__allSet = 137;
 
   // The default reference point is set.
   DAC__1stEnv.DAC__refPoint = new complex[ n ];
   for( i = 0; i < n; i++ ) DAC__1stEnv.DAC__refPoint[i] = r[i];
 
   DAC__1stEnv.DAC__NumVar = n;
   DAC__1stEnv.DAC__MaxWeight = w;
   DAC__1stEnv.DAC__exponent = new int[ n ];
   DAC__1stEnv.DAC__expCode = new char[ w + n ];
   DAC__1stEnv.DAC__monomial = new complex[ bcfRec( w + n, n ) ];
   DAC__1stEnv.DAC__SpaceDim = 0;             // No DA vectors will be allowed.
   DAC__1stEnv.DAC__PBOK = 0;                 // No Poisson brackets allowed.
 
   DAC__1stEnv.DAC__AllZeroes = new int[ n ];
   for( i = 0; i < n; i++ ) DAC__1stEnv.DAC__AllZeroes[i] = 0;
 
   // Go through all predefined DAC variables: set the reference
   // and weight accuracy.
   while( p = (DAC*) DAC__1stEnv.DAC__predefDA.get() ) {
     p->refPoint = new complex[ DAC__1stEnv.DAC__NumVar ];
     for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) (p->refPoint)[i] = DAC__1stEnv.DAC__refPoint[i];
     p->accuWgt = DAC__1stEnv.DAC__MaxWeight;
     }
   while( q = (CLieOperator*) DAC__1stEnv.DAC__predefLieOp.get() ) {
     q->v = new DAC[ DAC__1stEnv.DAC__NumVar ];
     q->refPoint = new complex[ DAC__1stEnv.DAC__NumVar ];
     for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) (q->refPoint)[i] = DAC__1stEnv.DAC__refPoint[i];
     }
 
   // Load the DAC__1stEnv.DAC__numPaths array with binomial coefficients;
   // required by Wilf's algorithm for ranking monomials.
   DAC__1stEnv.DAC__numPaths = imatrix( 0, w, 1, n );
   for( i = 0; i <= w; i++ )
     for( j = 1; j <= n; j++ )
       DAC__1stEnv.DAC__numPaths[i][j] = bcfRec( i + j - 1, i );
 
   // Initialize the DAC__coordPool dlist
   int* counter;
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
     counter = new int(i);
     DAC__coordPool.append( counter );
     }
 
   }
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DACSetup( int n, int w, int s ) {
 int i, j;
 DAC* p;
 CLieOperator* q;
 
 
 if( DAC__1stEnv.DAC__allSet == 137 )
   printf( "\n*** DAC ERROR: Attempt to call DACSetup twice.\n" );
 
 else {
 
   // Some error checking ..
   if( n < 1 ) {
     printf("\n*** DAC WARNING: DACSetup requires at least one variable.");
     printf("\n*** DAC WARNING: Number of variables is reset to 1.\n");
     n = 1;
     }
 
   if( w < 1 ) {
     printf("\n*** DAC WARNING: DACSetup requires minimal maximum weight of 1.");
     printf("\n*** DAC WARNING: Maximum weight is reset to 2.\n");
     w = 2;
     }
 
   if ( n < s ) {
     printf( "\n*** DAC ERROR: DACSetup called with incompatible parameters." );
     printf( "\n**********************************************************\n" );
     exit(0);
     }
 
   DAC__1stEnv.DAC__allSet = 137;
 
   // The default reference point is set to the origin.
   DAC__1stEnv.DAC__refPoint = new complex[ n ];
   for ( i = 0; i < n; i++ ) DAC__1stEnv.DAC__refPoint[i] = complex_zero;
 
   // Set global variables.
   DAC__1stEnv.DAC__NumVar = n;
   DAC__1stEnv.DAC__MaxWeight = w;
   DAC__1stEnv.DAC__exponent = new int[ n ];
   DAC__1stEnv.DAC__expCode = new char[ w + n ];
   DAC__1stEnv.DAC__monomial = new complex[ bcfRec( w + n, n ) ];
   DAC__1stEnv.DAC__DAmonomial = new DAC[ bcfRec( w + n, n ) ];
   DAC__1stEnv.DAC__SpaceDim = s;
   DAC__1stEnv.DAC__dof = s/2;
   DAC__1stEnv.DAC__PBOK = ( 2*DAC__1stEnv.DAC__dof == s );
 
   DAC__1stEnv.DAC__AllZeroes = new int[ n ];
   for( i = 0; i < n; i++ ) DAC__1stEnv.DAC__AllZeroes[i] = 0;
 
   // Go through all predefined DAC variables: set the reference
   // and weight accuracy.
   while( p = (DAC*) DAC__1stEnv.DAC__predefDA.get() ) {
     p->refPoint = new complex[ DAC__1stEnv.DAC__NumVar ];
     for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) (p->refPoint)[i] = DAC__1stEnv.DAC__refPoint[i];
     p->accuWgt = DAC__1stEnv.DAC__MaxWeight;
     }
   while( q = (CLieOperator*) DAC__1stEnv.DAC__predefLieOp.get() ) {
     q->v = new DAC[ DAC__1stEnv.DAC__NumVar ];
     q->refPoint = new complex[ DAC__1stEnv.DAC__NumVar ];
     for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) (q->refPoint)[i] = DAC__1stEnv.DAC__refPoint[i];
     }
 
   // Load the DAC__1stEnv.DAC__numPaths array with binomial coefficients;
   // required by Wilf's algorithm for ranking monomials.
   DAC__1stEnv.DAC__numPaths = imatrix( 0, w, 1, n );
   for( i = 0; i <= w; i++ )
     for( j = 1; j <= n; j++ )
       DAC__1stEnv.DAC__numPaths[i][j] = bcfRec( i + j - 1, i );
 
   // Initialize the DAC__coordPool dlist
   int* counter;
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
     counter = new int(i);
     DAC__coordPool.append( counter );
     }
 
   }
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DACSetup( int n, int w, int s, complex* r ) {
 int i, j;
 DAC* p;
 CLieOperator* q;
 
 if( DAC__1stEnv.DAC__allSet == 137 )
   printf( "\n*** DAC ERROR: Attempt to call DACSetup twice.\n" );
 
 else {
 
   // Some error checking ..
   if( n < 1 ) {
     printf("\n*** DAC WARNING: DACSetup requires at least one variable.");
     printf("\n*** DAC WARNING: Number of variables is reset to 1.\n");
     n = 1;
     }
 
   if( w < 1 ) {
     printf("\n*** DAC WARNING: DACSetup requires minimal maximum weight of 1.");
     printf("\n*** DAC WARNING: Maximum weight is reset to 2.\n");
     w = 2;
     }
 
   if( s < 2 ) {
     printf("\n*** DAC WARNING: DACSetup requires minimum vector size of 2.");
     printf("\n*** DAC WARNING: Vector size is reset to 2.\n");
     s = 2;
     }
 
   if ( n < s ) {
     printf( "\n*** DAC ERROR: DACSetup called with incompatible parameters." );
     printf( "\n**********************************************************\n" );
     exit(0);
     }
 
   DAC__1stEnv.DAC__allSet = 137;
 
   // The default reference point is set.
   DAC__1stEnv.DAC__refPoint = new complex[ n ];
   for( i = 0; i < n; i++ ) DAC__1stEnv.DAC__refPoint[i] = r[i];
 
   // Set global variables.
   DAC__1stEnv.DAC__NumVar = n;
   DAC__1stEnv.DAC__MaxWeight = w;
   DAC__1stEnv.DAC__exponent = new int[ n ];
   DAC__1stEnv.DAC__expCode = new char[ w + n ];
   DAC__1stEnv.DAC__monomial = new complex[ bcfRec( w + n, n ) ];
   DAC__1stEnv.DAC__DAmonomial = new DAC[ bcfRec( w + n, n ) ];
   DAC__1stEnv.DAC__SpaceDim = s;
   DAC__1stEnv.DAC__dof = s/2;
   DAC__1stEnv.DAC__PBOK = ( 2*DAC__1stEnv.DAC__dof == s );
 
   DAC__1stEnv.DAC__AllZeroes = new int[ n ];
   for( i = 0; i < n; i++ ) DAC__1stEnv.DAC__AllZeroes[i] = 0;
 
   // Go through all predefined DAC variables: set the reference
   // and weight accuracy.
   while( p = (DAC*) DAC__1stEnv.DAC__predefDA.get() ) {
     p->refPoint = new complex[ DAC__1stEnv.DAC__NumVar ];
     for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) (p->refPoint)[i] = DAC__1stEnv.DAC__refPoint[i];
     p->accuWgt = DAC__1stEnv.DAC__MaxWeight;
     }
   while( q = (CLieOperator*) DAC__1stEnv.DAC__predefLieOp.get() ) {
     q->v = new DAC[ DAC__1stEnv.DAC__NumVar ];
     q->refPoint = new complex[ DAC__1stEnv.DAC__NumVar ];
     for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) (q->refPoint)[i] = DAC__1stEnv.DAC__refPoint[i];
     }
 
   // Load the DAC__1stEnv.DAC__numPaths array with binomial coefficients;
   // required by Wilf's algorithm for ranking monomials.
   DAC__1stEnv.DAC__numPaths = imatrix( 0, w, 1, n );
   for( i = 0; i <= w; i++ )
     for( j = 1; j <= n; j++ )
       DAC__1stEnv.DAC__numPaths[i][j] = bcfRec( i + j - 1, i );
 
   // Initialize the DAC__coordPool dlist
   int* counter;
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
     counter = new int(i);
     DAC__coordPool.append( counter );
     }
 
   }
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DACFixReference( complex* r ) {
 int i;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) DAC__1stEnv.DAC__refPoint[i] = r[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DACFixReferenceAtEnd( CLieOperator& x ) {
 int i;
 complex* u = new complex [ DAC__1stEnv.DAC__NumVar ];
 x.standardPart( u );
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) DAC__1stEnv.DAC__refPoint[i] = u[i];
 delete [] u;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DACFixReferenceAtStart( CLieOperator& x ) {
 int i;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) DAC__1stEnv.DAC__refPoint[i] = x.refPoint[i];
}
 
 
 //***************************************************************
 //***************************************************************
 //***************************************************************
 //
 //     Implementation of struct DAC__environment
 
 
DAC__environment::DAC__environment() {
  DAC__monomial           = 0;
  DAC__DAmonomial         = 0;
  DAC__exponent           = 0;
  DAC__expCode            = 0;
  DAC__numPaths           = 0;
  DAC__NumVar             = 0;
  DAC__MaxWeight          = 0;
  DAC__allSet             = 0;
  DAC__weightLimit        = 0;    
  DAC__SpaceDim           = -1;
  DAC__dof                = 0;            
  DAC__refPoint           = 0;       
  DAC__AllZeroes          = 0;      
}
 
 
DAC__environment::~DAC__environment() {
  if( DAC__allSet == 137 ) {
   delete [] DAC__monomial;       
   if( DAC__DAmonomial ) delete [] DAC__DAmonomial;     
   delete [] DAC__exponent;       
   delete [] DAC__expCode;        
  
   free_imatrix( DAC__numPaths, 0, DAC__MaxWeight, 1, DAC__NumVar ); // ???
                                 // ??? Carrying this around is stupid!!
   delete [] DAC__refPoint;       
   delete [] DAC__AllZeroes;      
  
   // ??? DAC* p;
   // ??? while( p = (DAC*) DAC6__predefDA.get() ) delete p;
   // ??? CLieOperator* q;
   // ??? while( q = (CLieOperator*) DAC__predefLieOp.get() ) delete q;
  }
}



//***************************************************************
//***************************************************************
//***************************************************************
//
//      Implementation of Class DAC

//    Constructors and destructors    |||||||||||||||||||||||||||

DAC::DAC() {
 int i;
 
 weight = -1;
 count = 0;
 accuWgt = DAC__1stEnv.DAC__MaxWeight;
 
 if( DAC__1stEnv.DAC__allSet == 137 ) {
   refPoint = new complex[ DAC__1stEnv.DAC__NumVar ];
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = DAC__1stEnv.DAC__refPoint[i];
   }
 else {
   DAC__1stEnv.DAC__predefDA.insert( this );
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC::DAC(DA& x) {

 dlist_iterator getNext( (dlist&) x );
 DAterm* p;
 DACterm* q;
 int i;
 
 if( DAC__1stEnv.DAC__allSet != 137 ) {
   printf( "\n*** DAC::DAC( DA& ) ERROR *** " );
   printf( "Prior call to DACSetup required.\n" );
   exit(0);
   }
 
 if( DA__1stEnv.DA__allSet != 137 ) {
   printf( "\n*** DA::DA( DA& ) ERROR *** " );
   printf( "Prior call to DASetup required.\n" );
   exit(0);
   }
 
 while( p = (DAterm*) getNext() ) {
   q = new DACterm( p );
   append( q );
   }
 count    = x.count;
 weight   = x.weight;
 accuWgt  = x.accuWgt;
 refPoint = new complex[ DA__1stEnv.DA__NumVar ];
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) 
   refPoint[i] = complex(x.refPoint[i],0.0);
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC::DAC( complex x ) {
 int* ndx;
 int i;
 
 if( DAC__1stEnv.DAC__allSet != 137 ) {
   printf( "\n*** DAC::DAC( complex ) ERROR *** " );
   printf( "Prior call to DACSetup required.\n" );
   exit(0);
   }
 
 clear();
 weight = 0;
 count = 0;
 accuWgt = DAC__1stEnv.DAC__MaxWeight;
 
 refPoint = new complex[ DAC__1stEnv.DAC__NumVar ];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = DAC__1stEnv.DAC__refPoint[i];
 
                             // ??? There is some danger here!  This constructor
                             //     governs the conversion of complex into DA.
                             //     In an expression like 3.0 * z, where z is a DA,
                             //     the multiplication may not go through if the
                             //     current reference point has changed since z
                             //     was created.  One way around this is to overload
                             //     all arithmetic operators explicitly so conversion
                             //     is never necessary.
 
 ndx = new int[ DAC__1stEnv.DAC__NumVar ];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) ndx[i] = 0;
 insert( new DACterm( ndx, x ) );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC::DAC( DAC& x ) {
 dlist_iterator getNext( (dlist&) x );
 DACterm* p;
 DACterm* q;
 int i;
 
 if( DAC__1stEnv.DAC__allSet != 137 ) {
   printf( "\n*** DAC::DAC( DAC& ) ERROR *** " );
   printf( "Prior call to DACSetup required.\n" );
   exit(0);
   }
 
 if( DAC__1stEnv.DAC__allSet != 137 ) {
   printf( "\n*** DAC::DAC( DAC& ) ERROR *** " );
   printf( "Prior call to DACSetup required.\n" );
   exit(0);
   }
 
 while( p = (DACterm*) getNext() ) {
   q = new DACterm( p );
   append( q );
   }
 count    = x.count;
 weight   = x.weight;
 accuWgt  = x.accuWgt;
 refPoint = new complex[ DAC__1stEnv.DAC__NumVar ];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = x.refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC::~DAC() {
 clear();
 delete [] refPoint;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

//     Member functions(public)  |||||||||||||||||||||||||||||||

void DAC::addTerm( DACterm* a) {
 dlist_traversor getNext( *(dlist*) this );
 dlink* p;
 
 // If the value of *a is 0, don't bother with it unless
 // the weight is also 0.
 if( ( a -> value == 0.0 ) && ( a -> weight != 0 ) ) return;
 
 //
 // In the event that the candidate is lighter than the first
 // element in the DAC dlist ... or the list is empty
 //
 p = getNext();
 
 if( p == 0 ) {
   insert( a );
   return;
   }
 
 if(     *a   <=   ( *(DACterm*) (p->info()) )   ) {
   if(   *a   %=   ( *(DACterm*) (p->info()) )   ) {
 
     (( (DACterm*) (p->info()) ) -> value ) += ( a -> value );
 
     if(
         (
           fabs( real( ( (DACterm*) (p->info()) ) -> value ) ) < MX_SMALL*fabs( real( a -> value ) )
            && 
           fabs( imag( ( (DACterm*) (p->info()) ) -> value ) ) < MX_SMALL*fabs( imag( a -> value ) )
         )
         // REMOVE ??? &&
         // REMOVE ??? (
         // REMOVE ???   p != ( dlist::lastPtr() ) -> nextPtr()
         // REMOVE ??? )
       )
 
         delete remove( p );
 
     delete a;
     return;
     }
 
   else {
     insert( a );
     return;
     }
 
   }
 
 //
 // Otherwise, search through the list
 //
 while( p = getNext() ){
 
   if(     *a   <=   ( *(DACterm*) (p->info()) )   ) {
     if(   *a   %=   ( *(DACterm*) (p->info()) )   ) {
 
       (( (DACterm*) (p->info()) ) -> value ) += ( a -> value );
 
       if(
           (
             fabs( real( ( (DACterm*) (p->info()) ) -> value ) ) < MX_SMALL*fabs( real( a -> value ) )
              && 
             fabs( imag( ( (DACterm*) (p->info()) ) -> value ) ) < MX_SMALL*fabs( imag( a -> value ) )
           )
           // REMOVE ??? &&
           // REMOVE ??? (
           // REMOVE ???   p != ( dlist::lastPtr() ) -> nextPtr()
           // REMOVE ??? )
         )
 
         delete remove( p );
 
       delete a;
       return;
       }
 
     else {
       p -> putAbove( new dlink( a, 0, 0 ) );
       (this->count)++;
       if( (this->weight) < (a->weight) ) this->weight = a->weight;
       return;
       }
 
     }
   }
 
 //
 //  The new entry is heavier than existing ones.
 //
 append( a );
 return;
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::fixReference( complex* r ) {
 int i;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = r[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::fixReference() {
 int i;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = DAC__1stEnv.DAC__refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::fixReference( DAC& x ) {
 int i;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = x.refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::fixReferenceAtEnd( CLieOperator& x ) {
 int i;
 complex* u = new complex [ DAC__1stEnv.DAC__NumVar ];
 x.standardPart( u );
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = u[i];
 delete [] u;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::fixReferenceAtStart( CLieOperator& x ) {
 int i;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = x.refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::getReference( complex* r ) {
 int i;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) r[i] = refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char DAC::isNilpotent() {
 dlist_iterator getNext( *(dlist*) this );
 DACterm* p = (DACterm*) getNext();
 if( p->weight == 0 && p->value != complex_zero ) return 0;
 else                                             return 1;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::peekAt() {
 dlist_traversor getNext( *(dlist*) this );
 int i;
 DACterm* p;
 dlink* q;
 printf( "\nCount  = %d, Weight = %d, Max accurate weight = %d\n",
          count, weight, accuWgt );
 printf( "Reference point:  \n" );
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
   printf( "(%e, %e)  ", real(refPoint[i]),imag(refPoint[i]) );
 printf( "\n" );
 while( q = getNext() ) {
   p = (DACterm*) q->info();
   printf( "Weight: %d   Value: (%e, %e)  || ",
           p -> weight,real( p -> value),imag(p -> value) );
   printf("Addresses: %d %d %d : %d\n", q->prevPtr(), q, q->nextPtr(), p );
   printf("Index:  ");
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
     printf( "%d  ", (p -> index)[i] );
   printf("\n\n");
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::printCoeffs() {
 dlist_traversor getNext( *(dlist*) this );
 int i;
 DACterm* p;
 dlink* q;
 printf( "\nCount  = %d, Weight = %d, Max accurate weight = %d\n",
          count, weight, accuWgt );
 printf( "Reference point: " );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) 
    printf( "(%e,%e)  ", real(refPoint[i]),imag(refPoint[i]) );
 printf( "\n\n" );
 while( q = getNext() ) {
   p = (DACterm*) q->info();
   printf("Index:  ");
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
     printf( "%3d ", (p -> index)[i] );
   printf( "   Value: (%14.6le, %14.6le)  ", real(p -> value),
	   imag(p -> value) );
   printf("\n");
   }
 printf( "\n\n" );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::peekAt( int  ) {
 dlist_traversor getNext( *(dlist*) this );
 int i;
 DACterm* p;
 dlink* q;
 fprintf( DA__scratchFile,
          "\nCount  = %d, Weight = %d, Max accurate weight = %d\n",
          count, weight, accuWgt );
 fprintf( DA__scratchFile, "Reference point:  \n" );
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
   fprintf( DA__scratchFile, "%e %e ", real(refPoint[i]),imag(refPoint[i]) );
 fprintf( DA__scratchFile, "\n" );
 while( q = getNext() ) {
   p = (DACterm*) q->info();
   fprintf( DA__scratchFile, "Weight: %d   Value: %e %e || ",
           p -> weight, real( p -> value),imag(p -> value) );
   fprintf( DA__scratchFile, "Addresses: %d %d %d : %d\n",
                  q->prevPtr(), q, q->nextPtr(), p );
   fprintf( DA__scratchFile, "Index:  ");
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
     fprintf( DA__scratchFile, "%d  ", (p -> index)[i] );
   fprintf( DA__scratchFile, "\n\n");
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::printCoeffs( int  ) {
 dlist_traversor getNext( *(dlist*) this );
 int i;
 DACterm* p;
 dlink* q;
 fprintf( DA__scratchFile, "\nCount  = %d, Weight = %d, Max accurate weight = %d\n",
          count, weight, accuWgt );
 fprintf( DA__scratchFile, "Reference point:  " );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) 
   fprintf( DA__scratchFile, "(%e,%e)  ", real(refPoint[i]),
	    imag(refPoint[i]) );
 fprintf( DA__scratchFile, "\n\n" );
 while( q = getNext() ) {
   p = (DACterm*) q->info();
   fprintf( DA__scratchFile,"Index:  ");
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
     fprintf( DA__scratchFile, "%3d ", (p -> index)[i] );
   fprintf( DA__scratchFile, "   Value: (%14.6e,%14.6e)  ", real(p -> value),
	    imag(p -> value) );
   fprintf( DA__scratchFile,"\n");
   }
 fprintf( DA__scratchFile, "\n\n" );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::writeToFile( char* fileName ) {
 dlist_traversor getNext( *(dlist*) this );
 int i;
 DACterm* p;
 dlink* q;
 
 DA__scratchFile = fopen( fileName, "w" );
 
 fprintf( DA__scratchFile,
          "\nCount  = %d, Weight = %d, Max accurate weight = %d\n",
          count, weight, accuWgt );
 fprintf( DA__scratchFile, "Reference point:  \n" );
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
   fprintf( DA__scratchFile, "%e  ", refPoint[i] );
 fprintf( DA__scratchFile, "\n" );
 while( q = getNext() ) {
   p = (DACterm*) q->info();
   fprintf( DA__scratchFile, "Weight: %d   Value: %e  || ",
           p -> weight, p -> value );
   fprintf( DA__scratchFile, "Addresses: %d %d %d : %d\n",
                  q->prevPtr(), q, q->nextPtr(), p );
   fprintf( DA__scratchFile, "Index:  ");
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
     fprintf( DA__scratchFile, "%d  ", (p -> index)[i] );
   fprintf( DA__scratchFile, "\n\n");
   }
 
 fclose( DA__scratchFile );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

dlist DAC::image() {       // ??? Problem: nothing is recorded about the
                           // ??? reference point.

 dlist_iterator getNext( *(dlist*) this );
 DACterm* q;
 dlist ret;

 // ??? for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) fprintf( DAC__scratchFile, "%e  ", refPoint[i] );

 while( q = (DACterm*) getNext() )
   ret.append( new DACtermData( *q ) );

 return ret;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::writeToFile( FILE* filePtr ) {
 dlist_traversor getNext( *(dlist*) this );
 int i;
 DACterm* p;
 dlink* q;
 
 fprintf( filePtr,
          "\nCount  = %d, Weight = %d, Max accurate weight = %d\n",
          count, weight, accuWgt );
 fprintf( filePtr, "Reference point:  \n" );
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
   fprintf( filePtr, "%e  ", refPoint[i] );
 fprintf( filePtr, "\n" );
 while( q = getNext() ) {
   p = (DACterm*) q->info();
   fprintf( filePtr, "Weight: %d   Value: %e  || ",
           p -> weight, p -> value );
   fprintf( filePtr, "Addresses: %d %d %d : %d\n",
                  q->prevPtr(), q, q->nextPtr(), p );
   fprintf( filePtr, "Index:  ");
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
     fprintf( filePtr, "%d  ", (p -> index)[i] );
   fprintf( filePtr, "\n\n");
   }
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::scaleBy( complex y ) {
 DACterm* p;
 dlist_iterator getNext( *(dlist*) this );
 
 if ( this->count < 1 ) {
   printf( "\n\n*** WARNING::DAC::scaleBy: function invoked " );
   printf(          "by null DAC variable with address %d.\n",   this );
   return;
   }
 
 while( p = (DACterm*) getNext() )   p->value *= y;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::setVariable( complex x, int j ) {
 int* ndx;
 int i;
 
 clear();
 if( ( j < 0 ) || ( j >= DAC__1stEnv.DAC__NumVar ) ) return;
 
 ndx = new int[ DAC__1stEnv.DAC__NumVar ];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) ndx[i] = 0;
 ndx[j] = 1;
 insert( new DACterm( ndx, 1.0 ) );
 delete [] ndx;
 
 ndx = new int[ DAC__1stEnv.DAC__NumVar ];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) ndx[i] = 0;
 insert( new DACterm( ndx, x ) );
 delete [] ndx;
 
 DAC__1stEnv.DAC__refPoint[j] = x;
 refPoint[j] = x;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::setVariable( int j ) {
 int* ndx;
 int i;
 complex x;
 
 clear();
 if( ( j < 0 ) || ( j >= DAC__1stEnv.DAC__NumVar ) ) return;
 
 x = DAC__1stEnv.DAC__refPoint[j];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = DAC__1stEnv.DAC__refPoint[i];
 
 ndx = new int[ DAC__1stEnv.DAC__NumVar ];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) ndx[i] = 0;
 ndx[j] = 1;
 insert( new DACterm( ndx, 1.0 ) );
 
 ndx = new int[ DAC__1stEnv.DAC__NumVar ];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) ndx[i] = 0;
 insert( new DACterm( ndx, x ) );
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::insert( DACterm* a) {
 dlist::insert(a);
 count++;
 if( weight < (a->weight) ) weight = a->weight;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DACterm* DAC::get() {
 DACterm* p;
 if( count <= 0 ) return 0;
 p = ((DACterm*) dlist::get());
 if( --count == 0 ) weight = -1;
 return p;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::append( DACterm* a) {
 dlist::append(a);
 count++;
 if( weight < (a->weight) ) weight = a->weight;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DACterm* DAC::remove( dlink* w ) {
 DACterm* a;
 dlink* predecessor;
 dlink* successor;
 int predWeight;
 int succWeight;
 
 predecessor = w->prevPtr();
 successor   = w->nextPtr();
 
 a = (DACterm*) dlist::remove( w );
 count--;
 
 if( count == 0 ) {
   weight = -1;
   return a;
   }
 
 if ( weight > a->weight ) return a;
 
 predWeight = ( (DACterm*) ( predecessor->info() ) ) -> weight;
 succWeight = ( (DACterm*) ( successor->info() ) ) -> weight;
 weight = predWeight;
 if( succWeight > weight ) weight = succWeight;
 return a;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

complex DAC::standardPart() {
 return weightedDerivative( DAC__1stEnv.DAC__AllZeroes );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC::clear() {
 DACterm* p;
 while( p = get() )  
   delete p;
 dlist::clear();
 count   = 0;
 weight  = -1;
 accuWgt = DAC__1stEnv.DAC__MaxWeight;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

complex DAC::weightedDerivative( int* ind ) {
 int i, w;
 DAC z;
 DACterm* p;
 char theOne;
 
 w = 0;
 for ( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) w += ind[i];
 z = filter( w, w );
 if ( z.count < 1 ) return 0.0;
 
 // --- Old code ------
 // dlist_iterator getNext( (dlist) z );
 // --- New code ------    Oct 2, 1992
 dlist_iterator getNext( (dlist&) z );
 // -------------------
 while( p = (DACterm*) getNext() ) {
   theOne = 1;
   for ( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
     theOne = theOne && ( (p->index)[i] == ind[i] );
   if( theOne ) return p->value;
   }
 
 return 0.0;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

complex DAC::derivative( int* ind ) {
 double n;
 complex multiplier;
 complex d;
 int i;
 
 d = weightedDerivative( ind );
 if ( d == 0.0 ) return 0.0;
 
 multiplier = 1.0;
 for ( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   n = ind[i];
   while(n)  multiplier *= n--;
   }
 
 return multiplier*d;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& DAC::filter( int wgtLo, int wgtHi ) { 
 DAC* z = new DAC;
 dlist_iterator getNext( *(dlist*) this );
 DACterm* p;
 DACterm* q;
 int numTerms;
 int wgt, upperWgt;
 
 if( ( wgtLo <= 0 ) && ( wgtHi > DAC__1stEnv.DAC__MaxWeight ) )
   return *this;
 
 numTerms = 0;
 upperWgt = 0;
 
 while( p = (DACterm*) getNext() ) {
   wgt = p->weight;
   if( ( wgt >= wgtLo ) && ( wgt <= wgtHi ) ) {
     q = new DACterm( p );
     z->append( q );
     if( wgt > upperWgt ) upperWgt = wgt;
     numTerms++;
     }
   }
 
 z->count = numTerms;
 z->weight = upperWgt;
 z->accuWgt = accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& DAC::filter( char (*f) ( int*, complex ) ) { 
 DAC* z = new DAC;
 dlist_iterator getNext( *(dlist*) this );
 DACterm* p;
 DACterm* q;

 int i;
 int nv = DAC__1stEnv.DAC__NumVar;
 int* oldIndex = new int[ nv ];

 while( p = (DACterm*) getNext() ) {
  for( i = 0; i < nv; i++ ) oldIndex[i] = p->index[i];

  if( (*f)( p->index, p->value ) ) {
   q = new DACterm( p );
   z->append( q );
  }

  for( i = 0; i < nv; i++ ) 
   if( oldIndex[i] != p->index[i] ) {
    printf( "\n" );
    printf( "*** ERROR ***                                      \n" );
    printf( "*** ERROR *** DA& DA::filter( char (*f) ( int*, double ) \n" );
    printf( "*** ERROR *** The test routine is not allowed      \n" );
    printf( "*** ERROR *** to change the values in the index    \n" );
    printf( "*** ERROR *** array!!                              \n" );
    printf( "*** ERROR ***                                      \n" );
    exit(0);
   }
 }

 delete [] oldIndex;
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& DAC::operator()( DAC* y ) { 
 DAC* z = new DAC;
 DAC* u;
 DAC term;
 int i;
 int j;
 int w;
 DACterm* p;
 
 u = new DAC [ DAC__1stEnv.DAC__NumVar ];
 
 // Check consistency of reference points.
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   for( j = 0; j < DAC__1stEnv.DAC__NumVar; j++ )
     if( y[i].refPoint[j] != y[0].refPoint[j] ){
       printf( "\n*** DAC DAC::operator() ERROR: Inconsistent reference points.\n" );
       printf("y[%d].refPoint[%d] != y[0].refPoint[%d]\n", i, j, j);
       printf("%lf != %lf\n", y[i].refPoint[j], y[0].refPoint[j]);
       exit(1);
     }
   if( this -> refPoint[i] != y[i].weightedDerivative( DAC__1stEnv.DAC__AllZeroes ) ) {
     printf( "\n*** DAC DAC::operator() ERROR: Inconsistent reference points.\n" );
     printf("this -> refPoint[%d] != y[%d].weightedDerivative( DAC__1stEnv.DAC__AllZeroes )\n",
             i, i);
     printf("%lf != %lf\n",
             this -> refPoint[i], y[i].weightedDerivative( DAC__1stEnv.DAC__AllZeroes ));
     exit(1);
   }
 }
 
 // Subtract reference point prior to concatenation.
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   u[i] = y[i];
   p    = ( u[i] ).get();
   if( p->weight != 0 ) {
     printf( "\n*** DAC DAC::operator() ERROR: Argument has no nonstandard part!!\n" );
     exit(0);
   }
 }
 
 // Evaluate and store monomials.
 
 // The zeroth one.
 DAC__1stEnv.DAC__DAmonomial[0] = complex_one;
 DAC__1stEnv.DAC__DAmonomial[0].fixReference( y[0] );
 
 // For all higher weights ...
 for( w = 1; w <= ( this->weight ); w++ )
 
   // Get the next set of exponents of weight w.
   while( nexcom( w, DAC__1stEnv.DAC__NumVar, DAC__1stEnv.DAC__exponent ) ) {
 
     // Find the first non-zero exponent.
     i = 0;
     while( !( DAC__1stEnv.DAC__exponent[i++] ) ) ;
     i--;
 
     // The value of the monomial associated with this composition
     // is obtained by multiplying a factor into a previously
     // computed monomial.
     ( DAC__1stEnv.DAC__exponent[i] )--;
     DAC__monoCode();
     term = DAC__1stEnv.DAC__DAmonomial[ DAC__monoRank() ];
     ( DAC__1stEnv.DAC__exponent[i] )++;
     DAC__monoCode();
     DAC__1stEnv.DAC__DAmonomial[ DAC__monoRank() ] = term * u[i];   // ??? Is this OK???
 
     } // End while loop.
 
 // Monomials have been stored.
 // Now traverse the DAC variable and evaluate.
 
 *z = concat( *this );
 
 // Set the correct reference point in z.
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = y[0].refPoint[i];
 
 delete [] u;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& DAC::operator()( CLieOperator& y ) { 
 DAC* z = new DAC;
 CLieOperator u;
 DAC term;
 int i;
 int w;
 dlist_iterator getNext( *(dlist*) this );
 DACterm* p;
 
 u = y;
 u.reset();

 // Check consistency of reference points.
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
   if( this -> refPoint[i] != ( y.v[i] ).weightedDerivative( DAC__1stEnv.DAC__AllZeroes ) ) {
     printf( "\n*** DAC DAC::operator() ERROR: Inconsistent reference points.\n" );
     exit(0);
     }
 
 // In the event that the argument y is null
 if( u.weight <= 0 ) {
  if( ( p = (DACterm*) getNext() ) == 0 ) {
   DA__garbage.store( z );
   return *z;
  }
  if( p->weight == 0 ) *z = complex_zero;
  else                 *z = p->value;
  DA__garbage.store( z );
  return *z;
 }

 // Subtract reference point prior to concatenation.
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
  p = ( u.v[i] ).get();
  if( p->weight != 0 ) {
   printf( "\n*** DAC DAC::operator() ERROR: Argument has no nonstandard part!!\n" );
   exit(0);
  }
 }
 
 // Evaluate and store monomials.
 
 // The zeroth one.
 DAC__1stEnv.DAC__DAmonomial[0] = complex_one;
 DAC__1stEnv.DAC__DAmonomial[0].fixReferenceAtStart( y );
 
 // For all higher weights ...
 for( w = 1; w <= ( this->weight ); w++ )
 
   // Get the next set of exponents of weight w.
   while( nexcom( w, DAC__1stEnv.DAC__NumVar, DAC__1stEnv.DAC__exponent ) ) {
 
     // Find the first non-zero exponent.
     i = 0;
     while( !( DAC__1stEnv.DAC__exponent[i++] ) ) ;
     i--;
 
     // The value of the monomial associated with this composition
     // is obtained by multiplying a factor into a previously
     // computed monomial.
     ( DAC__1stEnv.DAC__exponent[i] )--;
     DAC__monoCode();
     term = DAC__1stEnv.DAC__DAmonomial[ DAC__monoRank() ];
     ( DAC__1stEnv.DAC__exponent[i] )++;
     DAC__monoCode();
     DAC__1stEnv.DAC__DAmonomial[ DAC__monoRank() ] = term * u.v[i];   // ??? Is this OK???
 
     } // End while loop.
 
 // Monomials have been stored.
 // Now traverse the DAC variable and evaluate.
 
 *z = concat( *this );
 
 // Set the correct reference point in z.
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = y.refPoint[i];
 
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

complex DAC::operator()( complex* x ) {
 DACterm* p;
 complex v;
 int w;
 int i;
 complex term;
 complex* u;
 dlist_iterator getNext( *(dlist*) this );
 
 u = new complex[ DAC__1stEnv.DAC__NumVar ];   // ??? Check other places in the source
                                 // code where this was not done correctly!!
 
 // Subtract off the reference point.
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) u[i] = x[i] - refPoint[i];
 
 // Evaluate and store monomials.
 
 // The zeroth one.
 DAC__1stEnv.DAC__monomial[0] = complex_one;
 
 // For all higher weights ...
 for( w = 1; w <= weight; w++ )
 
   // Get the next set of exponents of weight w.
   while( nexcom( w, DAC__1stEnv.DAC__NumVar, DAC__1stEnv.DAC__exponent ) ) {
 
     // Find the first non-zero exponent.
     i = 0;
     while( !( DAC__1stEnv.DAC__exponent[i++] ) ) ;
     i--;
 
     // The value of the monomial associated with this composition
     // is obtained by multiplying a factor into a previously
     // computed monomial.
     ( DAC__1stEnv.DAC__exponent[i] )--;
     DAC__monoCode();
     term = DAC__1stEnv.DAC__monomial[ DAC__monoRank() ];
     ( DAC__1stEnv.DAC__exponent[i] )++;
     DAC__monoCode();
     DAC__1stEnv.DAC__monomial[ DAC__monoRank() ] = term * u[i];
 
     } // End while loop.
 
 // Monomials have been now stored at this point.
 // Now traverse the DAC variable and evaluate.
 
 v = 0.0;
 
 while( p = (DACterm*) getNext() ) {
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) DAC__1stEnv.DAC__exponent[i] = (p->index)[i];
   DAC__monoCode();
   v += ( p->value ) * ( DAC__1stEnv.DAC__monomial[ DAC__monoRank() ] );
   }
 
 delete [] u;
 
 return v;
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& DAC::D( int* n ) { 
 char noTermAdded;
 int f, i, j, k, w;
 DAC* z = new DAC;
 dlist_iterator getNext( *(dlist*) this );
 DACterm* p;
 DACterm* q;
 
 noTermAdded = 1;
 
 // --- Preliminary check of index set.
 
 w = 0;
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   if( n[i] < 0 ) {
     printf( "\n*** DAC ERROR: Cannot differentiate with negative index." );
     printf( "\n*******************************************************\n" );
     exit(0);
     }
   w += n[i];
   }
 
 if( w > accuWgt ) {
   printf( "\n*** DAC ERROR: Differentiation request beyond accuracy allowed." );
   printf( "\n**************************************************************\n" );
   exit(0);
   }
 
 if( w == 0 ) return *this;      // ??? Will this work, or should I set z = *this
                                 // and then return z ???
 
 // --- Construct the derivative one link at a time.
 // --- ( See note Obs.4 )
 
 while( p = (DACterm*) getNext() ) {
 
   q = new DACterm( p );
 
   char doit = 1;
   // -- Reset the index.
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) doit = doit && ( ( q->index[i] -= n[i] ) >= 0 );
 
   if( doit ) {
     // -- Build factorial multiplier.
     f = 1;
     for( k = 0; k < DAC__1stEnv.DAC__NumVar; k++ ) {
       j = q->index[k];
       for( i = 0; i < n[k]; i++ ) f *= ++j;
       }
     if( f <= 0 ) {
       printf( "\n*** DAC ERROR: Horrible, unexplainable error while differentiating!" );
       printf( "\n******************************************************************\n" );
       exit(0);
       }                           // Super fussbudget!! ( f "must" be positive )
   
     // -- Make final changes in private data of the DACterm and
     //    absorb it into the answer.
     (q->value) *= f;              // OK. So I'm a fussbudget with parentheses again ..
     (q->weight ) -= w;
   
     noTermAdded = 0;
     z->addTerm( q );               // ??? This also may be unnecessarily conservative.
                                    // The append function may be adequate, if the
                                    // ordering is preserved. ???
   
     } 
   }
 
 if( noTermAdded ) *z = complex_zero;
 
 
 // --- Finally, adjust accuWgt and return value
 
 z->accuWgt = accuWgt - w;       // ??? Is this correct ???

 DA__garbage.store( z );
 return *z;
}
 

//***************************************************************
//***************************************************************
//***************************************************************
//
//      The overloaded operators for class DAC
//
ostream& operator<<(ostream& os, DAC& x) {
 dlist_traversor getNext( (dlist&) x );
 int i;
 DACterm* p;
 dlink* q;

 os << "\n Count = " << x.count << ", Weight = " << x.weight;
 os << ", Max accurate weight = " << x.accuWgt << endl;
 os << "Reference point: ";
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) 
   os << x.refPoint[i];
 os << "\n\n";

 while( q = getNext() ) {
   p = (DACterm*) q->info();
   os << "Index: ";
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ )
     os << p -> index[i];
  os << "   Value: " << p -> value << endl;
 }
 return os << "\n" << endl;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator==( DAC& x, DAC& y ) {
 dlist_iterator getNextX( (dlist&) x );
 dlist_iterator getNextY( (dlist&) y );
 DACterm* p;
 DACterm* q;
 int i;
 
 if( ( x.count   != y.count )   ||
     ( x.weight  != y.weight )  ||
     ( x.accuWgt != y.accuWgt )
   ) return 0;
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
   if( x.refPoint[i] != y.refPoint[i] ) return 0;
 
 while( p = (DACterm*) getNextX() ) {
   if( !( q = (DACterm*) getNextY() ) ) return 0;
   if( !( *p == *q ) ) return 0;
   }
 
 if( (DACterm*) getNextY() ) {
   printf( "\n*** ERROR: Inconsistency in DAC operator==\n" );
     // This point should never be reached, since that would imply that
     // x.count != y.count
   return 0;
   }
 
 return 1;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator==( DAC& x, complex& y ) {
 char result = 1;
 dlist_iterator getNext( (dlist&) x );
 DACterm* p;

 if( x.count < 1 ) {
  if( y == complex_zero ) return 1;
  else                    return 0;
 }

 while( p = (DACterm*) getNext() ) 
  result = result && ( p->weight == 0 ? p->value == y : 
                                        p->value == complex_zero );

  // REMOVE ??? result = result && ( ( ( p->weight == 0 ) && ( p->value == y   ) )
  // REMOVE ???                      ||
  // REMOVE ???                      ( ( p->weight != 0 ) && ( p->value == complex_zero ) )
  // REMOVE ???                    )
  // REMOVE ??? 
 return result;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator==( complex& y, DAC& x ){
 return x == y;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator!=( DAC& x, DAC& y ) {
 return !( x == y );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator!=( DAC& x, complex& y ) {
 return !( x == y );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator!=( complex& x, DAC& y ) {
 return !( x == y );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& DAC::operator=( const DAC& x ) {
 dlist_iterator getNext( (dlist&) x );
 DACterm* p;
 DACterm* q;
 int i;
 
 if( this == &x ) return *this;
 
 clear();
 while( p = (DACterm*) getNext() ) {
   q = new DACterm( p );
   append( q );
   }
 count   = x.count;
 weight  = x.weight;
 accuWgt = x.accuWgt;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = x.refPoint[i];
 return *this;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& DAC::operator+=( complex& x ) {  // ??? Untested!!
 int i;
 dlist_iterator getNext( *(dlist*) this );
 DACterm* p;
 DACterm* q;
 p = (DACterm*) getNext();

 if ( p->weight == 0 ) {
  p->value += x;
  if(  abs( p->value ) <  MX_SMALL* abs(x) ) p->value = 0.0;
 }                   // ??? This is not the correct way to do this.

 else {
   q = new DACterm;
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) q->index[i] = 0;
   q->weight = 0;
   q->value = x;
   insert( q );
 }

 return *this;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator+( DAC& x, DAC& y ) {  // ??? This should be modified so that
 DAC* z = new DAC;                       // terms beyond the accurate weight of
 DACterm* p;                            // x or y are not computed and carried
 DACterm* q;                            // into the answer.
 dlist_iterator gx( (dlist&) x );
 dlist_iterator gy( (dlist&) y );
 int i;
 
 // Check for consistency and set reference point of the sum.
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   if( x.refPoint[i] != y.refPoint[i] ) {
     printf( "\n*** DAC ADDITION ERROR: Inconsistent reference points.\n" );
     exit(0);
     }
   z->refPoint[i] = x.refPoint[i];
   }
 
 // If one of the arguments is void, then return the other ..
 if( x.count < 1 ) return y;
 if( y.count < 1 ) return x;
 
 // .. otherwise, continue normal operations.
 if( x.count > y.count ) {
   *z = x;
   while( p = (DACterm*) gy() ) {
     q = new DACterm( p );
     z->addTerm( q );
     }
   }
 
 else {
   *z = y;
   while( p = (DACterm*) gx() ) {
     q = new DACterm( p );
     z->addTerm( q );
     }
   }
 
 // Determine the maximum weight computed accurately.
 if( x.accuWgt < y.accuWgt ) z->accuWgt = x.accuWgt;
 else                        z->accuWgt = y.accuWgt;
 
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator+( DAC& x, complex& y ) {
 DAC* z = new DAC;
 
 *z = x;
 *z += y;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator+( complex& y, DAC& x ) {
 DAC* z = new DAC;
 
 *z = x;
 *z += y;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator-( DAC& y ) {  
 DAC* z = new DAC;
 dlist_iterator getNext( (dlist&) y );
 DACterm* p;
 DACterm* q;
 int i;
 
 // If the argument is void, then return it ..
 if( y.count < 1 ) return y;
 
 // .. otherwise continue normal operations.
 z->clear();
 
 // Insert the first one
 p = (DACterm*) getNext();
 q = new DACterm;
 *q = *p;
 q->value = - ( p->value );
 z->insert( q );
 
 // and append the rest
 while( p = (DACterm*) getNext() ){
   q = new DACterm;
   *q = *p;
   q->value = - ( p->value );
   z->append( q );
   }
 
 z->weight  = y.weight;
 z->accuWgt = y.accuWgt;
 z->count   = y.count;
 
 // Set the reference point.
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = y.refPoint[i];
 
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator-( DAC& x, DAC& y ) {  
 DAC* z = new DAC;
 DACterm* p;
 DACterm* q;
 dlist_iterator gx( (dlist&) x );
 dlist_iterator gy( (dlist&) y );
 int i;
 
 // Check for consistency and set reference point of the difference.
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   if( x.refPoint[i] != y.refPoint[i] ) {
     printf( "\n*** DAC SUBTRACTION ERROR: Inconsistent reference points.\n" );
     exit(0);
     }
   z->refPoint[i] = x.refPoint[i];
   }
 
 // If one of the arguments is void, then return the other ..
 if( x.count < 1 ) return -y;
 if( y.count < 1 ) return x;
 
 // .. otherwise, continue normal operations.
 if( x.count > y.count ) {
   *z = x;
   while( p = (DACterm*) gy() ) {
     q = new DACterm( p );
     ( q->value ) = - ( q->value );
     z->addTerm( q );
     }
   }
 
 else {
   *z = - y;
   while( p = (DACterm*) gx() ) {
     q = new DACterm( p );
     z->addTerm( q );
     }
   }
 
 // Determine the maximum weight computed accurately.
 if( x.accuWgt < y.accuWgt ) z->accuWgt = x.accuWgt;
 else                        z->accuWgt = y.accuWgt;
 
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator*( DAC& x, DAC& y ) {        // ??? This should be modified so that
 DAC* z = new DAC;                       // terms beyond the accurate weight of
 DACterm* p;                            // x or y are not computed and carried
 DACterm* q;                            // into the answer.
 DACterm* r;
 dlist_looper gx( (dlist&) x );
 dlist_looper gy( (dlist&) y );
 int i;
 
 // Check for consistency and set reference point of the product.
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   if( x.refPoint[i] != y.refPoint[i] ) {
     printf( "\n*** DAC MULTIPLICATION ERROR: Inconsistent reference points.\n" );
     exit(0);
     }
   z->refPoint[i] = x.refPoint[i];
   }
 
 // If one of the arguments is void, return it ..
 if ( x.count < 1 ) return x;
 if ( y.count < 1 ) return y;
 
 // .. otherwise continue normal operations.
 while( p = (DACterm*) gy() ) {
 while( q = (DACterm*) gx() ) {
 
   if( ( p->weight + q->weight ) > DAC__1stEnv.DAC__MaxWeight ) continue;
 
   r = new DACterm;
   *r = (*p)*(*q);
   z->addTerm( r );
   }}
 
 // Determine the maximum weight computed accurately.
 if( x.accuWgt < y.accuWgt ) z->accuWgt = x.accuWgt;
 else                        z->accuWgt = y.accuWgt;
 
 DA__garbage.store(z); 
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator*( DAC& x, const complex y ) {  
 DAC* z = new DAC;
 DACterm* p;
 DACterm* q;
 dlist_iterator gx( (dlist&) x );
 int i;
 
 if ( x.count < 1 ) return x;
 
 if( y == complex_zero ) {
   *z = complex_zero;
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
   DA__garbage.store(z); 
   return *z;
   }
 
 while( p = (DACterm*) gx() ) {
   q = new DACterm( p );
   q->value *= y;
   z->addTerm( q );
   }
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 
 z->accuWgt = x.accuWgt;
 
 DA__garbage.store(z); 
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator*( DAC& x, const int j ) { 
 DAC* z = new DAC;
 DACterm* p;
 DACterm* q;
 dlist_iterator gx( (dlist&) x );
 int i;
 double y;
 
 if ( x.count < 1 ) return x;
 
 if( ( y = (double) j ) == 0.0 ) {
   *z = complex_zero;
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
   DA__garbage.store( z );
   return *z;
   }
 
 while( p = (DACterm*) gx() ) {
   q = new DACterm( p );
   q->value *= y;
   z->addTerm( q );
   }
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 
 z->accuWgt = x.accuWgt;
 DA__garbage.store( z );
 return *z;
}


// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator*( const double y, DAC& x ) {  
 DAC* z = new DAC;
 DACterm* p;
 DACterm* q;
 dlist_iterator gx( (dlist&) x );
 int i;
 
 if ( x.count < 1 ) return x;
 
 if( y == 0.0 ) {
   *z = complex_zero;
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
   DA__garbage.store(z); 
   return *z;
   }
 
 while( p = (DACterm*) gx() ) {
   q = new DACterm( p );
   q->value *= y;
   z->addTerm( q );
   }
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 
 z->accuWgt = x.accuWgt;
 
 DA__garbage.store(z); 
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator*( const complex y, DAC& x ) {  
 DAC* z = new DAC;
 DACterm* p;
 DACterm* q;
 dlist_iterator gx( (dlist&) x );
 int i;
 
 if ( x.count < 1 ) return x;
 
 if( y == complex_zero ) {
   *z = complex_zero;
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
   DA__garbage.store(z); 
   return *z;
   }
 
 while( p = (DACterm*) gx() ) {
   q = new DACterm( p );
   q->value *= y;
   z->addTerm( q );
   }
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 
 z->accuWgt = x.accuWgt;
 
 DA__garbage.store(z); 
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator*( const complex y, const DA& x ) {  
 DAC* z = new DAC;
 DAterm* p;
 DACterm* q;
 dlist_iterator gx( (dlist&) x );
 int i;

// What to do about this????? 
// if ( x.count < 1 ) return x;
 
 if( y == complex_zero ) {
   *z = complex_zero;
   for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = 
     complex(x.refPoint[i],0.0);
   DA__garbage.store(z); 
   return *z;
   }
 
 while( p = (DAterm*) gx() ) {
   q = new DACterm( p );
   q->value *= y;
   z->addTerm( q );
   }
 
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = 
   complex(x.refPoint[i],0.0);
 
 z->accuWgt = x.accuWgt;
 
 DA__garbage.store(z); 
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator*( const int j, DAC& x ) { 
 DAC* z = new DAC;
 DACterm* p;
 DACterm* q;
 dlist_iterator gx( (dlist&) x );
 int i;
 double y;
 
 if ( x.count < 1 ) return x;
 
 if( ( y = (double) j ) == 0.0 ) {
   *z = complex_zero;
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
   DA__garbage.store( z );
   return *z;
   }
 
 while( p = (DACterm*) gx() ) {
   q = new DACterm( p );
   q->value *= y;
   z->addTerm( q );
   }
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 
 z->accuWgt = x.accuWgt;
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator|( DAC& u, DAC& v ) { 
 /*
 Truncated multiplication: used only by the division operator.
 No checks are made on the reference point.
 */
 DAC* z = new DAC;
 DACterm* p;
 DACterm* q;
 DACterm* r;
 dlist_looper gu( (dlist&) u );
 dlist_looper gv( (dlist&) v );
 
 // If one of the arguments is void, return it ..
 if ( u.count < 1 ) return u;
 if ( v.count < 1 ) return v;
 
 // .. otherwise continue normal operations.
 while( p = (DACterm*) gv() ) {
 while( q = (DACterm*) gu() ) {
 
   if( ( p->weight + q->weight ) > DAC__1stEnv.DAC__weightLimit ) continue;
 
   r = new DACterm;
   *r = (*p)*(*q);
   z->addTerm( r );
 
   }}
 
 // Determine the maximum weight computed accurately.
 if( u.accuWgt < v.accuWgt ) z->accuWgt = u.accuWgt;
 else                        z->accuWgt = v.accuWgt;
 
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator/( DAC& x, const double& y ) { 
 DAC* z = new DAC;
 DACterm* p;
 DACterm* q;
 dlist_iterator gx( (dlist&) x );
 int i;
 
 // Check for void operators ..
 if ( x.count < 1 ) return x;
 
 // Check for division by zero ..
 if( y == 0.0 ) {
   printf("\n*** DAC ERROR *** ");
   printf("Attempt to divide by a scalar zero.\n");
   exit(0);
   }
 
 // .. and continue.
 while( p = (DACterm*) gx() ) {
   q = new DACterm( p );
   q->value /= y;
   z->addTerm( q );
   }
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 
 z->accuWgt = x.accuWgt;
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator/( DAC& x, const complex& y ) { 
 DAC* z = new DAC;
 DACterm* p;
 DACterm* q;
 dlist_iterator gx( (dlist&) x );
 int i;
 
 // Check for void operators ..
 if ( x.count < 1 ) return x;
 
 // Check for division by zero ..
 if( y == complex_zero ) {
   printf("\n*** DAC ERROR *** ");
   printf("Attempt to divide by a scalar zero.\n");
   exit(0);
   }
 
 // .. and continue.
 while( p = (DACterm*) gx() ) {
   q = new DACterm( p );
   q->value /= y;
   z->addTerm( q );
   }
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 
 z->accuWgt = x.accuWgt;
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator/( DAC& x, const int& j ) { 
 DAC* z = new DAC;
 DACterm* p;
 DACterm* q;
 dlist_iterator gx( (dlist&) x );
 int i;
 double y;
 
 // Check for void operators ..
 if ( x.count < 1 ) return x;
 
 // Check for division by zero ..
 if( ( y = (double) j ) == 0.0 ) {
   printf("\n*** DAC ERROR *** ");
   printf("Attempt to divide by a scalar zero.\n");
   exit(0);
   }
 
 // .. and continue.
 while( p = (DACterm*) gx() ) {
   q = new DACterm( p );
   q->value /= y;
   z->addTerm( q );
   }
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 
 z->accuWgt = x.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator/( DAC& wArg, DAC& uArg ) { 
 dlist_looper gu( (dlist&) uArg );
 dlist_looper gw( (dlist&) wArg );
 DAC* vptr;
 DAC* v = new DAC;
 DAC vn;
 DAC w, u;
 DACterm* qu;
 DACterm* qw;
 complex u0, w0;
 int wgt;
 int i;
 
 // Check for void operators ..
 if ( wArg.count < 1 ) return wArg;
 if ( uArg.count < 1 ) {
   printf("\n*** DAC ERROR *** ");
   printf("Attempt to divide by a void DAC variable.\n");
   exit(0);
   }
 
 // Check for consistency and set reference point of the quotient.
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   if( wArg.refPoint[i] != uArg.refPoint[i] ) {
     printf( "\n*** DAC DIVISION ERROR: Inconsistent reference points.\n" );
     exit(0);
     }
   v->refPoint[i] = wArg.refPoint[i];
   }
 
 // Normalize the denominator
 if( ( qu = (DACterm*) gu() ) == 0 ) {
   printf( "\n*** DAC ERROR ***  Division algorithm called with uninitialized DAC.\n" );
   exit(0);
   }
 if( ( wgt = qu->weight ) != 0 ) {
   printf( "\n*** DAC ERROR ***  Attempt to divide by nilpotent element.\n" );
   exit(0);
   }
 if( ( u0 = qu->value ) == complex_zero ) {
   printf( "\n*** DAC ERROR ***  Attempt to divide by zero.\n" );
   exit(0);
   }
 u = uArg / u0;
 
 // Recursive algorithm
 qw = (DACterm*) gw();
 w0 = ( qw->value );
 // --- Old code ------
 // *v = (DAC) w0;
 // --- New code ------    This is done to control growth
 vptr = new DAC( w0 );   // It seems and probably is horribly
 *v = *vptr;            // inefficient.
 delete vptr;
 // -------------------
 
 DAC__1stEnv.DAC__weightLimit = 0;
 while ( DAC__1stEnv.DAC__weightLimit < DAC__1stEnv.DAC__MaxWeight ) {
   DAC__1stEnv.DAC__weightLimit++;
   vn = u|*v;
   vn = vn.filter( DAC__1stEnv.DAC__weightLimit, DAC__1stEnv.DAC__weightLimit );
   w = wArg.filter( DAC__1stEnv.DAC__weightLimit, DAC__1stEnv.DAC__weightLimit );
   *v = *v + ( w - vn );
   }
 
 // Correct normalization of the answer ..
 *v = *v / u0;
 
 // .. set the reference point ..
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) v->refPoint[i] = wArg.refPoint[i];
 
 // Determine the maximum weight computed accurately.
 if( wArg.accuWgt < uArg.accuWgt ) v->accuWgt = wArg.accuWgt;
 else                              v->accuWgt = uArg.accuWgt;
 
 // .. and return value.
 DA__garbage.store( v );
 return *v;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& operator^( DAC& x, DAC& y ) { 
 DAC* z = new DAC;
 int i;
 int* m = new int [ DAC__1stEnv.DAC__NumVar ];
 int* n = new int [ DAC__1stEnv.DAC__NumVar ];
 
 if( DAC__1stEnv.DAC__PBOK ) {
 
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
     m[i] = 0;
     n[i] = 0;
     }
 
   for( i = 0; i < DAC__1stEnv.DAC__dof; i++ ) {
     m[ i ] = 1;
     n[ i + DAC__1stEnv.DAC__dof ] = 1;
 
     *z = *z + ( ( x.D(m) * y.D(n) ) - ( x.D(n) * y.D(m) ) );
 
     m[ i ] = 0;
     n[ i + DAC__1stEnv.DAC__dof ] = 0;
     }
 
   delete [] m;
   delete [] n;
   DA__garbage.store( z );
   return *z;
   }
 
 printf( "\n*** ERROR ***                                \n" );
 printf(   "*** ERROR *** DAC operator^( DAC&, DAC& )    \n" );
 printf(   "*** ERROR *** Wrong DACSetup used; cannot    \n" );
 printf(   "*** ERROR *** perform bracket.               \n" );
 printf(   "*** ERROR ***                                \n" );
 
 if( 2 + 3 == 5 ) exit(1);       // Done to avoid compiler warnings
 delete [] m;                    // about leaving the function.
 delete [] n;
 return x;                       
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void operator+=( DAC& x, DAC& y ) {
 x = x + y;  // ??? Come up with a more efficient implementation SOON.
}

void operator-=( DAC& x, DAC& y ) {
 x = x - y;
}

void operator*=( DAC& x, DAC& y ) {
 x = x * y;
}

void operator/=( DAC& x, DAC& y ) {
 x = x / y;
}


//***************************************************************
//***************************************************************
//***************************************************************
//
//      Implementation of Class DACterm

DACterm::DACterm() {
 weight = 0;
 index = new int[ DAC__1stEnv.DAC__NumVar ];
 value = complex_zero;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DACterm::DACterm( int* l, complex x ) {
 int i, dpt;
 
 dpt = 0;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   if( (l[i] < 0) ) {
     printf( "\n*** DAC ERROR *** Bad index in DACTerm.\n" );
     exit(0);
     }
   dpt += l[i];
   }
 if( dpt > DAC__1stEnv.DAC__MaxWeight ) {
   printf("\n*** DAC ERROR *** Attempt to load a DACTerm with too large a weight.\n");
   exit(0);
   }
 
 index = new int[ DAC__1stEnv.DAC__NumVar ];
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) index[i] = l[i];
 weight = dpt;
 value = x;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DACterm::DACterm( DACterm* x ) {
 int i;
 
 weight = x->weight;
 value = x->value;
 index = new int[ DAC__1stEnv.DAC__NumVar ];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) index[i] = (x->index)[i];
}
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DACterm::DACterm( DAterm* x ) {
 int i;
 
 weight = x->weight;
 value = complex(x->value,0.0);
 index = new int[ DAC__1stEnv.DAC__NumVar ];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) index[i] = (x->index)[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DACterm::DACterm( DACterm& x ) {
 int i;
 
 weight = x.weight;
 value = x.value;
 index = new int[ DAC__1stEnv.DAC__NumVar ];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) index[i] = (x.index)[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DACterm::DACterm( DACtermData& x ) {
 int i;
 
 weight = x.weight;
 value = x.value;
 index = new int[ DAC__1stEnv.DAC__NumVar ];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) index[i] = (x.index)[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DACterm::~DACterm() {
 delete [] index;
}


//***************************************************************
//***************************************************************
//***************************************************************
//
//      Implementation of struct DACtermData

DACtermData::DACtermData() {
 printf( "\n" );
 printf( "*** ERROR ***                                   \n" );
 printf( "*** ERROR *** DACtermData::DACtermData()        \n" );
 printf( "*** ERROR *** Cannot declare a DACtermData      \n" );
 printf( "*** ERROR *** in this way.                      \n" );
 printf( "*** ERROR ***                                   \n" );
 exit(0);
}

DACtermData::DACtermData( DACterm& x ) {
 numvar = DAC__1stEnv.DAC__NumVar;   // ??? This has got to be changed!!
 index = new int[ numvar ];
 for( int i = 0; i < numvar; i++ ) index[i] = x.index[i];
 weight = x.weight;
 value = x.value;
}

DACtermData::~DACtermData() {
 if( index != 0 ) delete [] index;
}



//***************************************************************
//***************************************************************
//***************************************************************
//
//      Overloaded operators for class DACterm

void DACterm::operator=( DACterm& x ) {
 int i;
 weight = x.weight;
 value = x.value;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) index[i] = (x.index)[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator==( DACterm& a, DACterm& b ) {
 int i;
 if( ( a.weight != b.weight) || ( a.value != b.value)  ) return 0;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
   if( ( a.index[i] != b.index[i]) ) return 0;
 return 1;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator!=( DACterm& a, DACterm& b ) {
 return !( a == b );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator<=( DACterm& a, DACterm& b ) {
 int i;
 if( a.weight != b.weight ) return ( a.weight < b.weight );
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   if( a.index[i] == b.index[i] ) continue;
   return ( a.index[i] < b.index[i] );
   }
 return 1;  // when all indices are the same.
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator%=( DACterm& a, DACterm& b ) {
 int i;
 if( a.weight != b.weight ) return 0;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
   if( ( a.index[i] != b.index[i]) ) return 0;
 return 1;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DACterm& operator*( DACterm& x, DACterm& y ) {  
 DACterm* z = new DACterm;
 int i;
 z->weight = x.weight + y.weight;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->index[i] = x.index[i] + y.index[i];
 z->value = x.value * y.value;
 DA__garbage.store( z );
 return *z;
}


//***************************************************************
//***************************************************************
//***************************************************************
//
//      Overloaded analytic functions

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& cos( DAC& x ) { 
 
 DAC& epsSin( DAC& );
 DAC& epsCos( DAC& );
 DAC epsilon;
 complex cs, sn;
 dlist_iterator getNext( (dlist&) x );
 DACterm* p;
 
 if( x.count == 0 ) {
   printf("\n*** WARNING ***  exp called with unevaluated DAC.\n");
   return x;
   }
 
 p = (DACterm*) getNext();
 if( ( p -> weight ) == 0 ) {         // x has non-zero standard part
   cs = cos( p -> value );
   sn = sin( p -> value );
   epsilon = x;                       // x must not be altered by the routine
   p = epsilon.get();                 // pops the standard part off epsilon
   return cs*epsCos( epsilon ) - sn*epsSin( epsilon );
   }
 else {                               // x is pure infinitesimal
   return epsCos( x );
   }
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& cosh( DAC& x ) { 
 DAC* z = new DAC;
 *z = exp(x);
 *z = ( *z + ( complex_one / *z ) ) / 2.0;
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& exp( DAC& x ) { 
 
 DAC& epsExp( DAC& );
 DAC epsilon;
 complex factor;
 dlist_iterator getNext( (dlist&) x );
 DACterm* p;
 
 if( x.count == 0 ) {
   printf("\n*** WARNING ***  exp called with unevaluated DAC.\n");
   return x;
   }
 
 p = (DACterm*) getNext();
 if( ( p -> weight ) == 0 ) {         // x has non-zero standard part
   factor = exp( p -> value );
   epsilon = x;                       // x must not be altered by the routine
   p = epsilon.get();                 // pops the standard part off epsilon
   return factor*epsExp( epsilon );
   }
 else {                               // x is pure infinitesimal
   return epsExp( x );
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& log ( DAC& x ) { 
 DAC*             dummy;
 DAC*             epsilon = new DAC;
 DAC              u, w;
 complex          std;
 double           n;
 DACterm*         p;
 dlist_iterator  getNext( (dlist&) x );
 
 
 if( x.count == 0 ) {
   printf("\n*** WARNING ***  log called with unevaluated DAC.\n");
   return x;
   }
 
 p = (DACterm*) getNext();
 if( ( ( p -> weight      ) ==  0   ) &&
     ( ( std = p -> value ) !=  0.0 )
   )                                  // x has non-zero standard part
   {
   *epsilon = x;                      // x must not be altered by the routine
   p = epsilon->get();                //   pops the standard part off epsilon
   epsilon->scaleBy( - 1.0/std );
   w = *epsilon;
   u = *epsilon;                     // We use here the formulae
   n = 1.0;                          // ln( s + e )   = ln s + ln( 1 + e/s ), and
   while( u.count > 0 ) {            // ln( 1 + e/s ) = ln( 1 - ( -e/s )) 
     u = u*(*epsilon);               //               = - sum ( - e/s )^n / n
     w = w + ( u / ++n );
     }
 
 // --- Old code ------
 //  return ( (DAC) ( log( std ) ) ) - w;
 // --- New code ------            This is done to control memory growth
   dummy = new DAC( log(std) );  // by avoiding a constructor.
   *epsilon = *dummy - w;       // WARNING: This is a dummy use of epsilon.
   delete dummy;
   DA__garbage.store( epsilon );
   return *epsilon;
 // -------------------
 
   }
 else                                 // x has zero standard part
   {
   printf( "\n\n*** ERROR *** \n"                                  );
   printf(     "*** ERROR *** DAC log called with argument whose\n" );
   printf(     "*** ERROR *** standard part vanishes.\n"           );
   printf(     "*** ERROR *** \n\n"                                );
   if( 1 + 1 == 2 ) exit(1);
   return x;
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& log10( DAC& x ) {
 static const double logE = 0.4342944819032518276511289;
 return  logE*log(x);
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& pow( DAC& x, double s ) { 
 DAC& epsPow( DAC&, double );
 DAC* epsilon = new DAC;
 complex factor;
 complex std;
 dlist_iterator getNext( (dlist&) x );
 DACterm* p;
 int u;
 
 if( x.count == 0 ) {
   printf("\n*** WARNING ***  pow called with unevaluated DAC.\n");
   delete epsilon;
   return x;
   }
 
 p = (DACterm*) getNext();
 if( ( ( p -> weight      ) ==  0   ) &&
     ( ( std = p -> value ) !=  0.0 )
   )                                  // x has non-zero standard part
   {
   factor = pow( std, s );
   *epsilon = x;                      // x must not be altered by the routine
   p = epsilon->get();                //   pops the standard part off epsilon
   epsilon->scaleBy( 1.0/std );
   *epsilon = factor*epsPow( *epsilon, s );
   DA__garbage.store( epsilon );
   return *epsilon;
   }
 else                                 // x is pure infinitesimal
   {
   u = nearestInteger( s );
   if( s != (double) u ) {
     printf( "\n*** ERROR::DAC pow: attempt to use infinitesimal " );
     printf( "as base with non-integer exponent.\n" );
     exit(1);
     }
   *epsilon = complex_one;
   if ( u == 0 ) {
     DA__garbage.store( epsilon );
     return *epsilon;
   }
   if ( u > 0 ) {
     while( u-- > 0 ) *epsilon = (*epsilon)*x;
     DA__garbage.store( epsilon );
     return *epsilon;
     }
   else {
     while( u++ < 0 ) *epsilon = (*epsilon)*x;
     *epsilon = complex_one / *epsilon;
     DA__garbage.store( epsilon );
     return *epsilon;
     }
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& sin( DAC& x ) { 
 
 DAC& epsSin( DAC& );
 DAC& epsCos( DAC& );
 DAC epsilon;
 complex cs, sn;
 dlist_iterator getNext( (dlist&) x );
 DACterm* p;
 
 if( x.count == 0 ) {
   printf("\n*** WARNING ***  exp called with unevaluated DAC.\n");
   return x;
   }
 
 p = (DACterm*) getNext();
 if( ( p -> weight ) == 0 ) {         // x has non-zero standard part
   cs = cos( p -> value );
   sn = sin( p -> value );
   epsilon = x;                       // x must not be altered by the routine
   p = epsilon.get();                 // pops the standard part off epsilon
   return sn*epsCos( epsilon ) + cs*epsSin( epsilon );
   }
 else {                               // x is pure infinitesimal
   return epsSin( x );
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& sinh( DAC& x ) {
 DAC z;
 z = exp(x);
 return ( z - (complex_one/z))/2.0;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& sqrt( DAC& x ) {
 DAC& epsSqrt( DAC& );
 DAC epsilon;
 complex factor;
 complex std;
 dlist_iterator getNext( (dlist&) x );
 DACterm* p;
 
 if( x.count == 0 ) {
   printf("\n*** WARNING ***  pow called with unevaluated DAC.\n");
   return x;
   }
 
 p = (DACterm*) getNext();
 if( ( ( p -> weight      ) ==  0   ) &&
     ( ( std = p -> value ) !=  complex_zero )
   )                                  // x has non-zero standard part
   {
   factor = sqrt( std );
   epsilon = x;                       // x must not be altered by the routine
   p = epsilon.get();                 //   pops the standard part off epsilon
   epsilon.scaleBy( complex_one/std );
   return factor*epsSqrt( epsilon );
   }
 else                                 // x is pure infinitesimal
   {
   printf( "\n*** ERROR::DAC sqrt: attempt to use infinitesimal argument." );
   if( 1 + 1 == 2 ) exit(1);
   return x;
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& tan( DAC& x ) { 
 return sin(x) / cos(x) ;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& tanh( DAC& x ) { 
 return sinh(x) / cosh(x);
}
 

//***************************************************************
//***************************************************************
//***************************************************************
//
//      Auxiliary functions which operate on infinitesimals.
//      It is assumed that the calling program checks to be sure
//      that the argument has zero standard part.
 
DAC& epsCos( DAC& epsilon ) { 
 
 DAC* dummy;
 DAC* z = new DAC;
 DAC epsq, term;
 double n;
 int i;
 
 epsq = - epsilon*epsilon;
 
 // --- Old code ------
 // *z = (DAC) 1.0;
 // --- New code ------            This is done to control memory growth
 dummy = new DAC( complex_one );
 *z = *dummy;
 delete dummy;
 // -------------------
 
 term = epsq / 2.0;
 n = 2.0;
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = epsilon.refPoint[i];
 
 while( term.count > 0 ) {
   *z = *z + term;
   term = ( ( term*epsq ) / ++n ) / ++n;
   }
 
 z->accuWgt = epsilon.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& epsExp( DAC& epsilon ) { 
 DAC* dummy;
 DAC* z = new DAC;
 DAC  term;
 double n;
 int i;
 
 // --- Old code ------
 // *z = (DAC) 1.0;
 // --- New code ------            This is done to control memory growth
 dummy = new DAC( complex_one );
 *z = *dummy;
 delete dummy;
 // -------------------
 
 term = epsilon;
 n = 1.0;
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = epsilon.refPoint[i];
 
 while( term.count > 0 ) {
   *z = *z + term;
   term = ( term*epsilon ) / ++n;
   }
 
 z->accuWgt = epsilon.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& epsPow( DAC& epsilon, double s ) { 
 DAC* dummy;
 DAC* z = new DAC;
 DAC  term;
 double f, n;
 int i;
 
 // --- Old code ------
 // *z = (DAC) 1.0;
 // --- New code ------            This is done to control memory growth
 dummy = new DAC( complex_one );
 *z = *dummy;
 delete dummy;
 // -------------------
 
 f = s;
 n = 1.0;
 term = s*epsilon;
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
          z->refPoint[i] = epsilon.refPoint[i];
 
 while( term.count > 0 ) {
   *z = *z + term;
   term = ( (--f) * term * epsilon ) / ++n;
   }
 
 z->accuWgt = epsilon.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& epsSin( DAC& epsilon ) { 
 
 DAC* z = new DAC;
 DAC  epsq, term;
 double n;
 
 epsq = - epsilon*epsilon;
 *z = epsilon;
 term = ( epsilon*epsq ) / 6.0;
 n = 3.0;
 
 while( term.count > 0 ) {
   *z = *z + term;
   term = ( ( term*epsq ) / ++n ) / ++n;
   }
 
 z->accuWgt = epsilon.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& epsSqrt( DAC& epsilon ) {  // This function is identical to epsPow
                              // with the substitution  s = 1/2
 DAC*     dummy;
 DAC*     z = new DAC;
 DAC      term;
 double  f, n;
 int     i;
 
 // --- Old code ------
 // *z = (DAC) 1.0;
 // --- New code ------            This is done to control memory growth
 dummy = new DAC( complex_one );
 *z = *dummy;
 delete dummy;
 // -------------------
 
 f    = 1.0 / 2.0;
 n    = 1.0;
 term = f*epsilon;
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
          z->refPoint[i] = epsilon.refPoint[i];
 
 while( term.count > 0 ) {
   *z = *z + term;
   term = ( (--f) * term * epsilon ) / ++n;
   }
 
 z->accuWgt = epsilon.accuWgt;

 DA__garbage.store( z );
 return *z;
 }
 

//***************************************************************
//***************************************************************
//***************************************************************
//
//      Functions which rank and unrank monomials.  Developed from
//      algorithms provided by Nijenhuis and Wilf, Combinatorial
//      Algorithms. (2nd ed.)
 
void DAC__monoCode() {
 int c;
 int i, j;
 j = 0;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   for( c = 0; c < DAC__1stEnv.DAC__exponent[i]; c++ ) DAC__1stEnv.DAC__expCode[j++] = 1;
   DAC__1stEnv.DAC__expCode[j++] = 0;
   }
}

//    |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void DAC__monoDecode() {
 int c;
 int i, j;
 j = 0;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   c = 0;
   while( DAC__1stEnv.DAC__expCode[j++] ) ++c;
   DAC__1stEnv.DAC__exponent[i] = c;
   }
}

//    |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

int DAC__monoRank() {
 //  This function assumes DAC__monoCode has been run,
 //  so that the path is appropriately coded into DAC__1stEnv.DAC__expCode.
 char edge;
 int w, n;
 int rank;
 int zeroCount;
 int i;
 
 i = 0;
 rank = 0;
 w = 0;
 n = 1;
 
 if( edge = DAC__1stEnv.DAC__expCode[i++] ) zeroCount = 0;
 else                          zeroCount = 1;
 
 while( zeroCount < DAC__1stEnv.DAC__NumVar ) {
 
   if( edge ) {
     w++;
     if( ( w > 0 ) && ( n > 1 ) )  rank += DAC__1stEnv.DAC__numPaths[w][n-1];
     }
   else  n++;
 
   if( !( edge = DAC__1stEnv.DAC__expCode[i++] ) ) zeroCount++;
 
   }
 
 rank += ( w * DAC__1stEnv.DAC__numPaths[w][n] ) / n;
 
 return rank;
}


//***************************************************************
//***************************************************************
//***************************************************************
//
//    Implementation of class CLieOperator
//

//    Constructors and destructors    |||||||||||||||||||||||||||

CLieOperator::CLieOperator() {
 int i;
 
 if( DAC__1stEnv.DAC__SpaceDim == 0 ) {
   printf( "\n*** ERROR: CLieOperator::CLieOperator called " );
   printf( "after DASetup declared no vectors.\n" );
   exit(0);
   }
 
 weight = -1;
 
 if( DAC__1stEnv.DAC__allSet == 137 ) {
   v = new DAC[ DAC__1stEnv.DAC__NumVar ];
   refPoint = new complex[ DAC__1stEnv.DAC__NumVar ];
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = DAC__1stEnv.DAC__refPoint[i];
   }
 else {
   v = 0;
   refPoint = 0;
   DAC__1stEnv.DAC__predefLieOp.insert( this );
   }
}

//    |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator::CLieOperator( CLieOperator& x ) {
 int i;
 
 if( DAC__1stEnv.DAC__allSet != 137 ) {
   printf( "\n*** CLieOperator::CLieOperator( CLieOperator& ) ERROR *** " );
   printf( "Prior call to DASetup required.\n" );
   exit(0);
   }
 
 v = new DAC[ DAC__1stEnv.DAC__NumVar ];
 for ( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) v[i] = x.v[i];
 weight = x.weight;
 accuWgt = x.accuWgt;
 
 refPoint = new complex[ DAC__1stEnv.DAC__NumVar ];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = x.refPoint[i];
}

//    |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator::CLieOperator( LieOperator& x ) {
 int i;
 
 if( DAC__1stEnv.DAC__allSet != 137 ) {
   printf( "\n*** CLieOperator::CLieOperator( LieOperator& ) ERROR *** " );
   printf( "Prior call to DACSetup required.\n" );
   exit(0);
   }
 
 v = new DAC[ DAC__1stEnv.DAC__NumVar ];
 for ( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) v[i] = DAC(x.v[i]);
 weight = x.weight;
 accuWgt = x.accuWgt;
 
 refPoint = new complex[ DAC__1stEnv.DAC__NumVar ];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = 
   complex(x.refPoint[i],0.0);
}

//    |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator::CLieOperator( char* flag ) { 
 int i;
 int nv;
 
 if( DAC__1stEnv.DAC__SpaceDim == 0 ) {
   printf( "\n*** ERROR: CLieOperator::CLieOperator called " );
   printf( "after DASetup declared no vectors.\n" );
   exit(0);
   }
 
 if( DAC__1stEnv.DAC__allSet != 137 ) {
   printf( "\n*** CLieOperator::CLieOperator( char* ) ERROR *** " );
   printf( "Prior call to DASetup required.\n" );
   exit(0);
   }
 
 nv = DAC__1stEnv.DAC__NumVar;
 v = new DAC[ nv ];

 refPoint = new complex[ nv ];
 for( i = 0; i < nv; i++ ) {
  refPoint[i] = DAC__1stEnv.DAC__refPoint[i];
  v[i].setVariable( i );
 }

 weight = 1;
 accuWgt = DAC__1stEnv.DAC__MaxWeight;
}

//    |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

// ??? REMOVE  CLieOperator::CLieOperator( int size ) {
// ??? REMOVE  int i;
// ??? REMOVE  
// ??? REMOVE  if( DAC__1stEnv.DAC__allSet != 137 ) {
// ??? REMOVE    printf( "\n*** CLieOperator::CLieOperator( int ) ERROR *** " );
// ??? REMOVE    printf( "Prior call to DACSetup required.\n" );
// ??? REMOVE    exit(0);
// ??? REMOVE    }
// ??? REMOVE  
// ??? REMOVE  if( size <= 0 ) {
// ??? REMOVE    printf( "\n*** ERROR: CLieOperator::CLieOperator called with size = %d.\n", size );
// ??? REMOVE    exit(0);
// ??? REMOVE    }
// ??? REMOVE  
// ??? REMOVE  if( DAC__1stEnv.DAC__SpaceDim == 0 ) {
// ??? REMOVE    printf( "\n*** ERROR: CLieOperator::CLieOperator called " );
// ??? REMOVE    printf( "after DACSetup declared no vectors.\n" );
// ??? REMOVE    exit(0);
// ??? REMOVE    }
// ??? REMOVE  
// ??? REMOVE  if ( DAC__1stEnv.DAC__SpaceDim == -1 ) {
// ??? REMOVE    printf( "\n*** ERROR: CLieOperator::CLieOperator called " );
// ??? REMOVE    printf( "with DAC__1stEnv.DAC__SpaceDim == -1.\n" );
// ??? REMOVE    exit(0);         // In fact, this should never happen.
// ??? REMOVE    // DAC__1stEnv.DAC__SpaceDim = size;
// ??? REMOVE    // v = new DAC[ DAC__1stEnv.DAC__NumVar ];
// ??? REMOVE    // weight = -1;
// ??? REMOVE    }
// ??? REMOVE  
// ??? REMOVE  else {
// ??? REMOVE    if( size != DAC__1stEnv.DAC__SpaceDim ) {
// ??? REMOVE      printf( "\n*** ERROR: CLieOperator::CLieOperator discrepancy in vector size.\n" );
// ??? REMOVE      exit(0);
// ??? REMOVE      }
// ??? REMOVE    else {
// ??? REMOVE      v = new DAC[ DAC__1stEnv.DAC__NumVar ];
// ??? REMOVE      weight = -1;
// ??? REMOVE      }
// ??? REMOVE    }
// ??? REMOVE  
// ??? REMOVE  refPoint = new complex[ DAC__1stEnv.DAC__NumVar ];
// ??? REMOVE  for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = DAC__1stEnv.DAC__refPoint[i];
// ??? REMOVE  }
// ??? REMOVE  
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator::~CLieOperator() {
 if( v ) delete [] v;
 if( v ) delete [] refPoint;
}

void CLieOperator::reset() {
 int i, j;
 weight = -1;
 accuWgt = DAC__1stEnv.DAC__MaxWeight;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
  if( weight < v[i].weight ) weight = v[i].weight;
  if( accuWgt > v[i].accuWgt ) accuWgt = v[i].accuWgt;
  refPoint[i] = v[0].refPoint[i];
 }
 i = 1;
 while( i < DAC__1stEnv.DAC__NumVar ) {
  for( j = 0; j < DAC__1stEnv.DAC__NumVar; j++ ) 
   if( refPoint[j] != v[i].refPoint[j] ) {
    printf( "\n" );
    printf( "*** ERROR ***                                      \n" );
    printf( "*** ERROR *** void CLieOperator::reset()           \n" );
    printf( "*** ERROR *** refPoint error for i = %d            \n", i );
    printf( "*** ERROR ***                                      \n" );
    exit(0);
   }
  i++;
 }
}


//     Member functions(public)  |||||||||||||||||||||||||||||||

void CLieOperator::fixReference( complex* r ) {
 int i;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = r[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void CLieOperator::fixReference() {
 int i;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = DAC__1stEnv.DAC__refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void CLieOperator::fixReference( DAC& x ) {
 int i;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = x.refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void CLieOperator::fixReferenceAtEnd( CLieOperator& x ) {
 int i;
 complex* u = new complex [ DAC__1stEnv.DAC__NumVar ];
 x.standardPart( u );
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = u[i];
 delete [] u;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void CLieOperator::fixReferenceAtStart( CLieOperator& x ) {
 int i;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) refPoint[i] = x.refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void CLieOperator::setVariable( DAC& x, int j ) {
 int i;
 
 if( j < 0 || DAC__1stEnv.DAC__NumVar <= j ) {
  printf( "\n***ERROR ***                                              \n" );
  printf(   "***ERROR *** CLieOperator::setVariable( DAC&, int )            \n" );
  printf(   "***ERROR *** It is certainly not true                     \n" );
  printf(   "***ERROR *** that 0 <= %d < %d                            \n",
            j, DAC__1stEnv.DAC__NumVar );
  printf(   "***ERROR ***                                              \n" );
  printf(   "***ERROR *** Sorry.  Good bye.                            \n" );
  printf(   "***ERROR ***                                              \n" );
  exit(0);
 }
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) if( refPoint[i] != x.refPoint[i] ) {
  printf( "\n*** CLieOperator::setVariable ERROR: Incompatible references.\n" );
  exit(0);
 }
 
 v[j] = x;
 if ( weight < x.weight ) weight = x.weight;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void CLieOperator::setVariable( complex x, int j ) {
 int* ndx;
 int i;
 
 if( j < 0 || DAC__1stEnv.DAC__NumVar <= j ) {
  printf( "\n***ERROR ***                                              \n" );
  printf(   "***ERROR *** CLieOperator::setVariable( complex, int )         \n" );
  printf(   "***ERROR *** It is certainly not true                     \n" );
  printf(   "***ERROR *** that 0 <= %d < %d                            \n",
            j, DAC__1stEnv.DAC__NumVar );
  printf(   "***ERROR ***                                              \n" );
  printf(   "***ERROR *** Sorry.  Good bye.                            \n" );
  printf(   "***ERROR ***                                              \n" );
  exit(0);
 }
 
 v[j].clear();
 // if( ( j < 0 ) || ( j >= DAC__1stEnv.DAC__NumVar ) ) return;  ??? Old form.
 
 refPoint[j] = x;
 DAC__1stEnv.DAC__refPoint[j] = x;
 
 ndx = new int[ DAC__1stEnv.DAC__NumVar ];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) ndx[i] = 0;
 ndx[j] = 1;
 v[j].insert( new DACterm( ndx, 1.0 ) );
 
 ndx = new int[ DAC__1stEnv.DAC__NumVar ];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) ndx[i] = 0;
 v[j].insert( new DACterm( ndx, x ) );
                            // ??? How about delete ndx ???
 if ( weight < 1 ) weight = 1;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void CLieOperator::getReference( complex* r ) {
 int i;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) r[i] = refPoint[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char CLieOperator::isNilpotent() {
 for( int i = 0; i <  DAC__1stEnv.DAC__SpaceDim; i++ ) 
  if( !(v[i].isNilpotent()) ) return 0;
 return 1;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void CLieOperator::peekAt() {
 int i;
 printf( "\n******************\nCLieOperator::peekAt ********\n" );
 printf( "Weight: %d   Address: %d\n", weight, this );
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   printf( "\n******************\n**** Component index = %d:\n", i );
   v[i].peekAt();
   }
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

dlist* CLieOperator::image() {
 dlist* ret = new dlist[ DAC__1stEnv.DAC__NumVar ];  // ??? Change this!!!
 for( int i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) 
  ret[i] = v[i].image();
 return ret;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void CLieOperator::printCoeffs() {
 int i;
 printf( "\n************ Begin CLieOperator::printCoeffs ********\n" );
 printf( "Weight: %d \n", weight );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   printf( "\n******************\n**** Component index = %d:\n", i );
   v[i].printCoeffs();
   }
 printf( "\n************ End   CLieOperator::printCoeffs ********\n" );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void CLieOperator::peekAt( char* fileName ) {
 int i;
 DA__scratchFile = fopen( fileName, "w" );
 fprintf( DA__scratchFile,
          "\n******************\nCLieOperator::peekAt ********\n" );
 fprintf( DA__scratchFile, "Weight: %d   Address: %d\n", weight, this );
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   fprintf( DA__scratchFile,
            "\n******************\n**** Component index = %d:\n", i );
   v[i].peekAt( 1 );
   }
 fclose( DA__scratchFile );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void CLieOperator::printCoeffs( char* fileName ) {
 int i;
 DA__scratchFile = fopen( fileName, "w" );
 fprintf( DA__scratchFile,
          "\n************ Begin CLieOperator::printCoeffs ********\n" );
 fprintf( DA__scratchFile, "Weight: %d \n", weight );
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   fprintf( DA__scratchFile, "\n******************\n**** Component index = %d:\n", i );
   v[i].printCoeffs( 1 );
   }
 fprintf( DA__scratchFile, 
          "\n************ End   CLieOperator::printCoeffs ********\n" );
 fclose( DA__scratchFile );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void CLieOperator::standardPart( complex* x ) {
 int i;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )  x[i] = v[i].standardPart();
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void CLieOperator::weightedDerivative( int* m, complex* x ) {
 int i;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) x[i] = v[i].weightedDerivative( m );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void CLieOperator::derivative( int* m, complex* x ) {
 int i;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) x[i] = v[i].derivative( m );
}


// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& CLieOperator::filter( MX_C_FUNCPTR f [] ) {
 CLieOperator* z = new CLieOperator;
 int i;
 
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
  z->v[i] = v[i].filter( f[i] );
 }
 z->reset();

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& CLieOperator::filter( int lower, int upper ) {
 CLieOperator* z = new CLieOperator;     // ??? Could this be simplified by using
 int i;                                  // ??? CLieOperator* z = new CLieOperator( *this );

 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
  z->v[i] = v[i].filter( lower, upper );

 z->reset();

 DA__garbage.store( z );
 return *z;
}


//     Operators   |||||||||||||||||||||||||||||||||||||||||||||

ostream& operator<<(ostream& os,  CLieOperator& x) {
 int i;
 os << "\n************ Begin CLieOperator  printCoeffs ********\n";
 os << "Weight: " << x.weight << endl;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) {
   os << "\n******************\n**** Component index = " << i << endl;
   os << x.v[i];
   }
 return  os << "\n************ End   CLieOperator  printCoeffs ********\n";
}

char operator==( CLieOperator& x, CLieOperator& y ) {
 int i;
 if( x.weight != y.weight ) return 0;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) if( x.refPoint[i] != y.refPoint[i] ) return 0;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) if( !( x.v[i] == y.v[i] ) ) return 0;
 return 1;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

char operator!=( CLieOperator& x, CLieOperator& y ) {
 return !( x == y );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

complexmatrix CLieOperator::Jacobian() {
 int             i, j;
 int             nsd = DAC__1stEnv.DAC__SpaceDim;
 int*            d = new int[ nsd ];
 complexmatrix   M( nsd, nsd, (complex) 0.0 );

 for( i = 0; i < nsd; i++  ) d[i] = 0;
 for( j = 0; j < nsd; j++ ) {
  d[j] = 1;
  for( i = 0; i < nsd; i++ ) M( i, j ) = v[i].derivative( d );
  d[j] = 0;
 }

 return M;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& CLieOperator::operator()( CLieOperator& x ) {
 int i;
 CLieOperator* z = new CLieOperator;
 for( i = 0; i < DAC__1stEnv.DAC__SpaceDim; i++) {
  z->v[i] = v[i]( x );
 }
 while( i < DAC__1stEnv.DAC__NumVar ) z->v[i] = x.v[i++];
 z->reset();

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& CLieOperator::operator=( CLieOperator& x ) {
 int i;
 int w;
 weight = -1;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   v[i] = x.v[i];
   if ( weight < ( w = v[i].weight ) ) weight = w;
   refPoint[i] = x.refPoint[i];
   }
 return *this;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC CLieOperator::operator[]( int i ) {
 return v[i];
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& CLieOperator::operator^( DAC& x ) { 
 DAC*  answer = new DAC;
 int  s      = DAC__1stEnv.DAC__SpaceDim;
 int* ndx    = DAC__1stEnv.DAC__AllZeroes;
 int aw, i, jw;
 char adjustWeight = 1;

 aw = DAC__1stEnv.DAC__MaxWeight;
 ndx[0] = 1;
 *answer = v[0]*x.D( ndx );
 ndx[0] = 0;

        // Differentiation will normally lower 
        //  the maximum accurate order by one.  This is 
        //  offset if the constant term in v[] vanishes.
        //
        if( v[0].standardPart() == complex_zero ) {
         jw = v[0].accuWgt;
         if( jw > x.accuWgt ) jw = x.accuWgt;
         if( jw < aw ) aw = jw;
        }
        else adjustWeight = 0;

 if( s > 1 ) for( i = 1; i < s; i++ ) {
  ndx[i] = 1;
  *answer += v[i]*x.D( ndx );
  ndx[i] = 0;

        if( v[i].standardPart() == complex_zero ) {
         jw = v[i].accuWgt;
         if( jw > x.accuWgt ) jw = x.accuWgt;
         if( jw < aw ) aw = jw;
        }
        else adjustWeight = 0;

 }

 // The accuracy of the answer is adjusted only if
 //  all components of v[] are differentials.
 // 
 if( adjustWeight ) answer->accuWgt = aw;

 DA__garbage.store( answer );
 return *answer;
}


// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& CLieOperator::expMap( double t, DAC& x ) { 
 DAC* answer = new DAC;
 DAC u;
 double f;
 int count;
 
 *answer = x;
 u     = x;
 f     = 1.0;
 count = 0;

 u = ( t/f++ )*( operator^( u ) );
 while( ( count++ < MX_MAXITER ) && ( u != complex(0.0,0.0) ) ) {
  *answer += u;                        // ??? How does this
  u = ( t/f++ )*( operator^( u ) );    // ??? affect efficiency?
 }

 if( count >= MX_MAXITER ) {
  printf( "\n" );
  printf( "*** WARNING ***                                         \n" );
  printf( "*** WARNING *** DAC& CLieOperator::expMap()             \n" );
  printf( "*** WARNING *** Number of iterations has exceeded %d    \n", MX_MAXITER );
  printf( "*** WARNING *** without achieving convergence.          \n" );
  printf( "*** WARNING *** Results may be incorrect.               \n" );
  printf( "*** WARNING ***                                         \n" );
  printf( "\n" );
 }

 DA__garbage.store( answer );
 return *answer;

}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& CLieOperator::expMap( DAC& t, DAC& x ) { 
 DAC* answer = new DAC;
 DAC u;
 double f;
 int count;
 
 *answer = x;
 u     = x;
 f     = 1.0;
 count = 0;

 u = ( t/f++ )*( operator^( u ) );
 while( ( count++ < MX_MAXITER ) && ( u != 0.0 ) ) {
  *answer += u;                      // ??? How does this
  u = ( t/f++ )*( operator^( u ) );  // ??? affect efficiency?
 }

 if( count >= MX_MAXITER ) {
  printf( "\n" );
  printf( "*** WARNING ***                                         \n" );
  printf( "*** WARNING *** DAC& CLieOperator::expMap()             \n" );
  printf( "*** WARNING *** Number of iterations has exceeded %d    \n", MX_MAXITER );
  printf( "*** WARNING *** without achieving convergence.          \n" );
  printf( "*** WARNING *** Results may be incorrect.               \n" );
  printf( "*** WARNING ***                                         \n" );
  printf( "\n" );
 }

 DA__garbage.store( answer );
 return *answer;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& CLieOperator::expMap( double t , CLieOperator& x ) {
 CLieOperator* z = new CLieOperator;

 for( int i = 0; i < DAC__1stEnv.DAC__SpaceDim; i++) 
  z->v[i] = expMap( t, x.v[i] );
 while( i < DAC__1stEnv.DAC__NumVar ) z->v[i] = x.v[i++];
 z->reset();

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& CLieOperator::expMap( DA& t, CLieOperator& x ) {
 CLieOperator* z = new CLieOperator;

 for( int i = 0; i < DAC__1stEnv.DAC__SpaceDim; i++) 
  z->v[i] = expMap( t, x.v[i] );
 while( i < DAC__1stEnv.DAC__NumVar ) z->v[i] = x.v[i++];
 z->reset();

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& CLieOperator::expMap( DAC& t, CLieOperator& x ) {
 CLieOperator* z = new CLieOperator;

 for( int i = 0; i < DAC__1stEnv.DAC__SpaceDim; i++) 
  z->v[i] = expMap( t, x.v[i] );
 while( i < DAC__1stEnv.DAC__NumVar ) z->v[i] = x.v[i++];
 z->reset();

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& operator+ ( CLieOperator& x, CLieOperator& y ) { 
 CLieOperator* z = new CLieOperator;
 int i;

 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   if( x.refPoint[i] != ( z->refPoint[i] = y.refPoint[i] ) ) {
     printf( "\n*** CLieOperator ADDITION ERROR: Inconsistency in reference points.\n" );
     exit(0);
     }
   }
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];

 z->weight = 0;
 z->accuWgt = DAC__1stEnv.DAC__MaxWeight;
 for( i = 0; i < DAC__1stEnv.DAC__SpaceDim; i++ )  {
  z->v[i] = x.v[i] + y.v[i];
  if( z->weight  < z->v[i].weight  ) z->weight  = z->v[i].weight;
  if( z->accuWgt > z->v[i].accuWgt ) z->accuWgt = z->v[i].accuWgt;
 }
 
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& operator- ( CLieOperator& x, CLieOperator& y ) {
 CLieOperator* z = new CLieOperator;
 int i;

 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   if( x.refPoint[i] != ( z->refPoint[i] = y.refPoint[i] ) ) {
     printf( "\n*** CLieOperator ADDITION ERROR: Inconsistency in reference points.\n" );
     exit(0);
     }
   }
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];

 z->weight = 0;
 z->accuWgt = DAC__1stEnv.DAC__MaxWeight;
 for( i = 0; i < DAC__1stEnv.DAC__SpaceDim; i++ )  { 
  z->v[i] = x.v[i] - y.v[i];
  if( z->weight  < z->v[i].weight  ) z->weight  = z->v[i].weight;
  if( z->accuWgt > z->v[i].accuWgt ) z->accuWgt = z->v[i].accuWgt;
 }

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& operator- ( CLieOperator& x ) {
 CLieOperator* z = new CLieOperator;
 int i;

 for( i = 0; i < DAC__1stEnv.DAC__SpaceDim; i++ )  z->v[i] = - x.v[i];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 z->weight  = x.weight;
 z->accuWgt = x.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& operator* ( complex& c, CLieOperator& x ) {
 CLieOperator* z;
 int i;

 for( i = 0; i < DAC__1stEnv.DAC__SpaceDim; i++ )  z->v[i] = c*x.v[i];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 z->weight  = x.weight;
 z->accuWgt = x.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& operator* ( CLieOperator& x, complex& c ) {
 CLieOperator* z;
 int i;

 for( i = 0; i < DAC__1stEnv.DAC__SpaceDim; i++ )  z->v[i] = c*x.v[i];
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];
 z->weight  = x.weight;
 z->accuWgt = x.accuWgt;

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& operator* ( DAC& c, CLieOperator& x ) {
 CLieOperator* z;
 int i;

 z->weight = 0;
 z->accuWgt = DAC__1stEnv.DAC__MaxWeight;
 for( i = 0; i < DAC__1stEnv.DAC__SpaceDim; i++ )  {
  z->v[i] = c*x.v[i];
  if( z->weight  < z->v[i].weight  ) z->weight  = z->v[i].weight;
  if( z->accuWgt > z->v[i].accuWgt ) z->accuWgt = z->v[i].accuWgt;
  }

 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& operator* ( CLieOperator& x, DAC& c ) {
 return c*x;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& operator*(  doublematrix& M, CLieOperator& x ) {
 CLieOperator* z = new CLieOperator;
 int i, j;

 z->weight = x.weight;
 z->accuWgt = x.accuWgt;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];

 int nsd = DA__1stEnv.DA__SpaceDim;

 if( ( M.rows() != nsd ) || 
     ( M.cols() != nsd )) {
  printf( "\n" );
  printf( "*** ERROR ***                                           \n" );
  printf( "*** ERROR *** CLieOperator& operator*(  doublematrix& M, CLieOperator& x ) \n" );
  printf( "*** ERROR *** Rows and/or columns of the matrix         \n" );
  printf( "*** ERROR *** are not correct.                          \n" );
  printf( "*** ERROR ***                                           \n" );
  exit(0);
 }

 for( i = 0; i < nsd; i++ ) {
  z->v[i] = M( i, 0 ) * x.v[0];
  j = 1;
  while( j < nsd )   z->v[i] += M( i, j ) * x.v[j++];
 }

 DA__garbage.store( z );
 return *z;
}
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& operator*(  complexmatrix& M, CLieOperator& x ) {
 CLieOperator* z = new CLieOperator;
 int i, j;

 z->weight = x.weight;
 z->accuWgt = x.accuWgt;
 for( i = 0; i < DA__1stEnv.DA__NumVar; i++ ) z->refPoint[i] = x.refPoint[i];

 int nsd = DA__1stEnv.DA__SpaceDim;

 if( ( M.rows() != nsd ) || 
     ( M.cols() != nsd )) {
  printf( "\n" );
  printf( "*** ERROR ***                                           \n" );
  printf( "*** ERROR *** CLieOperator& operator*(  complexmatrix& M, CLieOperator& x ) \n" );
  printf( "*** ERROR *** Rows and/or columns of the matrix         \n" );
  printf( "*** ERROR *** are not correct.                          \n" );
  printf( "*** ERROR ***                                           \n" );
  exit(0);
 }

 for( i = 0; i < nsd; i++ ) {
  z->v[i] = M( i, 0 ) * x.v[0];
  j = 1;
  while( j < nsd )   z->v[i] += M( i, j ) * x.v[j++];
 }

 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

CLieOperator& operator*( CLieOperator& x, CLieOperator& y ) { 
 CLieOperator* z = new CLieOperator;
 CLieOperator u;
 DAC term;
 int i;
 int j;
 int w;
 DACterm* p;
 
 // Check consistency of reference points.
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ )
   if( x.refPoint[i] != ( y.v[i] ).weightedDerivative( DAC__1stEnv.DAC__AllZeroes ) ) {
     printf( "\n*** CLieOperator CONCATENATION ERROR: Inconsistent reference points.\n" );
     exit(0);
     }
 
 // Subtract reference point prior to concatenation.
 u = y;
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) p = ( u.v[i] ).get();
 if( p->weight != 0 ) {
   printf( "\n*** CLieOperator CONCATENATION ERROR: Argument has no nonstandard part!!\n" );
   exit(0);
   }
 
 // Evaluate and store monomials.
 
 // The zeroth one.
 DAC__1stEnv.DAC__DAmonomial[0] = complex_one;
 DAC__1stEnv.DAC__DAmonomial[0].fixReferenceAtStart( y );
 
 // For all higher weights ...
 for( w = 1; w <= x.weight; w++ )
 
   // Get the next set of exponents of weight w.
   while( nexcom( w, DAC__1stEnv.DAC__NumVar, DAC__1stEnv.DAC__exponent ) ) {
 
     // Find the first non-zero exponent.
     i = 0;
     while( !( DAC__1stEnv.DAC__exponent[i++] ) ) ;
     i--;
 
     // The value of the monomial associated with this composition
     // is obtained by multiplying a factor into a previously
     // computed monomial.
     ( DAC__1stEnv.DAC__exponent[i] )--;
     DAC__monoCode();
     term = DAC__1stEnv.DAC__DAmonomial[ DAC__monoRank() ];
     ( DAC__1stEnv.DAC__exponent[i] )++;
     DAC__monoCode();
     DAC__1stEnv.DAC__DAmonomial[ DAC__monoRank() ] = term * u.v[i];   // ??? Is this OK???
 
     } // End while loop.
 
 // Monomials have been stored.
 // Now traverse the DAC variable and evaluate.
 
 for( i = 0; i < DAC__1stEnv.DAC__SpaceDim; i++ )  {
   z->v[i] = concat( x.v[i] );
   for( j = 0; j < DAC__1stEnv.DAC__NumVar; j++ ) ( z->v[i] ).refPoint[j] = y.refPoint[j];
   }
 
 for( i = DAC__1stEnv.DAC__SpaceDim; i < DAC__1stEnv.DAC__NumVar; i++ ) {
   if( x.v[i] != y.v[i] )
     printf( "\n*** CLieOperator CONCATENATION ERROR!!! Horrible!!!\n" );
   z->v[i] = y.v[i];
   }
 
 // Set the correct reference point in z.
 for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) z->refPoint[i] = y.refPoint[i];
 
 DA__garbage.store( z );
 return *z;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

DAC& concat( DAC& x ) { 
 DAC* v = new DAC;
 dlist_iterator getNext( (dlist&) x );
 DACterm* p;
 int i;
 
 *v = complex_zero;
 v->fixReference( DAC__1stEnv.DAC__DAmonomial[0] );
 
 while( p = (DACterm*) getNext() ) {
   for( i = 0; i < DAC__1stEnv.DAC__NumVar; i++ ) DAC__1stEnv.DAC__exponent[i] = (p->index)[i];
   DAC__monoCode();
   *v += ( p->value ) * ( DAC__1stEnv.DAC__DAmonomial[ DAC__monoRank() ] );
   }
 
 DA__garbage.store( v );
 return *v;
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void operator*=( CLieOperator& x, CLieOperator& y ) {
 x = x*y;
}
 
 

//***************************************************************
//***************************************************************
//***************************************************************
//
//    Implementation of class coordC
//
 
coordC::coordC( complex x ) : DAC() {
 int* n;
 coordC* y;
 
 if( DAC__1stEnv.DAC__allSet != 137 ) {
   printf( "\n*** ERROR ***                                       \n" );
   printf(   "*** ERROR *** coordC::coordC( complex )                \n" );
   printf(   "*** ERROR *** DACSetup must be invoked first.        \n" );
   printf(   "*** ERROR ***                                       \n" );
   exit(1);
   }
 
 if( ( n = (int*) DAC__coordPool.get() ) == 0 ) {
   printf( "\n*** ERROR ***                                       \n" );
   printf(   "*** ERROR *** coordC::coordC( complex )                \n" );
   printf(   "*** ERROR *** Attempt made to declare too many      \n" );
   printf(   "*** ERROR *** coordinates, according to what was    \n" );
   printf(   "*** ERROR *** declared in DACSetup.                  \n" );
   printf(   "*** ERROR ***                                       \n" );
   exit(1);
   }
 
 index = *n;
 DAC::setVariable( x, index );
 delete n;
 
 DAC__coordPtrs.append( this );
 dlist_iterator getNext( DAC__coordPtrs );
 while( y = (coordC*) getNext() ) y->fixReference();
 
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

coordC::~coordC() {
 int* n;
 char c;
 n = new int( index );
 DAC__coordPool.insert( n );
 c = DAC__coordPtrs.remove( this );
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

coordC::coordC( coordC&  ) {
 printf( "\n*** ERROR ***                                       \n" );
 printf(   "*** ERROR *** coordC::coordC( coordC& )                \n" );
 printf(   "*** ERROR *** Coordinate copy constructor called.   \n" );
 printf(   "*** ERROR ***                                       \n" );
 exit(1);
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

void coordC::set( complex x ) {
 coordC* y;
 DAC::setVariable( x, index );
 dlist_iterator getNext( DAC__coordPtrs );
 while( y = (coordC*) getNext() ) y->fixReference();
}

// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

coordC& coordC::operator=( coordC& ) {
 printf( "\n*** ERROR ***                                       \n" );
 printf(   "*** ERROR *** coordC::operator=                      \n" );
 printf(   "*** ERROR *** Attempt made to change the value      \n" );
 printf(   "*** ERROR *** of a coordinate.                      \n" );
 printf(   "*** ERROR ***                                       \n" );
 if( 3 + 8 == 11 ) exit(1);  // To avoid compiler warnings.
 return *this;
}


// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

coordC& coordC::operator=( DAC& ) {
 printf( "\n*** ERROR ***                                       \n" );
 printf(   "*** ERROR *** coordC::operator=                      \n" );
 printf(   "*** ERROR *** Attempt made to change the value      \n" );
 printf(   "*** ERROR *** of a coordinate.                      \n" );
 printf(   "*** ERROR ***                                       \n" );
 if( 3 + 8 == 11 ) exit(1);  // To avoid compiler warnings.
 return *this;
}



//***************************************************************
//***************************************************************
//***************************************************************
//
//    DACAbout() and DACNews
//

void DACAbout() {
 printf("\n\n");
 printf( "MXYZPTLK:  A C++ implementation of differential algebra.      \n" );
 printf( "                                                              \n" );
 printf( "Copyright (c) 1990  Universities Research Association, Inc.   \n" );
 printf( "              All Rights Reserved                             \n" );
 printf( "                                                              \n" );
 printf( "Author:    Leo Michelotti                                     \n" );
 printf( "                                                              \n" );
 printf( "           Fermilab                                           \n" );
 printf( "           P.O.Box 500                                        \n" );
 printf( "           Mail Stop 345                                      \n" );
 printf( "           Batavia, IL   60510                                \n" );
 printf( "                                                              \n" );
 printf( "           Phone: (708) 840 4956                              \n" );
 printf( "           Email: MICHELOTTI@FNALAD                           \n" );
 printf( "                  ALMOND::MICHELOTTI                          \n" );
 printf( "                                                              \n" );
 printf( "Release    Version 1.0 : January 31, 1990                     \n" );
 printf( "Dates:              .1 : October 11, 1990                     \n" );
 printf( "                    .2 : November 6, 1990                     \n" );
 printf("\n");
}

void DACNews() {
 printf( "\n\n" );
 printf( "7/28/93   .. James Holt                                   \n" );
 printf( "First attempt at DA with complex coefficients       \n" );
 printf( "\n" );
}


End of mxyzptlk_DAC.cc
echo normalForm.cc 1>&2
cat >normalForm.cc <<'End of normalForm.cc'
/*
**
** Utility function.
**
** Calculates the nonresonant normal form
** of a one-turn map.
**
** --- Leo Michelotti
** --- November 4, 1993
**
*/

#include "beamline.hxx"

#define MLT1  1.0e-12

char sh0( int* index, complex value ) {
 if( index[0] != index[3] + 1 ) return 0;
 if( index[1] != index[4] )     return 0;
 if( index[2] != index[5] )     return 0;
 return 1;
}

char sh1( int* index, complex value ) {
 if( index[0] != index[3] )     return 0;
 if( index[1] != index[4] + 1 ) return 0;
 if( index[2] != index[5] )     return 0;
 return 1;
}

char sh2( int* index, complex value ) {
 if( index[0] != index[3] )     return 0;
 if( index[1] != index[4] )     return 0;
 if( index[2] != index[5] + 1 ) return 0;
 return 1;
}

char sh3( int* index, complex value ) {
 if( index[0] != index[3] - 1 ) return 0;
 if( index[1] != index[4] )     return 0;
 if( index[2] != index[5] )     return 0;
 return 1;
}

char sh4( int* index, complex value ) {
 if( index[0] != index[3] )     return 0;
 if( index[1] != index[4] - 1 ) return 0;
 if( index[2] != index[5] )     return 0;
 return 1;
}

char sh5( int* index, complex value ) {
 if( index[0] != index[3] )     return 0;
 if( index[1] != index[4] )     return 0;
 if( index[2] != index[5] - 1 ) return 0;
 return 1;
}

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

void normalForm( LieOperator&   theMap,     /* input */
                 int            maxOrder,   /* input */
                 complexmatrix* Bptr,
                 CLieOperator*  N,
                 CLieOperator*  T ) {

 typedef char (*CFUNCPTR)(int*, complex);
 static CFUNCPTR shear[] = { sh0, sh1, sh2, sh3, sh4, sh5 };
 int i, j;

      /* CAUTION */  // A little test
      /* CAUTION */  if( !(theMap.isNilpotent()) ) {
      /* CAUTION */   printf( "\n" );
      /* CAUTION */   printf( "***                                        \n" );
      /* CAUTION */   printf( "*** SORRY:                                 \n" );
      /* CAUTION */   printf( "*** SORRY: void normalForm()               \n" );
      /* CAUTION */   printf( "*** SORRY: This version only supports      \n" );
      /* CAUTION */   printf( "*** SORRY: nilpotent maps.                 \n" );
      /* CAUTION */   printf( "*** SORRY:                                 \n" );
      /* CAUTION */   exit(0);
      /* CAUTION */  }

 // Establishing linear normal form coordinates
 doublematrix  A = theMap.Jacobian();
 complexmatrix B = A.eigenVectors();
 *Bptr           = B;

 complexmatrix lambda = A.eigenValues();  // ??? How inefficient is this?
                                          // ??? I've already invoked A.eigenVectors()
      /* CAUTION */  for( i = 0; i < 6; i++ ) {
      /* CAUTION */   if( fabs( abs(lambda(i)) - 1.0 ) > MLT1 ) {
      /* CAUTION */    printf( "\n" );
      /* CAUTION */    printf( "***                                            \n" );
      /* CAUTION */    printf( "*** SORRY:                                     \n" );
      /* CAUTION */    printf( "*** SORRY: void normalForm()                   \n" );
      /* CAUTION */    printf( "*** SORRY: For now, I am only allowing         \n" );
      /* CAUTION */    printf( "*** SORRY: maps with an elliptic fixed point   \n" );
      /* CAUTION */    printf( "*** SORRY: at the origin.  This will be        \n" );
      /* CAUTION */    printf( "*** SORRY: loosened as soon as I'm sure        \n" );
      /* CAUTION */    printf( "*** SORRY: everything is working properly.     \n" );
      /* CAUTION */    printf( "*** SORRY:                                     \n" );
      /* CAUTION */    printf( "*** SORRY: lambda( %d ) has magnitude = %le    \n", 
      /* CAUTION */                                 i,            abs(lambda(i)) );
      /* CAUTION */    printf( "*** SORRY:                                     \n" );
      /* CAUTION */    exit(0);
      /* CAUTION */   }
      /* CAUTION */  }

 // Normalizing the linear normal form coordinates
 complex       mi( 0., -1. );
 doublematrix  J( "J", 6 );
 complexmatrix Nx = ( B * J * B.transpose() * J ) * mi;

 for( i = 0; i < 6; i++ ) {
  Nx( i, i ) = 1.0 / sqrt( Nx(i,i) );  // ??? In principle, could get divide
                                       // ??? by zero here.
      /* CAUTION */   for( j = 0; j < 6; j++ ) {
      /* CAUTION */    if( j == i ) continue;
      /* CAUTION */    else if( abs( Nx(i,j) ) > MLT1) {
      /* CAUTION */          printf( "\n" );
      /* CAUTION */          printf( "***                                        \n" );
      /* CAUTION */          printf( "*** ERROR:                                 \n" );
      /* CAUTION */          printf( "*** ERROR: void normalForm()               \n" );
      /* CAUTION */          printf( "*** ERROR: Nondiagonal element in BJB^TJ   \n" );
      /* CAUTION */          printf( "*** ERROR: abs( Nx( %d, %d ) ) = %le       \n", i, j, abs(Nx(i,j)) );
      /* CAUTION */          printf( "*** ERROR:                                 \n" );
      /* CAUTION */          exit(0);
      /* CAUTION */         }
      /* CAUTION */        else Nx(i,j) = complex_zero;
      /* CAUTION */   }
 }

 B = B*Nx;

 // Some useful matrices
 complexmatrix Binv   = B.inverse();
 complexmatrix D      = Binv * A * B;
 complexmatrix Dinv   = D.inverse();

      /* CAUTION */  // A little checking and cleaning.
      /* CAUTION */  for( i = 0; i < 6; i++ ) {
      /* CAUTION */   if( fabs( abs(Dinv(i,i)) - 1.0 ) > MLT1 ) {
      /* CAUTION */    printf( "\n" );
      /* CAUTION */    printf( "***                                            \n" );
      /* CAUTION */    printf( "*** SORRY:                                     \n" );
      /* CAUTION */    printf( "*** SORRY: void normalForm()                   \n" );
      /* CAUTION */    printf( "*** SORRY: For now, I am only allowing         \n" );
      /* CAUTION */    printf( "*** SORRY: maps with an elliptic fixed point   \n" );
      /* CAUTION */    printf( "*** SORRY: at the origin.  This will be        \n" );
      /* CAUTION */    printf( "*** SORRY: loosened as soon as I'm sure        \n" );
      /* CAUTION */    printf( "*** SORRY: everything is working properly.     \n" );
      /* CAUTION */    printf( "*** SORRY:                                     \n" );
      /* CAUTION */    printf( "*** SORRY: Dinv( %d, %d ) has magnitude = %le  \n", 
      /* CAUTION */                               i,  i,            abs(Dinv(i,i)) );
      /* CAUTION */    printf( "*** SORRY:                                     \n" );
      /* CAUTION */    exit(0);
      /* CAUTION */   }
      /* CAUTION */   for( j = 0; j < 6; j++ ) {
      /* CAUTION */    if( j == i ) continue;
      /* CAUTION */    else if( abs( Dinv(i,j) ) > MLT1) {
      /* CAUTION */          printf( "\n" );
      /* CAUTION */          printf( "***                                        \n" );
      /* CAUTION */          printf( "*** ERROR:                                 \n" );
      /* CAUTION */          printf( "*** ERROR: void normalForm()               \n" );
      /* CAUTION */          printf( "*** ERROR: A horrible, inexplicable error  \n" );
      /* CAUTION */          printf( "*** ERROR: has occurred.                   \n" );
      /* CAUTION */          printf( "*** ERROR:                                 \n" );
      /* CAUTION */          exit(0);
      /* CAUTION */         }
      /* CAUTION */        else Dinv(i,j) = complex_zero;
      /* CAUTION */   }
      /* CAUTION */  }
      /* CAUTION */ 
      /* CAUTION */  for( i = 0; i < 6; i++ ) {
      /* CAUTION */   if( fabs( abs(D(i,i)) - 1.0 ) > MLT1 ) {
      /* CAUTION */    printf( "\n" );
      /* CAUTION */    printf( "***                                          \n" );
      /* CAUTION */    printf( "*** SORRY:                                   \n" );
      /* CAUTION */    printf( "*** SORRY: void normalForm()                 \n" );
      /* CAUTION */    printf( "*** SORRY: For now, I am only allowing       \n" );
      /* CAUTION */    printf( "*** SORRY: maps with an elliptic fixed point \n" );
      /* CAUTION */    printf( "*** SORRY: at the origin.  This will be      \n" );
      /* CAUTION */    printf( "*** SORRY: loosened as soon as I'm sure      \n" );
      /* CAUTION */    printf( "*** SORRY: everything is working properly.   \n" );
      /* CAUTION */    printf( "*** SORRY:                                   \n" );
      /* CAUTION */    printf( "*** SORRY: D( %d, %d ) has magnitude = %le   \n", 
      /* CAUTION */                            i,  i,                abs(D(i,i)) );
      /* CAUTION */    printf( "*** SORRY:                                   \n" );
      /* CAUTION */    exit(0);
      /* CAUTION */   }
      /* CAUTION */ 
      /* CAUTION */   for( j = 0; j < 6; j++ ) {
      /* CAUTION */    if( j == i ) continue;
      /* CAUTION */    else if( abs( D(i,j) ) > MLT1) {
      /* CAUTION */          printf( "\n" );
      /* CAUTION */          printf( "***                                        \n" );
      /* CAUTION */          printf( "*** ERROR:                                 \n" );
      /* CAUTION */          printf( "*** ERROR: void normalForm()               \n" );
      /* CAUTION */          printf( "*** ERROR: A horrible, inexplicable error  \n" );
      /* CAUTION */          printf( "*** ERROR: has occurred.                   \n" );
      /* CAUTION */          printf( "*** ERROR:                                 \n" );
      /* CAUTION */          exit(0);
      /* CAUTION */         }
      /* CAUTION */        else D(i,j) = complex_zero;
      /* CAUTION */   }
      /* CAUTION */  }


 // The original near-identity transformation
 CLieOperator     CL1( theMap );
 CLieOperator     id( "ident" );
 CLieOperator     calN = Dinv*(Binv*CL1( B*id ));


 // And the rest ...
 complex          factor;
 int              ll;

 CLieOperator     reg;
 DACtermData*     q;
 DAC              scr;

 dlist*           doc;
 dlist_iterator*  g;

 for( int k = 0; k <= maxOrder - 2; k++ ) {
  reg = calN;
  ll = 0;
  while( ll < k ) reg = N[ll++].expMap( -1.0, reg );
  reg = reg.filter( k+2, k+2 );
  N[k] = reg.filter( shear );

  doc = ( N[k] - reg ).image();
  for( i = 0; i < 6; i++ ) {
   scr.clear();
   g = new dlist_iterator( doc[i] );
   while( q = (DACtermData*) (*g)() ) {
    factor = 1.0;
    for( j = 0; j < 6; j++ ) {
      factor *= pow( 1.0 / lambda(j), q->index[j] );
    }
    factor *= lambda(i);
    q->value /= ( factor - (complex) 1.0 );
    scr.addTerm( new DACterm( *q ) );
   }
   T[k].setVariable( scr, i );
   delete g;
  }
  T[k].reset();    // ??? Probably unnecessary

  // for( i = 0; i < 6; i++ ) delete doc[i];


  // Prepare for the next order
  calN = T[k].expMap( -1.0, calN( D*T[k].expMap( 1.0, Dinv*id ) ) );
 }

}
End of normalForm.cc
