
/*
 * Computer Algebra Kit (c) 1993,98 by Comp.Alg.Objects.  All Rights Reserved.
 * $Id: term.m,v 1.8 1998/11/13 09:45:48 stes Exp $
 */

#include "cakit.h"

@implementation Term
- check
{
  assert(scalarZero);
  [scalarZero check];
  if (symbol)
    [symbol check];
  assert((exponent == 0 && symbol == nil) || (exponent && symbol));
  assert(coefficient);
  [coefficient check];
  if ([coefficient differentClass:scalarZero]) {
    assert([[coefficient scalarZero] sameClass:scalarZero]);
    if ([coefficient isVariableSparse]) {
      if (symbol) {
	id z = [coefficient asScalar];

	assert(z == nil || [z differentClass:scalarZero]);
	assert([coefficient compareSymbols:self] < 0);
      } else {
	/* symbol nil might occur after derive, divide etc
	 * when the exponent drops to zero
	 * it's a polynomial lifted to a term
	 * but this case does *NOT* occur inside a varsps polynomial
	 */
      }
    } else {
      /* don't compare wrt to alphabetic in vardns case */
      assert(symbol == nil || symbol != nil);
    }
  }
  return self;
}


- _setUpScalarZero:aZero coefficient:aCoefficient symbol:aSymbol exponent:(int)anExponent
{
  scalarZero = aZero;
  if ([aZero notZero])
    [self error:"Scalar must be zero"];
  coefficient = aCoefficient;
  exponent = anExponent;
  if (exponent == 0 && symbol != nil)
    [self error:"Symbol must be nil"];
  symbol = aSymbol;
  assert([self check]);
  return self;
}

- scalarZero:aScalar coefficient:aCoefficient symbol:aSymbol exponent:(int)anExponent
{
  return [self notImplemented:_cmd];
}

+ scalarZero:aZero coefficient:aCoefficient symbol:aSymbol exponent:(int)anExponent
{
  return [[super new] _setUpScalarZero:aZero coefficient:aCoefficient symbol:aSymbol exponent:anExponent];
}

- scalar:aScalar symbol:aSymbol exponent:(int)anExponent
{
  return [self notImplemented:_cmd];
}

+ scalar:aScalar symbol:aSymbol exponent:(int)anExponent
{
  return [self scalarZero:[aScalar zero] coefficient:aScalar symbol:aSymbol exponent:anExponent];
}

+ coefficient:aCoefficient symbol:aSymbol exponent:(int)anExponent
{
  id aZero = [[aCoefficient scalarZero] cheapCopy];

  return [self scalarZero:aZero coefficient:aCoefficient symbol:aSymbol exponent:anExponent];
}

- copy
{
  self = [super copy];
  scalarZero = [scalarZero cheapCopy];
  if ([coefficient sameClass:scalarZero]) {
    coefficient = [coefficient cheapCopy];
  } else {
    coefficient = [coefficient copy];
  }
  if (symbol)
    symbol = [symbol cheapCopy];
  return self;
}
- deepCopy
{
  self = [super deepCopy];
  scalarZero = [scalarZero deepCopy];
  coefficient = [coefficient deepCopy];
  if (symbol)
    symbol = [symbol deepCopy];
  return self;
}
- clone
{
  self = [super clone];
  scalarZero = [scalarZero cheapCopy];
  coefficient = nil;
  symbol = nil;
  return self;
}

- clear
{
  scalarZero = [scalarZero free];
  coefficient = [coefficient free];
  if (symbol)
    symbol = [symbol free];
  return [super clear];
}

- coefficient:aCoefficient symbol:aSymbol exponent:(int)anExponent
{
  self = [self clone];
  coefficient = aCoefficient;
  symbol = aSymbol;
  exponent = anExponent;
  assert([self check]);
  return self;
}

