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

#include "cakit.h"

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

  [super check];
  assert(termOne != nil && terms != nil);
  [termOne check];
  [terms check];

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

    assert([[term coefficient] isOne] && [term exponent] > 0);
    if (last)
      assert([last compareSymbols:term] < 0);
    last = term;
  }

  return self;
}

- _setUpScalarOne:aOne
{
  assert([aOne isOne]);
  termOne = [Term scalar:aOne symbol:nil exponent:0];
  terms = [CACollection new];
  assert([self check]);
  return self;
}

+ scalarOne:aOne
{
  return [[super new] _setUpScalarOne:aOne];
}

- copy
{
  return [self _terms:[terms copy]];
}

- deepCopy
{
  return [self _terms:[terms deepCopy]];
}

- clear
{
  termOne = [termOne free];
  terms = [terms free];
  return [super clear];
}

- clone
{
  self = [super clone];
  termOne = [termOne cheapCopy];
  terms = nil;
  return self;
}

- _terms
{
  return terms;
}

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

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

- termOne  {
  return termOne;
}
- (BOOL)isVariableSparse  {
  return YES;
}
- (BOOL)isVariableDense   {
  return NO;
}

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

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

- (int) compare:b
{
  int cmp, n, m;
  id bterms = [b _terms];

  n = [terms size];
  m = [bterms size];

  while (n && m) {
    id term = [terms at:--n];
    id bterm = [bterms at:--m];

    if ((cmp = [term compareExponents:bterm]))
      return cmp;
  }

  if (n)
    return +1;
  if (m)
    return -1;
  return 0;
}

- (BOOL) isEqual:b
{
  id bTerms = [b _terms];

  return (terms == bTerms) ? YES : [terms isEqual:bTerms];
}

- (unsigned) hash
{
  return [terms hash];
}

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

- symbol:aSymbol
{
  id term = [termOne symbol:aSymbol];

  assert([termOne symbol] == nil && term);	/* never fails since symbol is nil */
  return [[self empty] insertTerm:term];
}

- (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
{
  int n;

  [self checkRefCountOne];
  assert([self check] && [[aTerm coefficient] isOne]);
  if ([aTerm exponent] == 0) {
    [aTerm free];
    return self;
  }
  n = [terms size];
  while (n--) {
    int cmp;
    id term = [terms at:n];

    cmp = [term compareSymbols:aTerm];
    if (cmp == 0) {
      id product = [term multiply:aTerm];

      [aTerm free];
      if ([product exponent] < 0) {
	[product free];
	return nil;
      }
      if ([product exponent] == 0) {
	[[terms removeAt:n] free];
	[product free];
	assert([self check]);
	return [self invalidate];
      } else {
	[[terms at:n put:product] free];
	assert([self check]);
	return [self invalidate];
      }
    } else {
      if (cmp < 0) {
	continue;
      } else {
	if ([aTerm exponent] < 0) {
	  return nil;
	} else {
	  [terms at:n + 1 insert:aTerm];
	  assert([self check]);
	  return [self invalidate];
	}
      }
    }
  }

  if ([aTerm exponent] < 0) {
    return nil;
  } else {
    [terms at:0 insert:aTerm];
    assert([self check]);
    return [self invalidate];
  }
}

@end

