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

#include "cakit.h"

@implementation polynomialc
- empty
{
  [self subclassResponsibility:_cmd];
  return self;
}

- (BOOL) isEmpty
{
  [self subclassResponsibility:_cmd];
  return NO;
}

- (BOOL)isVariableDense  {
  [self subclassResponsibility:_cmd];
  return NO;
}
- (BOOL)isVariableSparse  {
  [self subclassResponsibility:_cmd];
  return NO;
}
- (BOOL)isRecursive  {
  [self subclassResponsibility:_cmd];
  return NO;
}
- (BOOL)isExpanded  {
  [self subclassResponsibility:_cmd];
  return NO;
}
- (BOOL)isDegreeDense  {
  [self subclassResponsibility:_cmd];
  return NO;
}
- (BOOL)isDegreeSparse  {
  [self subclassResponsibility:_cmd];
  return NO;
}

- (int)numTerms
{
  if ([self isRecursive]) {
    [self subclassResponsibility:_cmd];
    return 0;
  } else {
    [self doesNotRecognize:_cmd];
    return 0;
  }
}

- eachTerm
{
  if ([self isRecursive]) {
    [self subclassResponsibility:_cmd];
    return self;
  } else {
    [self doesNotRecognize:_cmd];
    return self;
  }
}

- removeTerm
{
  if ([self isRecursive]) {
    [self subclassResponsibility:_cmd];
    return self;
  } else {
    [self doesNotRecognize:_cmd];
    return self;
  }
}

- insertTerm:aTerm
{
  if ([self isRecursive]) {
    [self subclassResponsibility:_cmd];
    return self;
  } else {
    [self doesNotRecognize:_cmd];
    return self;
  }
}

- (int)numMonomials
{
  if ([self isExpanded]) {
    [self subclassResponsibility:_cmd];
    return 0;
  } else {
    [self doesNotRecognize:_cmd];
    return 0;
  }
}

- eachMonomial
{
  if ([self isExpanded]) {
    [self subclassResponsibility:_cmd];
    return self;
  } else {
    [self doesNotRecognize:_cmd];
    return self;
  }
}

- removeMonomial
{
  if ([self isExpanded]) {
    [self subclassResponsibility:_cmd];
    return self;
  } else {
    [self doesNotRecognize:_cmd];
    return self;
  }
}

- insertMonomial:aMonomial
{
  if ([self isExpanded]) {
    [self subclassResponsibility:_cmd];
    return self;
  } else {
    [self doesNotRecognize:_cmd];
    return self;
  }
}

- (int) leadingDegree
{
  if ([self isEmpty]) {
    return -1;
  } else {
    int deg;
    id seq = [self eachElement];

    deg = [[seq firstElement] degree];
    [seq free];
    return deg;
  }
}

- (int) lastDegree
{
  if ([self isEmpty]) {
    return -1;
  } else {
    int deg;
    id seq = [self eachElement];

    deg = [[seq lastElement] degree];
    [seq free];
    return deg;
  }
}

- (int) maxDegree
{
  if ([self isEmpty]) {
    return -1;
  } else {
    int deg, max;
    id member, seq = [self eachElement];

    max = [[seq firstElement] degree];
    while (member = [seq next]) {
      deg = [member degree];
      if (deg > max)
	max = deg;
    }
    [seq free];
    return max;
  }
}

- (int) minDegree
{
  if ([self isEmpty]) {
    return -1;
  } else {
    int deg, min;
    id member, seq = [self eachElement];

    min = [[seq firstElement] degree];
    while (member = [seq next]) {
      deg = [member degree];
      if (deg < min)
	min = deg;
    }
    [seq free];
    return min;
  }
}

- eachElement
{
  return ([self isRecursive]) ? [self eachTerm] : [self eachMonomial];
}

- (unsigned) size
{
  return ([self isRecursive]) ? [self numTerms] : [self numMonomials];
}

- insertMember:aMember
{
  return ([self isRecursive]) ? [self insertTerm : aMember]:[self insertMonomial:aMember];
}

- (BOOL) isOpposite:b
{
  id tmp;
  BOOL res;

  tmp = [self add:b];
  res = [tmp isZero];
  [tmp free];
  return res;
}

- negate
{
  id seq, member, res;

  res = [self empty];
  seq = [self eachElement];
  while (member = [seq next])
    [res insertMember:[member negate]];
  seq = [seq free];
  return res;
}

- double
{
  id seq, member, res;

  res = [self empty];
  seq = [self eachElement];
  while (member = [seq next])
    [res insertMember:[member double]];
  seq = [seq free];
  return res;
}

- add:b
{
  id res, seq, member;

  res = [self empty];

  seq = [self eachElement];
  while (member = [seq next])
    [res insertMember:[member cheapCopy]];
  seq = [seq free];

  seq = [b eachElement];
  while (member = [seq next])
    [res insertMember:[member cheapCopy]];
  seq = [seq free];

  return res;
}

- subtract:b
{
  id res, seq, member;

  res = [self empty];

  seq = [self eachElement];
  while (member = [seq next])
    [res insertMember:[member cheapCopy]];
  seq = [seq free];

  seq = [b eachElement];
  while (member = [seq next])
    [res insertMember:[member negate]];
  seq = [seq free];

  return res;
}

- multiplyScalar:aScalar
{
  id seq, member, res;

  if ([self isRecursive] && [self isVariableDense]) {
    [self notImplemented:_cmd];
  }
  assert([self check] && [aScalar check]);
  res = [self empty];
  seq = [self eachElement];
  while (member = [seq next]) {
    [res insertMember:[member multiplyScalar:aScalar]];
  }
  seq = [seq free];
  return res;
}