- coefficient:aCoefficient exponent:(int)anExponent
{
  if (exponent) {
    assert([symbol check]);
    return [self coefficient:aCoefficient symbol:[symbol cheapCopy] exponent:anExponent];
  } else {
    assert(symbol == nil);
    if (anExponent) {
      return [self error:""];
    } else {
      return [self coefficient:aCoefficient symbol:nil exponent:0];
    }
  }
}

- coefficient:aCoefficient
{
  return [self notImplemented:_cmd];
}

- symbol:aSymbol exponent:(int)anExponent
{
  return [self notImplemented:_cmd];
}

- (BOOL)sameClass:b
{
  return isa == [b class];
}

- (BOOL)inAdditiveSemiGroup		 {
  return YES;
}
- (BOOL)inAdditiveMonoid		 {
  return YES;
}
- (BOOL)inAdditiveGroup			 {
  return YES;
}

- (BOOL)inSemiGroup			 {
  return YES;
}
- (BOOL)inMonoid			 {
  return YES;
}
- (BOOL)inGroup				 {
  return NO;
}

- (BOOL)inEuclideanDomain		 {
  return NO;
}
- (BOOL)inIntegralDomain		 {
  return NO;
}
- (BOOL)inField				 {
  return NO;
}

- (BOOL)inOrderedSet			 {
  return NO;
}
- (int)characteristic			 {
  return [scalarZero characteristic];
}


- addSymbolsTo:aCltn
{
  if ([coefficient sameClass:scalarZero]) {
    if (symbol)
      [aCltn addIfAbsent:[symbol cheapCopy]];
  } else {
    [coefficient addSymbolsTo:aCltn];
    if (symbol)
      [aCltn addIfAbsent:[symbol cheapCopy]];
  }

  return aCltn;
}

- scalarZero
{
  return scalarZero;
}

- coefficient
{
  return coefficient;
}

- (BOOL) isCoefficient
{
  return exponent == 0;
}

- symbol
{
  return symbol;
}

- (int) exponent
{
  return exponent;
}

- (int) degree
{
  return exponent;
}

- (unsigned) hash
{
  if (exponent) {
    return ([coefficient hash] & 255) + (((unsigned) exponent) << 8) + ([symbol hash] << 16);
  } else {
    return ([coefficient hash] & 255);
  }
}

- (BOOL) isEqual:b
{
  assert([self check]);
  assert([b check]);

  if (self == b) {
    return YES;
  } else {
    if ([coefficient differentClass:[b coefficient]])
      return NO;

    if (exponent) {
      return [coefficient isEqual:[b coefficient]] && exponent == [b exponent] && [symbol isEqual:[b symbol]];
    } else {
      return 0 == [b exponent] && [coefficient isEqual:[b coefficient]];
    }
  }
}

- (int) compareSymbols:aTerm
{
  /* don't check because check invokes compareSymbols
   * assert([self check]);assert([aTerm check]);
   */

  if (self == aTerm) {
    return 0;
  } else {
    if (symbol) {
      id aSymbol = [aTerm symbol];

      return (aSymbol) ? [symbol compare : aSymbol]:+1;
    } else {
      return ([aTerm symbol]) ? -1 : 0;
    }
  }
}

- (int) compareExponents:b
{
  /* don't check because check invokes compareSymbols
   * assert([self check]);assert([b check]);
   */

  if (self == b) {
    return 0;
  } else {
    int cmp = [self compareSymbols:b];

    if (cmp == 0) {
      cmp = exponent - [b exponent];
      return (cmp == 0) ? 0 : ((cmp < 0) ? -1 : +1);
    } else {
      return cmp;
    }
  }
}


- (int) intValue
{
  if (exponent) {
    [self error:"-intValue: term not intValue"];
    return 0;
  } else {
    return [coefficient intValue];
  }
}

- intValue:(int)aValue
{
  id c = [coefficient intValue:aValue];

  return [self coefficient:c symbol:nil exponent:0];
}

