gt: 						throw( new RuntimeException( "Internal Error" ) );
context: 
  
  
  
  
  //$$strtCprt
  /**
  * Simple Algebra 
  * 
  * Copyright (C) 2014 Thornton Green
  * 
  * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 
  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  * You should have received a copy of the GNU General Public License along with this program; if not, 
  * see <http://www.gnu.org/licenses>.
  * Additional permission under GNU GPL version 3 section 7
  *
  */
  //$$endCprt
  
  
  
  
  
  package test_simplealgebra;
  
  import java.io.PrintStream;
  import java.math.BigInteger;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Random;
  import java.util.Map.Entry;
  
  import junit.framework.Assert;
  import junit.framework.TestCase;
  import simplealgebra.AbstractCache;
  import simplealgebra.CloneThreadCache;
  import simplealgebra.DoubleElem;
  import simplealgebra.DoubleElemFactory;
  import simplealgebra.Elem;
  import simplealgebra.NotInvertibleException;
  import simplealgebra.WriteBigIntegerCache;
  import simplealgebra.WriteElemCache;
  import simplealgebra.algo.NewtonRaphsonSingleElem;
  import simplealgebra.bigfixedpoint.WritePrecisionCache;
  import simplealgebra.ddx.PartialDerivativeOp;
  import simplealgebra.et.EinsteinTensorElem;
  import simplealgebra.et.EinsteinTensorElemFactory;
  import simplealgebra.stelem.Nelem;
  import simplealgebra.stelem.Stelem;
  import simplealgebra.symbolic.MultiplicativeDistributionRequiredException;
  import simplealgebra.symbolic.SCacheKey;
  import simplealgebra.symbolic.SymbolicElem;
  import simplealgebra.symbolic.SymbolicElemFactory;
  import simplealgebra.symbolic.SymbolicReduction;
  
  
  
  
  /**
   * Tests the ability to numerically evaluate the differential equation <math display="inline">
   * <mrow>
   *  <mfrac>
   *    <mrow>
   *      <msup>
   *              <mo>&PartialD;</mo>
   *            <mn>2</mn>
   *      </msup>
   *    </mrow>
   *    <mrow>
   *      <mo>&PartialD;</mo>
   *      <msup>
   *              <mi>x</mi>
   *            <mn>2</mn>
   *      </msup>
   *    </mrow>
   *  </mfrac>
   *  <mi>&phi;</mi>
   *  <mo>-</mo>
   *  <mfrac>
   *    <mrow>
   *      <mn>1</mn>
   *    </mrow>
   *    <mrow>
   *      <msup>
   *              <mi>c</mi>
   *            <mn>2</mn>
   *      </msup>
   *    </mrow>
   *  </mfrac>
   *  <mfrac>
   *    <mrow>
   *      <msup>
   *              <mo>&PartialD;</mo>
   *            <mn>2</mn>
   *      </msup>
   *    </mrow>
   *    <mrow>
   *      <mo>&PartialD;</mo>
   *      <msup>
   *              <mi>t</mi>
   *            <mn>2</mn>
   *      </msup>
   *    </mrow>
   *  </mfrac>
   *  <mi>&phi;</mi>
   *  <mo>=</mo>
   *  <mn>0</mn>
   * </mrow>
   * </math>
   *
   * in dimensions (x, t) where "c" is an arbitrary constant.  Uses JUnit ( <A href="http://junit.org">http://junit.org</A> ).
   *
   * This documentation should be viewed using Firefox version 33.1.1 or above.
   * 
   * @author thorngreen
   *
   */
  public class TestStelemA extends TestCase {
  	
  	/**
  	 * Temp step size in the T-direction.
  	 */
  	protected static final int NSTPT = 1;
  	
  	
  	/**
  	 * Temp step size in the X-direction.
  	 */
  	protected static final int NSTPX = 1;
  	
  	
  	
  	/**
  	 * Temporary array in which to generate Newton-Raphson solutions.
  	 * <p>0 = T
  	 * <p>1 = X
  	 */
  	private static double[][] tempArray = new double[ NSTPT * 2 + 1 ][ NSTPX * 2 + 1 ];
  	
  	
  	
  	/**
  	 * Given a change calculated by a Newton-Raphson iteration,
  	 * applies the change to the temp array.
  	 * 
  	 * @param dbl The change to apply to the temp array.
  	 */
  	protected static void performIterationUpdate( DoubleElem dbl )
  	{
  		tempArray[ NSTPT * 2 ][ NSTPX ] += dbl.getVal();
  	}
  	
  	
  	/**
  	 * The iteration cache value.
  	 */
  	protected static double iterationValueCache = 0.0;
  	
  	
  	/**
  	 * Places the current iteration value in the cache.
  	 */
  	protected static void cacheIterationValue()
  	{
  		iterationValueCache = tempArray[ NSTPT * 2 ][ NSTPX ];
  	}
  	
  	
  	/**
  	 * Sets the current iteration value to the value in the cache.
  	 */
  	protected static void retrieveIterationValue()
  	{
  		tempArray[ NSTPT * 2 ][ NSTPX ] = iterationValueCache;
  	}
  	
  	
  	/**
  	 * Returns the result of the Newton-Raphson iterations
  	 * from the temp array.
  	 * 
  	 * @return The value in the temp array.
  	 */
  	protected static double getUpdateValue()
  	{
  		return( tempArray[ NSTPT * 2 ][ NSTPX ] );
  	}
  	
  	
  	
  	/**
  	 * Test array used to verify that the entire temp array has been filled.
  	 */
  	private static int[][] spatialAssertArray = new int[ NSTPT * 2 + 1 ][ NSTPX * 2 + 1 ];
  	
  	
  	
  	/**
  	 * Clears the test array used to verify that the entire temp array has been filled.
  	 */
  	protected static void clearSpatialAssertArray( )
  	{
  		for( int ta = -NSTPT ; ta < NSTPT + 1 ; ta++ )
  		{
  			for( int xa = -NSTPX ; xa < NSTPX + 1 ; xa++ )
  			{
  				spatialAssertArray[ ta + NSTPT ][ xa + NSTPX ] = 0;
  			}
  		}
  	}
  	
  	
  	
  	/**
  	 * Cache for symbolic constants.
  	 * 
  	 * @author tgreen
  	 *
  	 */
  	private static class SymbolicConstCache
  	{
  		
  		/**
  		 * Map representing the cache.
  		 */
  		protected static HashMap<Double,SymbolicConst> map = new HashMap<Double,SymbolicConst>();
  		
  		/**
  		 * Returns a cached SymbolicConst representing a DoubleElem.
  		 * 
  		 * @param in The DoubleElem to be represented.
  		 * @param _fac The factory for DoubleElem instances.
  		 * @return The cached SymbolicConst.
  		 */
  		public static SymbolicConst get(  DoubleElem in , DoubleElemFactory _fac )
  		{
  			SymbolicConst cnst = map.get( in.getVal() );
  			if( cnst == null )
  			{
  				cnst = new SymbolicConst( in , _fac );
  				map.put( in.getVal() , cnst );
  			}
  			return( cnst );
  		}
  		
  		/**
  		 * Clears the cache.
  		 */
  		public static void clearCache()
  		{
  			map.clear();
  		}
  		
  	}
  	
  	
  	
  	/**
  	 * Node representing an ordinate of the coordinate space.
  	 * 
  	 * @author thorngreen
  	 *
  	 */
  	private static class Ordinate extends SymbolicElem<DoubleElem, DoubleElemFactory>
  	{
  		/**
  		 * The number of the ordinate.
  		 */
  		private int col;
  
  		/**
  		 * Constructs the node.
  		 * 
  		 * @param _fac The factory for the enclosed type.
  		 * @param _col The number of the ordinate.
  		 */
  		public Ordinate(DoubleElemFactory _fac, int _col) {
  			super(_fac);
  			col = _col;
  		}
  
  		@Override
  		public DoubleElem eval( HashMap<? extends Elem<?,?>,? extends Elem<?,?>> implicitSpace ) throws NotInvertibleException,
  				MultiplicativeDistributionRequiredException {
  			throw( new RuntimeException( "NotSupported" ) );
  		}
  		
  		@Override
  		public DoubleElem evalCached(
  				HashMap<? extends Elem<?, ?>, ? extends Elem<?, ?>> implicitSpace,
  				HashMap<SCacheKey<DoubleElem, DoubleElemFactory>, DoubleElem> cache)
  				throws NotInvertibleException,
  				MultiplicativeDistributionRequiredException {
  			throw( new RuntimeException( "NotSupported" ) );
  		}
  
  		@Override
  		public DoubleElem evalPartialDerivative(ArrayList<? extends Elem<?, ?>> withRespectTo , HashMap<? extends Elem<?,?>,? extends Elem<?,?>> implicitSpace)
  				throws NotInvertibleException,
  				MultiplicativeDistributionRequiredException {
  			throw( new RuntimeException( "NotSupported" ) );
  		}
  		
  		@Override
  		public DoubleElem evalPartialDerivativeCached(
  				ArrayList<? extends Elem<?, ?>> withRespectTo,
  				HashMap<? extends Elem<?, ?>, ? extends Elem<?, ?>> implicitSpace,
  				HashMap<SCacheKey<DoubleElem, DoubleElemFactory>, DoubleElem> cache)
  				throws NotInvertibleException,
  				MultiplicativeDistributionRequiredException {
  			throw( new RuntimeException( "NotSupported" ) );
  		}
  
  		@Override
  		public String writeDesc(
  				WriteElemCache<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>> cache,
  				PrintStream ps) {
  			String st = cache.get( this );
  			if( st == null )
  			{
  				final String sta = fac.writeDesc( (WriteElemCache<DoubleElem,DoubleElemFactory>)( cache.getInnerCache() ) , ps);
  				st = cache.getIncrementVal();
  				cache.put(this, st);
  				ps.print( Ordinate.class.getSimpleName() );
  				ps.print( " " );
  				ps.print( st );
  				ps.print( " = new " );
  				ps.print( Ordinate.class.getSimpleName() );
  				ps.print( "( " );
  				ps.print( sta );
  				ps.print( " , " );
  				ps.print( col );
  				ps.println( " );" );
  			}
  			return( st );
  		}
  		
  		@Override
  		public boolean symbolicEquals( SymbolicElem<DoubleElem,DoubleElemFactory> b )
  		{
  			if( b instanceof Ordinate )
  			{
  				return( col == ( (Ordinate) b ).col );
  			}
  			return( false );
  		}
  		
  		@Override
  		public boolean equals( Object b )
  		{
  			if( b instanceof Ordinate )
  			{
  				return( col == ( (Ordinate) b ).col );
  			}
  			return( false );
  		}
  		
  		@Override
  		public int hashCode()
  		{
  			return( col );
  		}
  		
  		/**
  		 * Returns the number of the ordinate.
  		 * 
  		 * @return The number of the ordinate.
  		 */
  		public int getCol() {
  			return col;
  		}
  		
  	}
  	
  	
  	/**
  	 * A symbolic elem representing a constant value
  	 * at the base Newton-Raphson evaluation level.
  	 * 
  	 * @author thorngreen
  	 *
  	 */
  	private static class SymbolicConst extends SymbolicReduction<DoubleElem, DoubleElemFactory>
  	{
  
  		/**
  		 * Constructs the elem.
  		 * 
  		 * @param _elem The constant to be represented.
  		 * @param _fac The factory for the constant.
  		 */
  		public SymbolicConst(DoubleElem _elem, DoubleElemFactory _fac) {
  			super(_elem, _fac);
  		}
  		
  		@Override
  		public boolean symbolicEquals( SymbolicElem<DoubleElem,DoubleElemFactory> b )
  		{
  			if( b instanceof SymbolicConst )
  			{
  				return( getElem().getVal() == ( (SymbolicConst) b ).getElem().getVal() );
  			}
  			return( false );
  		}
  		
  	}
  	
  	
  	
  	/**
  	 * An elem representing a symbolic constant at the level of mapping 
  	 * discretized approximations of the underlying differential
  	 * equation into expressions (e.g. Jacobian slopes)
  	 * for Newton-Raphson evaluations.
  	 * 
  	 * @author thorngreen
  	 *
  	 */
  	private static class StelemReduction2L extends SymbolicReduction<SymbolicElem<DoubleElem, DoubleElemFactory>,SymbolicElemFactory<DoubleElem, DoubleElemFactory>>
  	{
  
  		/**
  		 * Constructs the elem.
  		 * 
  		 * @param _elem The constant to be represented.
  		 * @param _fac The factory for the constant.
  		 */
  		public StelemReduction2L(SymbolicElem<DoubleElem, DoubleElemFactory> _elem, SymbolicElemFactory<DoubleElem, DoubleElemFactory> _fac) {
  			super(_elem, _fac);
  		}
  		
  		@Override
  		public boolean symbolicEquals( SymbolicElem<SymbolicElem<DoubleElem, DoubleElemFactory>,SymbolicElemFactory<DoubleElem, DoubleElemFactory>> b )
  		{
  			if( b instanceof StelemReduction2L )
  			{
  				return( getElem().symbolicEquals( ( (StelemReduction2L) b ).getElem() ) );
  			}
  			return( false );
  		}
  		
  	}
  	
  	
  	
  	/**
  	 * An elem representing a symbolic constant at the level
  	 * of mapping the underlying differential equation into
  	 * its discretized approximation.
  	 * 
  	 * @author thorngreen
  	 *
  	 */
  	private static class StelemReduction3L extends SymbolicReduction<
  		SymbolicElem<SymbolicElem<DoubleElem,DoubleElemFactory>,SymbolicElemFactory<DoubleElem,DoubleElemFactory>>,
  		SymbolicElemFactory<SymbolicElem<DoubleElem,DoubleElemFactory>,SymbolicElemFactory<DoubleElem,DoubleElemFactory>>>
  	{
  
  		/**
  		 * Constructs the elem.
  		 * 
  		 * @param _elem The constant to be represented.
  		 * @param _fac The factory for the constant.
  		 */
  		public StelemReduction3L(
  				SymbolicElem<SymbolicElem<DoubleElem,DoubleElemFactory>,SymbolicElemFactory<DoubleElem,DoubleElemFactory>> _elem, 
  				SymbolicElemFactory<SymbolicElem<DoubleElem,DoubleElemFactory>,SymbolicElemFactory<DoubleElem,DoubleElemFactory>> _fac) {
  			super(_elem, _fac);
  		}
  		
  		@Override
  		public boolean symbolicEquals( SymbolicElem<
  				SymbolicElem<SymbolicElem<DoubleElem,DoubleElemFactory>,SymbolicElemFactory<DoubleElem,DoubleElemFactory>>,
  				SymbolicElemFactory<SymbolicElem<DoubleElem,DoubleElemFactory>,SymbolicElemFactory<DoubleElem,DoubleElemFactory>>> b )
  		{
  			if( b instanceof StelemReduction3L )
  			{
  				return( getElem().symbolicEquals( ( (StelemReduction3L) b ).getElem() ) );
  			}
  			return( false );
  		}
  		
  	}
  	
  	
  	
  	/**
  	 * A constant coefficient with a numerator and a denominator.
  	 * 	
  	 * @author thorngreen
  	 *
  	 */
  	private static class CoeffNode
  	{
  		/**
  		 * The numerator.
  		 */
  		private SymbolicElem<DoubleElem,DoubleElemFactory> numer;
  		
  		/**
  		 * The denominator.
  		 */
  		private SymbolicElem<DoubleElem,DoubleElemFactory> denom;
  		
  		/**
  		 * Constructs the coefficient.
  		 * 
  		 * @param _numer The numerator.
  		 * @param _denom The denominator.
  		 */
  		public CoeffNode( SymbolicElem<DoubleElem,DoubleElemFactory> _numer , SymbolicElem<DoubleElem,DoubleElemFactory> _denom )
  		{
  			numer = _numer;
  			denom = _denom;
  		}
  		
  		/**
  		 * Gets the numerator.
  		 * 
  		 * @return The numerator.
  		 */
  		public SymbolicElem<DoubleElem,DoubleElemFactory> getNumer() {
  			return numer;
  		}
  		
  		/**
  		 * Gets the denominator.
  		 * 
  		 * @return The denominator.
  		 */
  		public SymbolicElem<DoubleElem,DoubleElemFactory> getDenom() {
  			return denom;
  		}
  		
  	}
  	
  	
  	/**
  	 * Elem representing the discretized equivalent 
  	 * of the value constrained by the differential equation.
  	 * 
  	 * @author thorngreen
  	 *
  	 */
  	private static class BNelem extends Nelem<DoubleElem,DoubleElemFactory,Ordinate>
  	{
  
  		/**
  		 * Constructs the elem.
  		 * 
  		 * @param _fac The factory for the enclosed type.
  		 * @param _coord Map taking implicit space terms representing ordinates to discrete ordinates of type BigInteger.
  		 */
  		public BNelem(DoubleElemFactory _fac, HashMap<Ordinate, BigInteger> _coord) {
  			super(_fac, _coord);
  		}
  		
  		
  		/**
  		 * Column indices in the discretized space.
  		 */
  		protected final int[] cols = new int[ 2 ];
  		
  		/**
  		 * Assertion booleans used to verify that all
  		 * column indices have been initialized.
  		 */
  		protected final boolean[] assertCols = new boolean[ 2 ];
  		
  
  		@Override
  		public DoubleElem eval(HashMap<? extends Elem<?, ?>, ? extends Elem<?, ?>> implicitSpace)
  				throws NotInvertibleException,
  				MultiplicativeDistributionRequiredException {
  			cols[ 0 ] = 0;
  			cols[ 1 ] = 0;
  			assertCols[ 0 ] = false;
  			assertCols[ 1 ] = false;
  			Assert.assertTrue( coord.keySet().size() == 2 );
  			for( Entry<Ordinate,BigInteger> ii : coord.entrySet() )
  			{
  				Ordinate keyCoord = ii.getKey();
  				BigInteger coordVal = ii.getValue();
  				final int offset = keyCoord.getCol() == 1 ? NSTPX : NSTPT;
  				cols[ keyCoord.getCol() ] = coordVal.intValue() + offset;
  				assertCols[ keyCoord.getCol() ] = true;
  			}
  			( spatialAssertArray[ cols[ 0 ] ][ cols[ 1 ] ] )++;
  			Assert.assertTrue( assertCols[ 0 ] );
  			Assert.assertTrue( assertCols[ 1 ] );
  			return( new DoubleElem( TestStelemA.tempArray[ cols[ 0 ] ][ cols[ 1 ] ] ) );
  		}
  		
  		@Override
  		public DoubleElem evalCached(
  				HashMap<? extends Elem<?, ?>, ? extends Elem<?, ?>> implicitSpace,
  				HashMap<SCacheKey<DoubleElem, DoubleElemFactory>, DoubleElem> cache)
  				throws NotInvertibleException,
  				MultiplicativeDistributionRequiredException {
  			return( eval( implicitSpace ) );
  		}
  
  		@Override
  		public String writeDesc(
  				WriteElemCache<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>> cache,
  				PrintStream ps) {
  			String st = cache.get( this );
  			if( st == null )
  			{
  				final String sta = fac.writeDesc( (WriteElemCache<DoubleElem, DoubleElemFactory>)( cache.getInnerCache() ) , ps);
  				cache.applyAuxCache( new WriteBigIntegerCache( cache.getCacheVal() ) );
  				final String strr = cache.getIncrementVal();
  				ps.print( "final HashMap<Ordinate, BigInteger> " );
  				ps.print( strr );
  				ps.println( " = new HashMap<Ordinate, BigInteger>();" );
  				for( Entry<Ordinate,BigInteger> ii : coord.entrySet() )
  				{
  					final String stai = ( (WriteBigIntegerCache)( cache.getAuxCache( WriteBigIntegerCache.class ) ) ).writeDesc( ii.getValue() , ps );
  					final String sl = ii.getKey().writeDesc( (WriteElemCache)( cache.getInnerCache() ) , ps);
  					ps.print( strr );
  					ps.print( ".put( " );
  					ps.print( sl );
  					ps.print( " , " );
  					ps.print( stai );
  					ps.println( " );" );
  				}
  				st = cache.getIncrementVal();
  				cache.put(this, st);
  				ps.print( BNelem.class.getSimpleName() );
  				ps.print( " " );
  				ps.print( st );
  				ps.print( " = new " );
  				ps.print( BNelem.class.getSimpleName() );
  				ps.print( "( " );
  				ps.print( sta );
  				ps.print( " , " );
  				ps.print( strr );
  				ps.println( " );" );
  			}
  			return( st );
  		}
  		
  		@Override
  		public boolean symbolicEquals( SymbolicElem<DoubleElem,DoubleElemFactory> b )
  		{
  			if( b instanceof BNelem )
  			{
  				BNelem bn = (BNelem) b;
  				if( coord.keySet().size() != bn.coord.keySet().size() )
  				{
  					return( false );
  				}
  				for( Entry<Ordinate,BigInteger> ii : coord.entrySet() )
  				{
  					Ordinate key = ii.getKey();
  					BigInteger ka = ii.getValue();
  					BigInteger kb = bn.coord.get( key );
  					if( ( ka == null ) || ( kb == null ) )
  					{
  						return( false );
  					}
  					if( !( ka.equals( kb ) ) )
  					{
  						return( false );
  					}
  				}
  				return( true );
  			}
  			return( false );
  		}
  		
  		@Override
  		public boolean equals( Object b )
  		{
  			if( b instanceof BNelem )
  			{
  				BNelem bn = (BNelem) b;
  				if( coord.keySet().size() != bn.coord.keySet().size() )
  				{
  					return( false );
  				}
  				for( Entry<Ordinate,BigInteger> ii : coord.entrySet() )
  				{
  					Ordinate key = ii.getKey();
  					BigInteger ka = ii.getValue();
  					BigInteger kb = bn.coord.get( key );
  					if( ( ka == null ) || ( kb == null ) )
  					{
  						return( false );
  					}
  					if( !( ka.equals( kb ) ) )
  					{
  						return( false );
  					}
  				}
  				return( true );
  			}
  			return( false );
  		}
  		
  		
  		@Override 
  		public int hashCode()
  		{
  			int sum = 0;
  			for( Entry<Ordinate,BigInteger> ii : coord.entrySet() )
  			{
  				Ordinate key = ii.getKey();
  				BigInteger ka = ii.getValue();
  				sum += key.hashCode();
  				sum += ka.hashCode();
  			}
  			return( sum );
  		}
  
  
  		
  	}
  	
  	
  	
  	/**
  	 * Elem representing the symbolic expression for 
  	 * the discretized equivalent
  	 * of the value constrained by the differential equation.
  	 * The partial derivatives of this elem generate
  	 * the slopes for producing Newton-Raphson iterations (e.g. the Jacobian slopes),
  	 * as opposed to partial derivatives for the underlying differential equation.
  	 * 
  	 * @author thorngreen
  	 *
  	 */	
  	private static class CNelem extends Nelem<SymbolicElem<DoubleElem,DoubleElemFactory>,
  		SymbolicElemFactory<DoubleElem,DoubleElemFactory>,Ordinate>
  	{
  
  		/**
  		 * Constructs the elem.
  		 * 
  		 * @param _fac The factory for the enclosed type.
  		 * @param _coord Map taking implicit space terms representing ordinates to discrete ordinates of type BigInteger.
  		 */
  		public CNelem(SymbolicElemFactory<DoubleElem,DoubleElemFactory> _fac, HashMap<Ordinate, BigInteger> _coord) {
  			super(_fac, _coord);
  		}
  
  		@Override
  		public SymbolicElem<DoubleElem,DoubleElemFactory> eval(HashMap<? extends Elem<?, ?>, ? extends Elem<?, ?>> implicitSpace)
  				throws NotInvertibleException,
  				MultiplicativeDistributionRequiredException {
  			return( new BNelem( fac.getFac() , coord ) );
  		}
  		
  		
  		@Override
  		public SymbolicElem<DoubleElem, DoubleElemFactory> evalCached(
  				HashMap<? extends Elem<?, ?>, ? extends Elem<?, ?>> implicitSpace,
  				HashMap<SCacheKey<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>>, SymbolicElem<DoubleElem, DoubleElemFactory>> cache)
  				throws NotInvertibleException,
  				MultiplicativeDistributionRequiredException {
  			final SCacheKey<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>> key =
  					new SCacheKey<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>>( this , implicitSpace );
  			final SymbolicElem<DoubleElem, DoubleElemFactory> iret = cache.get( key );
  			if( iret != null )
  			{
  				return( iret );
  			}
  			final SymbolicElem<DoubleElem, DoubleElemFactory> ret = eval( implicitSpace );
  			cache.put(key, ret);
  			return( ret );
  		}
  		
  		
  		@Override
  		public SymbolicElem<DoubleElem,DoubleElemFactory> evalPartialDerivative(ArrayList<? extends Elem<?, ?>> withRespectTo, HashMap<? extends Elem<?,?>,? extends Elem<?,?>> implicitSpace ) throws MultiplicativeDistributionRequiredException, NotInvertibleException {
  			if( withRespectTo.size() > 1 )
  			{
  				return( fac.zero() );
  			}
  			Iterator<? extends Elem<?,?>> it = withRespectTo.iterator();
  			CNelem wrt = (CNelem)( it.next() );
  			final boolean cond = this.symbolicEquals( wrt );
  			return( cond ? fac.identity() : fac.zero() );
  		}
  		
  		
  		@Override
  		public SymbolicElem<DoubleElem,DoubleElemFactory> evalPartialDerivativeCached(ArrayList<? extends Elem<?, ?>> withRespectTo, HashMap<? extends Elem<?,?>,? extends Elem<?,?>> implicitSpace,
  				HashMap<SCacheKey<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>>, SymbolicElem<DoubleElem, DoubleElemFactory>> cache ) throws MultiplicativeDistributionRequiredException, NotInvertibleException {
  			final SCacheKey<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>> key =
  					new SCacheKey<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>>( this , implicitSpace , withRespectTo );
  			final SymbolicElem<DoubleElem, DoubleElemFactory> iret = cache.get( key );
  			if( iret != null ) 
  			{
  				return( iret );
  			}
  			final SymbolicElem<DoubleElem, DoubleElemFactory> ret = evalPartialDerivative( withRespectTo , implicitSpace );
  			cache.put(key, ret);
  			return( ret );
  		}
  		
  		
  		@Override
  		public String writeDesc(
  				WriteElemCache<SymbolicElem<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>>, SymbolicElemFactory<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>>> cache,
  				PrintStream ps) {
  			String st = cache.get( this );
  			if( st == null )
  			{
  				final String sta = fac.writeDesc( (WriteElemCache<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>>)( cache.getInnerCache() ) , ps);
  				cache.applyAuxCache( new WriteBigIntegerCache( cache.getCacheVal() ) );
  				final String strr = cache.getIncrementVal();
  				ps.print( "final HashMap<Ordinate, BigInteger> " );
  				ps.print( strr );
  				ps.println( " = new HashMap<Ordinate, BigInteger>();" );
  				for( Entry<Ordinate,BigInteger> ii : coord.entrySet() )
  				{
  					final String stai = ( (WriteBigIntegerCache)( cache.getAuxCache( WriteBigIntegerCache.class ) ) ).writeDesc( ii.getValue() , ps );
  					final String sl = ii.getKey().writeDesc( (WriteElemCache)( cache.getInnerCache() ) , ps);
  					ps.print( strr );
  					ps.print( ".put( " );
  					ps.print( sl );
  					ps.print( " , " );
  					ps.print( stai );
  					ps.println( " );" );
  				}
  				st = cache.getIncrementVal();
  				cache.put(this, st);
  				ps.print( CNelem.class.getSimpleName() );
  				ps.print( " " );
  				ps.print( st );
  				ps.print( " = new " );
  				ps.print( CNelem.class.getSimpleName() );
  				ps.print( "( " );
  				ps.print( sta );
  				ps.print( " , " );
  				ps.print( strr );
  				ps.println( " );" );
  			}
  			return( st );
  		}
  		
  		
  		@Override
  		public boolean symbolicEquals( 
  				SymbolicElem<SymbolicElem<DoubleElem,DoubleElemFactory>,SymbolicElemFactory<DoubleElem,DoubleElemFactory>> b )
  		{
  			if( b instanceof CNelem )
  			{
  				CNelem bn = (CNelem) b;
  				if( coord.keySet().size() != bn.coord.keySet().size() )
  				{
  					return( false );
  				}
  				for( Entry<Ordinate,BigInteger> ii : coord.entrySet() )
  				{
  					Ordinate key = ii.getKey();
  					BigInteger ka = ii.getValue();
  					BigInteger kb = bn.coord.get( key );
  					if( ( ka == null ) || ( kb == null ) )
  					{
  						return( false );
  					}
  					if( !( ka.equals( kb ) ) )
  					{
  						return( false );
  					}
  				}
  				return( true );
  			}
  			return( false );
  		}
  		
  		
  	}
  	
  	
  	/**
  	 * An elem defining a partial derivative that is evaluated over the discretized space of the test.
  	 * 
  	 * @author thorngreen
  	 *
  	 */
  	private class AStelem extends Stelem<SymbolicElem<DoubleElem,DoubleElemFactory>,
  		SymbolicElemFactory<DoubleElem,DoubleElemFactory>,Ordinate>
  	{
  
  		/**
  		 * The size of the discretization.
  		 */
  		final DoubleElem h = new DoubleElem( 0.01 );
  		
  		/**
  		 * Constructs the elem.
  		 * 
  		 * @param _fac The factory for the enclosed type.
  		 */
  		public AStelem(SymbolicElemFactory<SymbolicElem<DoubleElem,DoubleElemFactory>, 
  				SymbolicElemFactory<DoubleElem,DoubleElemFactory>> _fac) {
  			super(_fac);
  		}
  
  		@Override
  		public AStelem cloneInstance() {
  			AStelem cl = new AStelem( fac );
  			for( Entry<Ordinate,BigInteger> ii : partialMap.entrySet() )
  			{
  				Ordinate key = ii.getKey();
  				cl.partialMap.put(key, ii.getValue() );
  			}
  			return( cl );
  		}
  
  		@Override
  		public SymbolicElem<SymbolicElem<DoubleElem,DoubleElemFactory>, 
  			SymbolicElemFactory<DoubleElem,DoubleElemFactory>> eval(
  				HashMap<? extends Elem<?, ?>, ? extends Elem<?, ?>> implicitSpace)
  				throws NotInvertibleException,
  				MultiplicativeDistributionRequiredException {
  			
  			
  			HashMap<Ordinate,Ordinate> imp = (HashMap<Ordinate,Ordinate>) implicitSpace;
  			
  			
  			HashMap<HashMap<Ordinate, BigInteger>,CoeffNode> spacesA = new HashMap<HashMap<Ordinate, BigInteger>,CoeffNode>();
  			
  			
  			{
  				CoeffNode cf = new CoeffNode( fac.getFac().identity() , fac.getFac().identity() );
  				HashMap<Ordinate, BigInteger> key = new HashMap<Ordinate, BigInteger>();
  				for( final Ordinate ae : imp.keySet() )
  				{
  					BigInteger valA = BigInteger.valueOf( imp.get( ae ).getCol() );
  					key.put( ae , valA );
  				}
  				spacesA.put( key , cf );
  			}
  			
  			
  			{
  				for( Entry<Ordinate,BigInteger> ii : partialMap.entrySet() )
  				{
  					HashMap<HashMap<Ordinate, BigInteger>,CoeffNode> spacesB = new HashMap<HashMap<Ordinate, BigInteger>,CoeffNode>();
  					final Ordinate ae = ii.getKey();
  					final BigInteger numDerivs = ii.getValue();
  					applyDerivativeAction( spacesA , ae , numDerivs.intValue() , h , spacesB );
  					spacesA = spacesB;
  				}
  			}
  			
  			
  			
  			SymbolicElem<SymbolicElem<DoubleElem,DoubleElemFactory>, 
  				SymbolicElemFactory<DoubleElem,DoubleElemFactory>> ret = fac.zero();
  			
  			
  			{
  				for( final Entry<HashMap<Ordinate, BigInteger>, CoeffNode> ii : spacesA.entrySet() )
  				{
  					HashMap<Ordinate, BigInteger> spaceAe = ii.getKey();
  					CoeffNode coeff = ii.getValue();
  					final CNelem an0 = 
  							new CNelem( fac.getFac() , spaceAe );
  					SymbolicElem<SymbolicElem<DoubleElem,DoubleElemFactory>,SymbolicElemFactory<DoubleElem,DoubleElemFactory>>
  						an1 = an0.mult( 
  								new StelemReduction2L( coeff.getNumer() , fac.getFac() ) );
  					SymbolicElem<SymbolicElem<DoubleElem,DoubleElemFactory>,SymbolicElemFactory<DoubleElem,DoubleElemFactory>> 
  						an2 = an1.mult( 
  								( new StelemReduction2L( coeff.getDenom() , fac.getFac() ) ).invertLeft() );
  					ret = ret.add( an2 );
  				}
  			}
  			
  			
  			return( ret );
  		}
  		
  		
  		@Override
  		public SymbolicElem<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>> evalCached(
  				HashMap<? extends Elem<?, ?>, ? extends Elem<?, ?>> implicitSpace,
  				HashMap<SCacheKey<SymbolicElem<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>>, SymbolicElemFactory<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>>>, SymbolicElem<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>>> cache)
  				throws NotInvertibleException,
  				MultiplicativeDistributionRequiredException {
  			final SCacheKey<SymbolicElem<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>>, SymbolicElemFactory<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>>> key =
  					new SCacheKey<SymbolicElem<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>>, SymbolicElemFactory<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>>>( this , implicitSpace );
  			final SymbolicElem<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>> iret = cache.get( key );
  			if( iret != null )
  			{
  				return( iret );
  			}
  			final SymbolicElem<SymbolicElem<DoubleElem, DoubleElemFactory>, SymbolicElemFactory<DoubleElem, DoubleElemFactory>> ret =
  					eval( implicitSpace );
  			cache.put(key, ret);
  			return( ret );
  		}
  		
  		
  		
  		/**
  		 * Applies a discretized approximation of a derivative using the following rules where "N"
  		 * is the number of derivatives and "h" is the size of the discretization:
  		 * <P>
  		 * <P> N = 0 -- Zero derivatives have been taken so simply return the original value of  the elem.
  		 * <P>
  		 * <P> N = 1 -- Use the first derivative formula <math display="inline">
           * <mrow>
           *   <mfrac>
           *     <mrow>
           *       <mi>F</mi><mo>&ApplyFunction;</mo>
           *       <mfenced open="(" close=")" separators=",">
           *         <mrow>
           *           <mi>x</mi>
           *           <mo>+</mo>
           *           <mi>h</mi>
           *         </mrow>
           *       </mfenced>
           *       <mo>-</mo>
           *       <mi>F</mi><mo>&ApplyFunction;</mo>
           *       <mfenced open="(" close=")" separators=",">
           *         <mrow>
           *           <mi>x</mi>
           *           <mo>-</mo>
           *           <mi>h</mi>
           *         </mrow>
           *       </mfenced>
           *     </mrow>
           *     <mrow>
           *       <mn>2</mn>
           *       <mi>h</mi>
           *     </mrow>
           *   </mfrac>
           * </mrow>
           * </math>
  		 * <P>
  		 * <P> (See http://en.wikipedia.org/wiki/Numerical_differentiation)
  		 * <P>
  		 * <P> N = 2 -- Use the second derivative formula <math display="inline">
           * <mrow>
           *   <mfrac>
           *     <mrow>
           *       <mi>F</mi><mo>&ApplyFunction;</mo>
           *       <mfenced open="(" close=")" separators=",">
           *         <mrow>
           *           <mi>x</mi>
           *           <mo>+</mo>
           *           <mi>h</mi>
           *         </mrow>
           *       </mfenced>
           *       <mo>-</mo>
           *       <mn>2</mn>
           *       <mi>F</mi><mo>&ApplyFunction;</mo>
           *       <mfenced open="(" close=")" separators=",">
           *         <mrow>
           *           <mi>x</mi>
           *         </mrow>
           *       </mfenced>
           *       <mo>+</mo>
           *       <mi>F</mi><mo>&ApplyFunction;</mo>
           *       <mfenced open="(" close=")" separators=",">
           *         <mrow>
           *           <mi>x</mi>
           *           <mo>-</mo>
           *           <mi>h</mi>
           *         </mrow>
           *       </mfenced>
           *     </mrow>
           *     <mrow>
           *       <msup>
           *               <mi>h</mi>
           *             <mn>2</mn>
           *       </msup>
           *     </mrow>
           *   </mfrac>
           * </mrow>
           * </math>
  		 * <P>
  		 * <P> (See http://en.wikipedia.org/wiki/Second_derivative)
  		 * <P>
  		 * <P> N = 3 -- Use the third derivative formula <math display="inline">
           * <mrow>
           *   <mfrac>
           *     <mrow>
           *       <mo>-</mo>
           *       <mi>F</mi><mo>&ApplyFunction;</mo>
           *       <mfenced open="(" close=")" separators=",">
           *         <mrow>
           *           <mi>x</mi>
           *           <mo>-</mo>
           *           <mn>2</mn>
           *           <mi>h</mi>
           *         </mrow>
           *       </mfenced>
           *       <mo>+</mo>
           *       <mn>2</mn>
           *       <mi>F</mi><mo>&ApplyFunction;</mo>
           *       <mfenced open="(" close=")" separators=",">
           *         <mrow>
           *           <mi>x</mi>
           *           <mo>-</mo>
           *           <mi>h</mi>
           *         </mrow>
           *       </mfenced>
           *       <mo>-</mo>
           *       <mn>2</mn>
           *       <mi>F</mi><mo>&ApplyFunction;</mo>
           *       <mfenced open="(" close=")" separators=",">
           *         <mrow>
           *           <mi>x</mi>
           *           <mo>-</mo>
           *           <mi>h</mi>
           *         </mrow>
           *       </mfenced>
           *       <mo>+</mo>
           *       <mi>F</mi><mo>&ApplyFunction;</mo>
           *       <mfenced open="(" close=")" separators=",">
           *         <mrow>
           *           <mi>x</mi>
           *           <mo>+</mo>
           *           <mn>2</mn>
           *           <mi>h</mi>
           *         </mrow>
           *       </mfenced>
           *     </mrow>
           *     <mrow>
           *       <mn>2</mn>
           *       <msup>
           *               <mi>h</mi>
           *             <mn>3</mn>
           *       </msup>
           *     </mrow>
           *   </mfrac>
           * </mrow>
           * </math>
  		 * <P>
  		 * <P> (See http://www.geometrictools.com/Documentation/FiniteDifferences.pdf)
  		 * <P>
  		 * <P> N > 3 -- Combine results from smaller values of N to build an approximation of a higher-order derivative.
  		 * 
  		 * @param implicitSpacesIn The input implicit space containing the discretized approximation function.
  		 * @param node The ordinate over which to take the derivative.
  		 * @param numDerivatives The number of derivatives to apply.
  		 * @param h The size of the discretization.
  		 * @param implicitSpacesOut The output implicit space containing the discretized approximation function with the derivatives applied.
  		 * @throws MultiplicativeDistributionRequiredException 
  		 * @throws NotInvertibleException 
  		 */
  		protected void applyDerivativeAction( HashMap<HashMap<Ordinate, BigInteger>,CoeffNode> implicitSpacesIn , 
  				Ordinate node , final int numDerivatives , DoubleElem h ,
  				HashMap<HashMap<Ordinate, BigInteger>,CoeffNode> implicitSpacesOut ) throws NotInvertibleException, MultiplicativeDistributionRequiredException
  		{
  			if( numDerivatives > 3 )
  			{
  				HashMap<HashMap<Ordinate, BigInteger>,CoeffNode> implicitSpacesMid = new HashMap<HashMap<Ordinate, BigInteger>,CoeffNode>();
  				applyDerivativeAction(implicitSpacesIn, node, 3, h, implicitSpacesMid);
  				applyDerivativeAction(implicitSpacesMid, node, numDerivatives-3, h, implicitSpacesOut);
  				return;
  			}
  			
  			for( final Entry<HashMap<Ordinate, BigInteger>,CoeffNode> ii : implicitSpacesIn.entrySet() )
  			{
  				final HashMap<Ordinate, BigInteger> implicitSpace = ii.getKey();
  				final CoeffNode coeffNodeIn = ii.getValue();
  				
  				switch( numDerivatives )
  				{
  				
  				case 0:
  					{
  						applyAdd( implicitSpace , coeffNodeIn , implicitSpacesOut );
  					}
  					break;
  				
  				case 1:
  					{
  						applyDerivativeAction1( 
  								implicitSpace , coeffNodeIn, 
  								node , h , implicitSpacesOut );
  					}
  					break;
  					
  				case 2:
  					{
  						applyDerivativeAction2( 
  								implicitSpace , coeffNodeIn, 
  								node , h , implicitSpacesOut );
  					}
  					break;
  					
  				case 3:
  					{
  						applyDerivativeAction3( 
  								implicitSpace , coeffNodeIn, 
  								node , h , implicitSpacesOut );
  					}
  					break;
  					
  				default:
  					{
  