- multiplyCoefficient:aCoefficient
{
  id seq, term, res;

  assert([self isRecursive] && [self isVariableDense]);
  assert([self check] && [aCoefficient check]);
  res = [self empty];
  seq = [self eachTerm];
  while (term = [seq next]) {
    [res insertMember:[term multiplyCoefficient:aCoefficient]];
  }
  seq = [seq free];
  return res;
}

- multiplyMonomial:aMonomial
{
  id seq, monomial, res;

  assert([self check] && [aMonomial check]);
  assert([aMonomial isScalar] == NO);
  res = [self empty];
  seq = [self eachMonomial];
  while (monomial = [seq next]) {
    [res insertMonomial:[monomial multiply:aMonomial]];
  }
  seq = [seq free];
  return res;
}

- vardnsMultiplyTerm:aTerm
{
  id seq, term, res;

  assert([self isVariableDense] && [self check] && [aTerm check]);
  assert([aTerm isCoefficient] == NO);
  res = [self empty];
  seq = [self eachTerm];
  while (term = [seq next]) {
    [res insertTerm:[term multiply:aTerm]];
  }
  seq = [seq free];
  return res;
}

- multiplyTerm:aTerm
{
  assert([self isRecursive]);
  return ([self isVariableDense]) ? [self vardnsMultiplyTerm : aTerm]:[self varspsMultiplyTerm:aTerm];
}

- divideScalar:aScalar
{
  id seq, member, res;

  if ([self isVariableDense])
    [self notImplemented:_cmd];

  assert([self check] && [aScalar check] && [aScalar notZero]);
  res = [self empty];
  seq = [self eachElement];
  while (member = [seq next]) {
    member = [member divideScalar:aScalar];
    if (member) {
      [res insertMember:member];
    } else {
      [seq free];
      [res free];
      return nil;
    }
  }
  seq = [seq free];
  return res;
}

- divideCoefficient:aCoefficient
{
  id seq, term, res;

  assert([self isRecursive] && [self isVariableDense]);
  assert([aCoefficient notZero] && [self check] && [aCoefficient check]);
  res = [self empty];
  seq = [self eachTerm];
  while (term = [seq next]) {
    term = [term divideCoefficient:aCoefficient];
    if (term) {
      [res insertMember:term];
    } else {
      [seq free];
      [res free];
      return nil;
    }
  }
  seq = [seq free];
  return res;
}

- divideMonomial:aMonomial
{
  id seq, monomial, res;

  assert([self check] && [aMonomial check]);
  assert([aMonomial isScalar] == NO && [aMonomial notZero]);
  res = [self empty];
  seq = [self eachMonomial];
  while (monomial = [seq next]) {
    monomial = [monomial divide:aMonomial];
    if (monomial) {
      [res insertMonomial:monomial];
    } else {
      [seq free];
      [res free];
      return nil;
    }
  }
  seq = [seq free];
  return res;
}

- vardnsDivideTerm:aTerm
{
  id seq, term, res;

  assert([self isVariableDense] && [self check]);
  assert([aTerm isCoefficient] == NO && [aTerm check] && [aTerm notZero]);
  res = [self empty];
  seq = [self eachTerm];
  while (term = [seq next]) {
    term = [term divide:aTerm];
    if (term) {
      [res insertTerm:term];
    } else {
      [seq free];
      [res free];
      return nil;
    }
  }
  seq = [seq free];
  return res;
}

- divideTerm:aTerm
{
  assert([self isRecursive]);
  return ([self isVariableDense]) ? [self vardnsDivideTerm : aTerm]:[self varspsDivideTerm:aTerm];
}

- over:aCarrier
{
  return [self notImplemented:_cmd];
}

- liftTerm:aTerm
{
  id aCarrier = [[self empty] insertTerm:aTerm];

  return [Polynomial over:aCarrier];
}

- varspsMultiplyTerm:aTerm
{
  id seq, term, res, aScalar;

  assert([self check] && [aTerm check]);
  assert([self isRecursive] && [self isVariableSparse] && [aTerm isCoefficient] == NO);
  res = [self empty];
  seq = [self eachTerm];
  while (term = [seq next]) {
    id product;
    int cmp = [term compareSymbols:aTerm];

    if (cmp == 0) {
      product = [term multiply:aTerm];
      [res insertTerm:product];
    } else {
      if (cmp < 0) {
	id poly = [self liftTerm:[term cheapCopy]];

	product = [aTerm varspsMultiplyCoefficient:poly];
	[res insertTerm:product];
	[poly free];
      } else {
	id poly = [self liftTerm:[aTerm cheapCopy]];

	product = [term varspsMultiplyCoefficient:poly];
	[res insertTerm:product];
	[poly free];
      }
    }
  }
  seq = [seq free];
  return res;
}

- varspsDivideTerm:aTerm
{
  id seq, term, res, aScalar;

  assert([self check] && [aTerm check]);
  assert([self isRecursive] && [self isVariableSparse] && [aTerm isCoefficient] == NO);
  res = [self empty];
  seq = [self eachTerm];
  while (term = [seq next]) {
    id product;
    int cmp = [term compareSymbols:aTerm];

    if (cmp == 0) {
      if (product = [term divide:aTerm]) {
	[res insertTerm:product];
      } else {
	[seq free];
	[res free];
	return nil;
      }
    } else {
      if (cmp < 0) {
	[seq free];
	[res free];
	return nil;
      } else {
	id poly = [self liftTerm:[aTerm cheapCopy]];

	product = [term varspsDivideCoefficient:poly];
	[poly free];
	if (product) {
	  [res insertTerm:product];
	} else {
	  [seq free];
	  [res free];
	  return nil;
	}
      }
    }
  }
  seq = [seq free];
  return res;
}

@end