- (float) floatValue
{
  if (exponent) {
    [self error:"-floatValue: term not floatValue"];
    return 0;
  } else {
    return [coefficient floatValue];
  }
}

- floatValue:(float)aValue
{
  id c = [coefficient floatValue:aValue];

  return [self coefficient:c symbol:nil exponent:0];
}

- asScalar
{
  if (exponent) {
    return nil;
  } else {
    if ([coefficient sameClass:scalarZero]) {
      return [coefficient cheapCopy];
    } else {
      return [coefficient asScalar];
    }
  }
}

- scalar:aScalar
{
  if ([coefficient sameClass:scalarZero]) {
    assert([scalarZero sameClass:aScalar]);
    return [self coefficient:aScalar symbol:nil exponent:0];
  } else {
    return [self coefficient:[coefficient scalar:aScalar] symbol:nil exponent:0];
  }
}

- asSymbol
{
  if (exponent == 0) {
    if ([coefficient sameClass:scalarZero]) {
      return nil;
    } else {
      return [coefficient asSymbol];
    }
  }
  if (exponent == 1) {
    return ([coefficient isOne]) ? [symbol cheapCopy] : nil;
  }
  return nil;
}

- symbol:aSymbol
{
  /* this method must be used with termOne or termZero */
  assert([self isZero] || [self isOne]);
  assert([aSymbol check]);

  if (symbol) {
    if ([symbol isEqual:aSymbol]) {
      id c = [coefficient one];

      return [self coefficient:c symbol:aSymbol exponent:1];
    } else {
      id c = [coefficient symbol:aSymbol];

      return (c) ? [self coefficient : c symbol:nil exponent:0]:nil;
    }
  } else {
    id c = [coefficient one];

    return [self coefficient:c symbol:aSymbol exponent:1];
  }
}

- asNumerical
{
  id s = [scalarZero asNumerical];
  id c = [coefficient asNumerical];

  return [isa scalarZero:s coefficient:c symbol:[symbol cheapCopy] exponent:exponent];
}

- asModp:(unsigned short)p
{
  id s = [scalarZero asModp:p];
  id c = [coefficient asModp:p];

  return [isa scalarZero:s coefficient:c symbol:[symbol cheapCopy] exponent:exponent];
}


- zero
{
  return [self coefficient:[coefficient zero] symbol:nil exponent:0];
}

- (BOOL) isZero
{
  return [coefficient isZero];
}

- (BOOL) isOpposite:b
{
  assert([self check]);
  assert([b check]);

  if (exponent) {
    if ([coefficient differentClass:[b coefficient]])
      return NO;

    return exponent == [b exponent] && [symbol isEqual:[b symbol]] && [coefficient isOpposite:[b coefficient]];
  } else {
    return 0 == [b exponent] && nil == [b symbol] && [coefficient isOpposite:[b coefficient]];
  }
}

- negate
{
  return [self coefficient:[coefficient negate] exponent:exponent];
}

- double
{
  return [self coefficient:[coefficient double] exponent:exponent];
}

- add:b
{
  assert([self check]);
  assert([b check]);

  if (self == b) {
    return [self double];
  } else {
    int e;
    id c, s, z;

    [self checkSameClass:b];
    if ([self isZero])
      return [b cheapCopy];
    if ([b isZero])
      return [self cheapCopy];

    if (exponent) {
      assert(exponent == [b exponent] && [symbol isEqual:[b symbol]]);
      s = [symbol cheapCopy];
      e = exponent;
    } else {
      assert(exponent == [b exponent]);
      s = nil;
      e = 0;
    }

    if ([coefficient sameClass:scalarZero]) {
      if ([[b coefficient] sameClass:scalarZero]) {
	c = [coefficient add:[b coefficient]];
      } else {
	c = [[b coefficient] addScalar:coefficient];
      }
    } else {
      if ([[b coefficient] sameClass:scalarZero]) {
	c = [coefficient addScalar:[b coefficient]];
      } else {
	c = [coefficient add:[b coefficient]];
	if ([c isVariableSparse] && (z = [c asScalar]))
	  c = idReplace(c, z);
      }
    }

    return [self coefficient:c symbol:s exponent:e];
  }
}

