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

#include "cakit.h"

@implementation obj_varspsrecdegsps_polynomial
- check
{
  int n;
  id last;

  [super check];
  [scalarZero check];
  [termZero check];
  [monomialZero check];
  assert([scalarZero isEqual:[termZero coefficient]]);
  assert([scalarZero isEqual:[monomialZero scalar]]);
  assert([monomialZero isVariableSparse]);

  last = nil;
  n = [terms size];
  while (n--) {
    id term = [terms at:n];

    assert([term notZero]);
    if ([term isCoefficient]) {
      assert([[term coefficient] sameClass:scalarZero]);
    }
    if (last)
      assert([term compareExponents:last] < 0);
    [term check];
    last = term;
  }

  return self;
}

+ new
{
  return [self notImplemented:_cmd];
}

- _setUpScalarZero:aScalar
{
  assert([aScalar isZero]);
  assert([aScalar class_varspsrecdegsps_polynomial] == [self class]);

  aScalar = [aScalar cheapCopy];
  termZero = [Term scalar:aScalar symbol:nil exponent:0];
  aScalar = [aScalar cheapCopy];
  monomialZero = [Monomial scalar:aScalar];
  scalarZero = aScalar;
  terms = [CACollection new];

  assert([self check]);
  return self;
}

+ scalarZero:aScalar
{
  return [[super new] _setUpScalarZero:aScalar];
}

- copy
{
  int i, n;
  id new;

  /* don't use [terms copy] -> sends cheapCopy */
  new = [terms empty];
  for (n = [terms size], i = 0; i < n; i++) {
    id term = [terms at:i];

    [new add:[term copy]];
  }

  self = [self clone];
  terms = new;
  return self;
}

- deepCopy
{
  int i, n;
  id new;

  /* don't use [terms deepCopy] -> sends copy */
  new = [terms empty];
  for (n = [terms size], i = 0; i < n; i++) {
    id term = [terms at:i];

    [new add:[term deepCopy]];
  }

  self = [self clone];
  terms = new;
  return self;
}

- clear
{
  scalarZero = [scalarZero free];
  termZero = [termZero free];
  monomialZero = [monomialZero free];
  terms = [terms free];
  return [super clear];
}

- _terms  {
  return terms;
}				/* super temporal of course */

- scalarZero  {
  return scalarZero;
}
- termZero    {
  return termZero;
}
- monomialZero  {
  return monomialZero;
}

- clone
{
  self = [super clone];
  scalarZero = [scalarZero cheapCopy];
  termZero = [termZero cheapCopy];
  monomialZero = [monomialZero cheapCopy];
  terms = nil;
  return self;
}

- _terms:cltn
{
  self = [self clone];
  terms = cltn;
  return self;
}

- empty
{
  return [self _terms:[CACollection new]];
}

- scalarZero:aScalar
{
  return [self notImplemented:_cmd];
}

- scalarZero:aScalar symbols:aCltn
{
  return [self notImplemented:_cmd];
}

- emptyScalarZero:aZero
{
  id classCarrier = [aZero class_varspsrecdegsps_polynomial];

  return [classCarrier scalarZero:aZero];
}

- emptyVariableDense:aCltn
{
  id classCarrier = [scalarZero class_vardnsrecdegsps_polynomial];

  return [classCarrier scalarZero:[scalarZero cheapCopy] symbols:aCltn];
}

- emptyVariableSparse
{
  return [self empty];
}

- emptyExpanded
{
  id classCarrier = [scalarZero class_varspsexpdegsps_polynomial];

  return [classCarrier scalarZero:[scalarZero cheapCopy]];
}

- emptyRecursive
{
  return [self empty];
}

- emptyDegreeSparse
{
  return [self empty];
}

- emptyDegreeDense
{
  id classCarrier = [scalarZero class_varspsrecdegdns_polynomial];

  return [classCarrier scalarZero:[scalarZero cheapCopy]];
}

- (BOOL) isEmpty
{
  return [terms size] == 0;
}

- (BOOL) isZero
{
  return [terms size] == 0;
}

- (BOOL) isOne
{
  return [terms size] == 1 && [[terms lastElement] isOne];
}

- (BOOL) isMinusOne
{
  return [terms size] == 1 && [[terms lastElement] isMinusOne];
}

- (BOOL) sameClass:b
{
  return [super sameClass:b] && [scalarZero isEqual:[b scalarZero]];
}

- (BOOL) isEqual:b
{
  assert([self sameClass:b]);
  return [terms isEqual:[b _terms]];
}

- asScalar
{
  return ([terms size] == 1) ? [[terms lastElement] asScalar] : nil;
}

- asSymbol
{
  return ([terms size] == 1) ? [[terms lastElement] asSymbol] : nil;
}

- (int) numTerms
{
  return [terms size];
}

- eachTerm
{
  return [terms eachElementReversed];
}

- removeTerm
{
  id lt;

  assert([self checkRefCountOne] == self && [self check] == self);
  lt = [terms removeLast];
  [self invalidate];
  return lt;
}

- insertTerm:aTerm
{
  id c;

  assert([self checkRefCountOne] == self && [self check] && [aTerm check]);

  if ([aTerm isZero]) {
    [aTerm free];
    return self;
  }
  if ([aTerm symbol] || [[aTerm coefficient] sameClass:scalarZero]) {
    int n = [terms size];

    while (n--) {
      int cmp;
      id term = [terms at:n];

      cmp = [term compareExponents:aTerm];
      if (cmp == 0) {
	id sum = [term add:aTerm];

	[aTerm free];
	if ([sum isZero]) {
	  [[terms removeAt:n] free];
	  [sum free];
	  assert([self check]);
	  return [self invalidate];
	} else {
	  [[terms at:n put:sum] free];
	  assert([self check]);
	  return [self invalidate];
	}
      } else {
	if (cmp > 0) {
	  continue;
	} else {
	  [terms at:n + 1 insert:aTerm];
	  assert([self check]);
	  return [self invalidate];
	}
      }
    }
    [terms at:0 insert:aTerm];
    assert([self check]);
    return [self invalidate];
  } else {
    /* "insert" of a lifted term */
    assert([aTerm isCoefficient] && [[aTerm coefficient] isVariableSparse]);
    self = [self addSelf:[aTerm coefficient]];
    [aTerm free];
    return self;
  }
}

@end

