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

#include "cakit.h"

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

  [super check];
  [scalarZero check];
  [termZero check];
  [monomialZero check];
  [monomials check];

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

    assert([monomial notZero]);
    if (last)
      assert([last compareTerms:monomial] > 0);
    last = monomial;
  }

  return self;
}

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

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

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

  scalarZero = aScalar;
  monomials = [CACollection new];

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

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

- copy
{
  int i, n;
  id new;

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

    [new add:[monomial copy]];
  }

  return [self _monomials:new];
}

- deepCopy
{
  int i, n;
  id new;

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

    [new add:[monomial deepCopy]];
  }

  return [self _monomials:new];
}

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

- _monomials  {
  return monomials;
}				/* 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];
  monomials = nil;
  return self;
}

- _monomials:cltn
{
  self = [self clone];
  monomials = cltn;
  assert([self check]);
  return self;
}

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

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

  return [classCarrier scalarZero:aZero];
}

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

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

- emptyVariableSparse
{
  return [self empty];
}

- emptyExpanded
{
  return [self empty];
}

- emptyRecursive
{
  id classCarrier = [scalarZero class_varspsrecdegsps_polynomial];

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

- emptyDegreeSparse
{
  return [self empty];
}

- emptyDegreeDense
{
  id classCarrier = [scalarZero class_varspsexpdegdns_polynomial];

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

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

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

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

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

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

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

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

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

- (int) numMonomials
{
  return [monomials size];
}

- eachMonomial
{
  return [monomials eachElementReversed];
}

- removeMonomial
{
  id lt;

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

- insertMonomial:aMonomial
{
  assert([self checkRefCountOne] == self && [self check] == self);

  if ([aMonomial isZero]) {
    [aMonomial free];
    return self;
  } else {
    int n = [monomials size];

    while (n--) {
      int cmp;
      id monomial = [monomials at:n];

      cmp = [monomial compareTerms:aMonomial];
      if (cmp == 0) {
	id sum = [monomial add:aMonomial];

	[aMonomial free];
	if ([sum isZero]) {
	  [[monomials removeAt:n] free];
	  [sum free];
	  assert([self check]);
	  return [self invalidate];
	} else {
	  [[monomials at:n put:sum] free];
	  assert([self check]);
	  return [self invalidate];
	}
      } else {
	if (cmp > 0) {
	  continue;
	} else {
	  [monomials at:n + 1 insert:aMonomial];
	  assert([self check]);
	  return [self invalidate];
	}
      }
    }
    [monomials at:0 insert:aMonomial];
    assert([self check]);
    return [self invalidate];
  }
}

@end