- subtract:b
{
  assert([self check]);
  assert([b check]);

  if (self == b) {
    return [self zero];
  } else {
    int e;
    id c, s, z;

    [self checkSameClass:b];
    if ([self isZero])
      return [b negate];
    if ([b isZero])
      return [self cheapCopy];

    if (exponent) {
      assert(exponent == [b exponent] && [symbol isEqual:[b symbol]]);
      s = [symbol cheapCopy];
      e = exponent;
    } else {
      assert(exponent == [b exponent]);
      s = nil;
      e = 0;
    }

    if ([coefficient sameClass:scalarZero]) {
      if ([[b coefficient] sameClass:scalarZero]) {
	c = [coefficient subtract:[b coefficient]];
      } else {
	c = [[[b coefficient] subtractScalar:coefficient] negateSelf];
      }
    } else {
      if ([[b coefficient] sameClass:scalarZero]) {
	c = [coefficient subtractScalar:[b coefficient]];
      } else {
	c = [coefficient subtract:[b coefficient]];
	if ([c isVariableSparse] && (z = [c asScalar]))
	  c = idReplace(c, z);
      }
    }

    return [self coefficient:c symbol:s exponent:e];
  }
}


- one
{
  assert([self check]);
  return [self coefficient:[coefficient one] symbol:nil exponent:0];
}

- (BOOL) isOne
{
  assert([self check]);
  return [coefficient isOne] && exponent == 0;
}

- (BOOL) isMinusOne
{
  assert([self check]);
  return [coefficient isMinusOne] && exponent == 0;
}

- square
{
  return [self coefficient:[coefficient square] exponent:exponent + exponent];
}

- inverse
{
  id c = [coefficient inverse];

  return (c) ? [self coefficient : c exponent:-exponent]:nil;
}

- multiplyScalar:b
{
  id c;

  assert([self check]);
  assert([b check]);

  if ([b isZero])
    return [self zero];
  if ([b isOne])
    return [self cheapCopy];
  if ([b isMinusOne])
    return [self negate];

  if ([coefficient sameClass:scalarZero]) {
    c = [coefficient multiply:b];
  } else {
    c = [coefficient multiplyScalar:b];
  }

  return [self coefficient:c exponent:exponent];
}

- multiplyCoefficient:b
{
  assert([self check] && [b check]);

  if ([b isZero])
    return [self zero];
  if ([b isOne])
    return [self cheapCopy];
  if ([b isMinusOne])
    return [self negate];

  return [self coefficient:[coefficient multiply:b] exponent:exponent];
}

- varspsMultiplyCoefficient:b
{
  assert([self check] && [b check] && [b isVariableSparse]);

  if ([b isZero])
    return [self zero];
  if ([b isOne])
    return [self cheapCopy];
  if ([b isMinusOne])
    return [self negate];

  if ([coefficient sameClass:scalarZero]) {
    id z, c = [b multiplyScalar:coefficient];

    if (z = [c asScalar])
      c = idReplace(c, z);
    return [self coefficient:c exponent:exponent];
  } else {
    id z, c = [coefficient multiply:b];

    if (z = [c asScalar])
      c = idReplace(c, z);
    return [self coefficient:c exponent:exponent];
  }
}

- multiply:b
{
  assert([self check]);
  assert([b check]);

  if (self == b) {
    return [self square];
  } else {
    int e;
    id c, s;

    [self checkSameClass:b];
    if ([self isZero] || [b isZero])
      return [self zero];
    if ([self isOne])
      return [b cheapCopy];
    if ([b isOne])
      return [self cheapCopy];

    if (e = exponent + [b exponent]) {
      if (exponent) {
	if ([b exponent])
	  assert([symbol isEqual:[b symbol]]);
	s = [symbol cheapCopy];
      } else {
	s = ([b exponent]) ? [[b symbol] cheapCopy] : nil;
      }
    } else {
      s = nil;
    }

    if ([coefficient sameClass:scalarZero]) {
      id z;

      if ([[b coefficient] sameClass:scalarZero]) {
	c = [coefficient multiply:[b coefficient]];
      } else {
	c = [[b coefficient] multiplyScalar:coefficient];
	if ([c isVariableSparse] && (z = [c asScalar]))
	  c = idReplace(c, z);
      }
    } else {
      id z;

      if ([[b coefficient] sameClass:scalarZero]) {
	c = [coefficient multiplyScalar:[b coefficient]];
	if ([c isVariableSparse] && (z = [c asScalar]))
	  c = idReplace(c, z);
      } else {
	c = [coefficient multiply:[b coefficient]];
	if ([c isVariableSparse] && (z = [c asScalar]))
	  c = idReplace(c, z);
      }
    }

    return (c) ? [self coefficient : c symbol:s exponent:e]:nil;
  }
}

- divideScalar:b
{
  id c;

  assert([self check]);
  assert([b check]);

  if ([b isZero])
    return nil;
  if ([b isOne])
    return [self cheapCopy];
  if ([b isMinusOne])
    return [self negate];

  if ([coefficient sameClass:scalarZero]) {
    c = [coefficient divide:b];
  } else {
    c = [coefficient divideScalar:b];
  }

  return (c) ? [self coefficient : c exponent:exponent]:nil;
}

- divideCoefficient:b
{
  id c;

  assert([self check] && [b check]);

  if ([b isZero])
    return nil;
  if ([b isOne])
    return [self cheapCopy];
  if ([b isMinusOne])
    return [self negate];

  c = [coefficient divide:b];
#ifndef NDEBUG
  if (c) {
    id d = [c multiply:b];

    assert([d isEqual:coefficient]);
    [d free];
  }
#endif
  return (c) ? [self coefficient : c exponent:exponent]:nil;
}

- varspsDivideCoefficient:b
{
  assert([self check] && [b check] && [b isVariableSparse]);

  if ([b isZero])
    return nil;
  if ([b isOne])
    return [self cheapCopy];
  if ([b isMinusOne])
    return [self negate];

  if ([coefficient sameClass:scalarZero]) {
    return nil;
  } else {
    id z, c = [coefficient divide:b];

    if (z = [c asScalar])
      c = idReplace(c, z);
    return [self coefficient:c exponent:exponent];
  }
}

- subtractExponents:b
{
  int e, bexponent = [b exponent];

  if (e = exponent - bexponent) {
    if (e > 0) {
      id c, s;

      if (exponent) {
	if (bexponent)
	  assert([symbol isEqual:[b symbol]]);
	s = [symbol cheapCopy];
      } else {
	s = (bexponent) ? [[b symbol] cheapCopy] : nil;
      }
      c = [coefficient cheapCopy];
      return [self coefficient:c symbol:s exponent:e];
    } else {
      return nil;
    }
  } else {
    id c = [coefficient cheapCopy];

    return [self coefficient:c symbol:nil exponent:0];
  }
}

- divide:b
{
  assert([self check]);
  assert([b check]);

  if ([b isZero])
    return nil;

  if (self == b) {
    return [self one];
  } else {
    int e;
    id c, s;

    [self checkSameClass:b];
    if ([self isZero])
      return [self zero];
    if ([self isOne])
      return [self cheapCopy];
    if ([b isOne])
      return [self cheapCopy];

    e = exponent - [b exponent];

    if ([coefficient sameClass:scalarZero]) {
      if ([[b coefficient] sameClass:scalarZero]) {
	c = [coefficient divide:[b coefficient]];
      } else {
	return nil;
      }
    } else {
      if ([[b coefficient] sameClass:scalarZero]) {
	id z;

	c = [coefficient divideScalar:[b coefficient]];
	if ([c isVariableSparse] && (z = [c asScalar]))
	  c = idReplace(c, z);
      } else {
	id z;

	c = [coefficient divide:[b coefficient]];
	if ([c isVariableSparse] && (z = [c asScalar]))
	  c = idReplace(c, z);
      }
    }

    if (c) {
      if (e) {
	if (exponent) {
	  if ([b exponent])
	    assert([symbol isEqual:[b symbol]]);
	  s = [symbol cheapCopy];
	} else {
	  s = ([b exponent]) ? [[b symbol] cheapCopy] : nil;
	}
      } else {
	s = nil;
      }
      return [self coefficient:c symbol:s exponent:e];
    } else {
      return nil;
    }
  }
}


- power:(int)n
{
  id c = [coefficient power:n];

  return [self coefficient:c exponent:exponent * n];
}

- root:(int)n
{
  id r = [coefficient root:n];

  if (r && exponent % n == 0) {
    return [self coefficient:r exponent:exponent / n];
  } else {
    return nil;
  }
}

- squareRoot
{
  id r = [coefficient squareRoot];

  if (r && exponent % 2 == 0) {
    return [self coefficient:r exponent:exponent / 2];
  } else {
    return nil;
  }
}


- frobenius
{
  id r = [coefficient frobenius];
  int n = [coefficient characteristic];

  return [self coefficient:r exponent:exponent * n];
}

- frobeniusInverse
{
  int n = [coefficient characteristic];
  id r = [coefficient frobeniusInverse];

  if (r && exponent % n == 0) {
    return [self coefficient:r exponent:exponent / n];
  } else {
    return nil;
  }
}


- derive
{
  if (exponent == 1) {
    id c = [coefficient cheapCopy];

    return [self coefficient:c symbol:nil exponent:0];
  }
  if (exponent > 1) {
    id c = [coefficient multiplyIntValue:exponent];
    id s = [symbol cheapCopy];

    return [self coefficient:c symbol:s exponent:exponent - 1];
  }
  return [self zero];
}

- integrate
{
  if (exponent) {
    id c = [coefficient divideIntValue:exponent];

    return (c) ? [self coefficient : c exponent:exponent + 1]:nil;
  } else {
    return [self zero];
  }
}

- substitute:(STR)aSymbol by:aPolynomial
{
  if ([coefficient sameClass:scalarZero]) {
    return [self cheapCopy];
  } else {
    id c = [coefficient substitute:aSymbol by:aPolynomial];

    return [self coefficient:c exponent:exponent];
  }
}

- makeDegreeDense
{
  if ([coefficient sameClass:scalarZero]) {
    return [self cheapCopy];
  } else {
    id c = [coefficient makeDegreeDense];
    id s = (symbol) ? [symbol cheapCopy] : nil;

    return [self coefficient:c symbol:s exponent:exponent];
  }
}

- makeDegreeSparse
{
  if ([coefficient sameClass:scalarZero]) {
    return [self cheapCopy];
  } else {
    id c = [coefficient makeDegreeSparse];
    id s = (symbol) ? [symbol cheapCopy] : nil;

    return [self coefficient:c symbol:s exponent:exponent];
  }
}

- changeRepresentationTo:aPrototype
{
  id new;

  assert([aPrototype isExpanded] || [aPrototype isRecursive]);

  if ([coefficient sameClass:scalarZero]) {
    new = [aPrototype scalar:[coefficient cheapCopy]];
    if (exponent) {
      id x = [aPrototype symbol:[symbol cheapCopy]];

      x = [x powerSelf:exponent];
      new = [new multiplySelf:x];
      [x free];
    }
  } else {
    new = [coefficient changeRepresentationTo:aPrototype];
    if (exponent) {
      id x = [aPrototype symbol:[symbol cheapCopy]];

      x = [x powerSelf:exponent];
      new = [new multiplySelf:x];
      [x free];
    }
  }

  return new;
}

- makeVariableSparse
{
  if ([coefficient sameClass:scalarZero]) {
    return [self cheapCopy];
  } else {
    id z;
    id c = [coefficient makeVariableSparse];
    id s = (symbol) ? [symbol cheapCopy] : nil;

    if (z = [c asScalar])
      c = idReplace(c, z);
    return [self coefficient:c symbol:s exponent:exponent];
  }
}


- (BOOL) printsLeadingSign
{
  /* the structure of this method must match printing ! */

  if ([self isZero]) {
    return NO;
  } else {
    if ([coefficient isOne])
      return NO;
    if ([coefficient isMinusOne])
      return YES;
    if (exponent) {
      return ([coefficient printsSum]) ? NO : [coefficient printsLeadingSign];
    } else {
      return [coefficient printsLeadingSign];
    }
  }
}

- (BOOL) printsSum
{
  /* the structure of this method must match printing ! */

  if ([self isZero]) {
    return NO;
  } else {
    if ([coefficient isOne])
      return NO;
    if ([coefficient isMinusOne])
      return NO;
    if (exponent) {
      return NO;
    } else {
      return [coefficient printsSum];
    }
  }
}

- (BOOL) printsProduct
{
  /* the structure of this method must match printing ! */

  if ([self isZero]) {
    return NO;
  } else {
    if ([coefficient isOne])
      return YES;
    if ([coefficient isMinusOne])
      return YES;
    if (exponent) {
      return ([coefficient printsSum]) ? YES : [coefficient printsProduct];
    } else {
      return [coefficient printsProduct];
    }
  }
}

- printOn:(IOD)aFile
{
  if ([coefficient isZero]) {
    fprintf(aFile, "0");
    return self;
  }
  if ([coefficient isOne]) {
    if (exponent) {
      if (exponent != 1) {
	if ([symbol printsProduct] || [symbol printsSum] || [symbol printsLeadingSign]) {
	  fprintf(aFile, "(");
	  [symbol printOn:aFile];
	  fprintf(aFile, ")");
	} else {
	  [symbol printOn:aFile];
	}
	fprintf(aFile, "^%i", exponent);
      } else {
	[symbol printOn:aFile];
      }
      return self;
    } else {
      fprintf(aFile, "1");
      return self;
    }
  }
  if ([coefficient isMinusOne]) {
    if (exponent) {
      fprintf(aFile, "-");
      if (exponent != 1) {
	if ([symbol printsProduct] || [symbol printsSum] || [symbol printsLeadingSign]) {
	  fprintf(aFile, "(");
	  [symbol printOn:aFile];
	  fprintf(aFile, ")");
	} else {
	  [symbol printOn:aFile];
	}
	fprintf(aFile, "^%i", exponent);
      } else {
	[symbol printOn:aFile];
      }
      return self;
    } else {
      fprintf(aFile, "-1");
      return self;
    }
  }
  if (exponent) {
    if ([coefficient printsSum]) {
      fprintf(aFile, "(");
      [coefficient printOn:aFile];
      fprintf(aFile, ")");
    } else {
      [coefficient printOn:aFile];
    }

    fprintf(aFile, " ");

    if (exponent != 1) {
      if ([symbol printsProduct] || [symbol printsSum] || [symbol printsLeadingSign]) {
	fprintf(aFile, "(");
	[symbol printOn:aFile];
	fprintf(aFile, ")");
      } else {
	[symbol printOn:aFile];
      }
      fprintf(aFile, "^%i", exponent);
    } else {
      [symbol printOn:aFile];
    }

    return self;
  } else {
    [coefficient printOn:aFile];
    return self;
  }
}


- fileOutOn:aFiler
{
  [super fileOutOn:aFiler];
  [aFiler fileOut:&exponent type:'i'];
  return self;
}

- fileInFrom:aFiler
{
  [super fileInFrom:aFiler];
  [aFiler fileIn:&exponent type:'i'];
  return self;
}

@end

