)abbrev category ABELGRP AbelianGroup
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ The class of abelian groups, i.e. additive monoids where
++ each element has an additive inverse.
++
++ Axioms:
++   \spad{-(-x) = x}
++   \spad{x+(-x) = 0}
-- following domain must be compiled with subsumption disabled
AbelianGroup() : Category == CancellationAbelianMonoid with
    --operations
      "-": % -> %                      ++ -x is the additive inverse of x.
      "-": (%,%) -> %                  ++ x-y is the difference of x and y
                                       ++ i.e. \spad{x + (-y)}.
                       -- subsumes the partial subtraction from previous
      "*": (Integer,%) -> %            ++ n*x is the product of x by the integer n.
    add
      (x : % - y : %) : % == x+(-y)
      subtractIfCan(x:%, y:%):Union(%, "failed") == (x-y) :: Union(%,"failed")
      n : NonNegativeInteger * x : % == (n::Integer) * x
      import from RepeatedDoubling(%)
      if not (% has Ring) then
          n : Integer * x : % ==
              zero? n => 0
              n>0 => double(qcoerce(n)@PositiveInteger, x)
              double(qcoerce(-n)@PositiveInteger, -x)
      opposite?(x,y) == x = -y


)abbrev category ABELMON AbelianMonoid
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ The class of multiplicative monoids, i.e. semigroups with an
++ additive identity element.
++
++ Axioms:
++   \spad{leftIdentity("+":(%,%)->%,0)}\tab{30}\spad{ 0+x=x }
++   \spad{rightIdentity("+":(%,%)->%,0)}\tab{30}\spad{ x+0=x }
-- following domain must be compiled with subsumption disabled
-- define SourceLevelSubset to be EQUAL
AbelianMonoid() : Category == AbelianSemiGroup with
      0 : constant -> %
        ++ 0 is the additive identity element.
      sample : constant -> %
        ++ sample yields a value of type %
      zero? : % -> Boolean
        ++ zero?(x) tests if x is equal to 0.
      "*": (NonNegativeInteger,%) -> %
        ++ n * x is left-multiplication by a non negative integer
      opposite? : (%,%) -> Boolean
        ++ \spad{opposite?(x,y)} holds if the sum of \spad{x}
        ++ and \spad{y} is \spad{0}.
    add
      import from RepeatedDoubling(%)
      zero? x == x = 0
      n : PositiveInteger * x : % == (n::NonNegativeInteger) * x
      sample() == 0
      if not (% has Ring) then
          n : NonNegativeInteger * x : % ==
              zero? n => 0
              double(qcoerce(n)@PositiveInteger, x)
      opposite?(x,y) == zero?(x + y)


)abbrev category ABELSG AbelianSemiGroup
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ the class of all additive (commutative) semigroups, i.e.
++ a set with a commutative and associative operation \spadop{+}.
++
++ Axioms:
++   \spad{associative("+":(%,%)->%)}\tab{30}\spad{ (x+y)+z = x+(y+z) }
++   \spad{commutative("+":(%,%)->%)}\tab{30}\spad{ x+y = y+x }
AbelianSemiGroup() : Category == SetCategory with
    --operations
      "+": (%,%) -> %                  ++ x+y computes the sum of x and y.
      "*": (PositiveInteger,%) -> %
        ++ n*x computes the left-multiplication of x by the positive integer n.
        ++ This is equivalent to adding x to itself n times.
    add
      import from RepeatedDoubling(%)
      if not (% has Ring) then
          n : PositiveInteger * x : % == double(n, x)


)abbrev category ALGEBRA Algebra
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ The category of associative algebras (modules which are themselves rings).
++
++ Axioms:
++   \spad{(b+c)::% = (b::%) + (c::%)}
++   \spad{(b*c)::% = (b::%) * (c::%)}
++   \spad{(1::R)::% = 1::%}
++   \spad{b*x = (b::%)*x}
++   \spad{r*(a*b) = (r*a)*b}
++   \spad{(a*b)*r = a*(b*r)}
Algebra(R : CommutativeRing) : Category ==
  Join(Ring, NonAssociativeAlgebra(R)) with
    --operations
      coerce : R -> %
          ++ coerce(r) maps the ring element r to a member of the algebra.
 add
  coerce(x : R) : % == x * 1$%

)abbrev category BASTYPE BasicType
--% BasicType
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ \spadtype{BasicType} is the basic category for describing a collection
++ of elements with \spadop{=} (equality).
BasicType() : Category == with
      "=": (%,%) -> Boolean    ++ x = y tests if x and y are equal.
      "~=": (%,%) -> Boolean   ++ x~=y tests if x and y are not equal.
   add
      _~_=(x : %, y : %) : Boolean == not(x = y)

)abbrev category BMODULE BiModule
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ A \spadtype{BiModule} is both a left and right module with respect
++ to potentially different rings.
++
++ Axiom:
++   \spad{ r*(x*s) = (r*x)*s }
BiModule(R : SemiRng, S : SemiRng) : Category ==
  Join(LeftModule(R), RightModule(S))

)abbrev category CABMON CancellationAbelianMonoid
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References: Davenport & Trager I
++ Description:
++ This is an \spadtype{AbelianMonoid} with the cancellation property, i.e.
++ \spad{ a+b = a+c => b=c }.
++ This is formalised by the partial subtraction operator,
++ which satisfies the axioms listed below:
++
++ Axioms:
++   \spad{c = a+b <=> c-b = a}
CancellationAbelianMonoid() : Category == AbelianMonoid with
    --operations
      subtractIfCan : (%,%) -> Union(%,"failed")
         ++ subtractIfCan(x, y) returns an element z such that \spad{z+y=x}
         ++ or "failed" if no such element exists.


)abbrev category CHARNZ CharacteristicNonZero
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ Rings of Characteristic Non Zero
CharacteristicNonZero() : Category == Ring with
    charthRoot : % -> Union(%,"failed")
       ++ charthRoot(x) returns the pth root of x
       ++ where p is the characteristic of the ring.

)abbrev category CHARZ CharacteristicZero
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ Rings of Characteristic Zero.
CharacteristicZero() : Category == Ring

)abbrev category COMRING CommutativeRing
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ The category of commutative rings with unity, i.e. rings where
++ \spadop{*} is commutative, and which have a multiplicative identity.
++ element.
CommutativeRing() : Category == Join(Ring, Algebra(%), CommutativeStar)


)abbrev category DIFRING DifferentialRing
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ An ordinary differential ring, that is, a ring with an operation
++ \spadfun{differentiate}.
++
++ Axioms:
++   \spad{differentiate(x+y) = differentiate(x)+differentiate(y)}
++   \spad{differentiate(x*y) = x*differentiate(y) + differentiate(x)*y}

DifferentialRing() : Category == Ring with
    differentiate : % -> %
         ++ differentiate(x) returns the derivative of x.
         ++ This function is a simple differential operator
         ++ where no variable needs to be specified.
    D : % -> %
         ++ D(x) returns the derivative of x.
         ++ This function is a simple differential operator
         ++ where no variable needs to be specified.
    differentiate : (%, NonNegativeInteger) -> %
         ++ differentiate(x, n) returns the n-th derivative of x.
    D : (%, NonNegativeInteger) -> %
         ++ D(x, n) returns the n-th derivative of x.
  add
    D r == differentiate r
    differentiate(r, n) ==
        for i in 1..n repeat r := differentiate r
        r
    D(r, n) == differentiate(r, n)


)abbrev category DIFEXT DifferentialExtension
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ Differential extensions of a ring R.
++ Given a differentiation on R, extend it to a differentiation on %.

DifferentialExtension(R : Ring) : Category == Ring with
    --operations
    differentiate : (%, R -> R) -> %
       ++ differentiate(x, deriv) differentiates x extending
       ++ the derivation deriv on R.
    differentiate : (%, R -> R, NonNegativeInteger) -> %
       ++ differentiate(x, deriv, n) differentiate x n times
       ++ using a derivation which extends deriv on R.
    D : (%, R -> R) -> %
       ++ D(x, deriv) differentiates x extending
       ++ the derivation deriv on R.
    D : (%, R -> R, NonNegativeInteger) -> %
       ++ D(x, deriv, n) differentiate x n times
       ++ using a derivation which extends deriv on R.
    if R has DifferentialRing then DifferentialRing
    if R has PartialDifferentialRing(Symbol) then
             PartialDifferentialRing(Symbol)
  add
    differentiate(x : %, derivation : R -> R, n : NonNegativeInteger) : % ==
      for i in 1..n repeat x := differentiate(x, derivation)
      x
    D(x : %, derivation : R -> R) == differentiate(x, derivation)
    D(x : %, derivation : R -> R, n : NonNegativeInteger) ==
            differentiate(x, derivation, n)

    if R has DifferentialRing then
        differentiate x == differentiate(x, differentiate$R)

    if R has PartialDifferentialRing Symbol then
        differentiate(x : %, v : Symbol) : % ==
            differentiate(x, (s : R) : R +-> differentiate(s, v)$R)

)abbrev category DIVRING DivisionRing
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ A division ring (sometimes called a skew field),
++ i.e. a not necessarily commutative ring where
++ all non-zero elements have multiplicative inverses.

DivisionRing() : Category ==
 Join(EntireRing, Algebra Fraction Integer, TwoSidedRecip) with
      "^": (%,Integer) -> %
          ++ x^n returns x raised to the integer power n.
      inv : % -> %
          ++ inv x returns the multiplicative inverse of x.
          ++ Error: if x is 0.
-- Q-algebra is a lie, should be conditional on characteristic 0,
-- but knownInfo cannot handle the following commented
--    if % has CharacteristicZero then Algebra Fraction Integer
    add
      n : Integer
      x : %
      import from RepeatedSquaring(%)
      x ^ n : Integer ==
          zero? n => 1
          zero? x =>
              n<0 => error "division by zero"
              x
          n<0 => expt(inv x, qcoerce(-n)@PositiveInteger)
          expt(x, qcoerce(n)@PositiveInteger)
--    if % has CharacteristicZero() then
      q : Fraction(Integer) * x : % == numer(q) * inv(denom(q)::%) * x


)abbrev category ENTIRER EntireRing
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ Entire Rings (non-commutative Integral Domains), i.e. a ring
++ not necessarily commutative which has no zero divisors.
++
++ Axioms:
++   \spad{ab=0 => a=0 or b=0}  -- known as noZeroDivisors
++   \spad{not(1=0)}
++
++ Conditional attributes:
++   canonicalUnitNormal\tab{20}the canonical field is the same for
++     all associates
++   canonicalsClosed\tab{20}the product of two canonicals is itself canonical
EntireRing() : Category == Join(Ring, noZeroDivisors) with
    --operations
      "exquo": (%,%) -> Union(%,"failed")
            ++ exquo(a, b) either returns an element c such that
            ++ \spad{c*b=a} or "failed" if no such element can be found.
      unitNormal : % -> Record(unit : %, canonical : %, associate : %)
            ++ unitNormal(x) tries to choose a canonical element
            ++ from the associate class of x.
            ++ The attribute canonicalUnitNormal, if asserted, means that
            ++ the "canonical" element is the same across all associates of x
            ++ if \spad{unitNormal(x) = [u, c, a]} then
            ++ \spad{u*c = x}, \spad{a*u = 1}.
      unitCanonical : % -> %
            ++ \spad{unitCanonical(x)} returns \spad{unitNormal(x).canonical}.
      associates? : (%, %) -> Boolean
        ++ associates?(x, y) tests whether x and y are associates, i.e.
        ++ differ by a unit factor.
      unit? : % -> Boolean
        ++ unit?(x) tests whether x is a unit, i.e. is invertible.
 add
      -- declaration
      x, y : %
      -- definitions
      UCA ==> Record(unit : %, canonical : %, associate : %)
      if not (% has Field) then
        unitNormal(x) == [1$%, x, 1$%]$UCA -- the non-canonical definition
      unitCanonical(x) == unitNormal(x).canonical -- always true
      recip(x) == if zero? x then "failed" else _exquo(1$%,x)
      unit?(x) == (recip x case "failed" => false; true)
      if % has canonicalUnitNormal then
          associates?(x, y) ==
              (unitNormal x).canonical = (unitNormal y).canonical
      else
          associates?(x, y) ==
              zero? x => zero? y
              zero? y => false
              x exquo y case "failed" => false
              y exquo x case "failed" => false
              true

      annihilate?(x,y) == zero? x or zero? y


)abbrev category EUCDOM EuclideanDomain
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ A constructive euclidean domain, i.e. one can divide producing
++ a quotient and a remainder where the remainder is either zero
++ or is smaller (\spadfun{euclideanSize}) than the divisor.
++
++ Conditional attributes:
++   multiplicativeValuation\tab{25}\spad{Size(a*b)=Size(a)*Size(b)}
++   additiveValuation\tab{25}\spad{Size(a*b)=Size(a)+Size(b)}

EuclideanDomain() : Category == PrincipalIdealDomain with
    --operations
      sizeLess? : (%, %) -> Boolean
         ++ sizeLess?(x, y) tests whether x is strictly smaller than y
         ++ with respect to the \spadfunFrom{euclideanSize}{EuclideanDomain}.
         ++ Note: zero is considered smaller than every nonzero element.
      euclideanSize : % -> NonNegativeInteger
         ++ euclideanSize(x) returns the euclidean size of the element x.
         ++ Error: if x is zero.
      divide : (%, %) -> Record(quotient : %, remainder : %)
         ++ divide(x, y) divides x by y producing a record containing a
         ++ \spad{quotient} and \spad{remainder},
         ++ where the remainder is smaller (see \spadfunFrom{sizeLess?}{EuclideanDomain})
         ++ than the divisor y.
      "quo" : (%,%) -> %
         ++ x quo y is the same as \spad{divide(x, y).quotient}.
         ++ See \spadfunFrom{divide}{EuclideanDomain}.
      "rem": (%,%) -> %
         ++ x rem y is the same as \spad{divide(x, y).remainder}.
         ++ See \spadfunFrom{divide}{EuclideanDomain}.
      extendedEuclidean : (%, %) -> Record(coef1 : %, coef2 : %, generator : %)
                     -- formerly called princIdeal
            ++ extendedEuclidean(x, y) returns a record rec where
            ++ \spad{rec.coef1*x+rec.coef2*y = rec.generator} and
            ++ rec.generator is a gcd of x and y.
            ++ The gcd is unique only
            ++ up to associates if \spadtype{canonicalUnitNormal} is not asserted.
            ++ \spadfun{principalIdeal} provides a version of this operation
            ++ which accepts an arbitrary length list of arguments.
      extendedEuclidean : (%,%,%) -> Union(Record(coef1:%,coef2:%),"failed")
                     -- formerly called expressIdealElt
          ++ extendedEuclidean(x, y, z) either returns a record rec
          ++ where \spad{rec.coef1*x+rec.coef2*y=z} or returns "failed"
          ++ if z cannot be expressed as a linear combination of x and y.
      multiEuclidean : (List %,%) -> Union(List %,"failed")
          ++ multiEuclidean([f1, ..., fn], z) returns a list of coefficients
          ++ \spad{[a1, ..., an]} such that
          ++ \spad{ z / prod fi = sum aj/fj}.
          ++ If no such list of coefficients exists, "failed" is returned.
    add

      import from NonNegativeInteger

      -- declarations
      x, y, z : %
      l : List %
      -- definitions
      sizeLess?(x, y) ==
          zero? y => false
          zero? x => true
          euclideanSize(x)<euclideanSize(y)
      x quo y == divide(x, y).quotient --divide must be user-supplied
      x rem y == divide(x, y).remainder
      x exquo y ==
          zero? y => "failed"
          qr := divide(x, y)
          zero?(qr.remainder) => qr.quotient
          "failed"
      gcd(x, y) ==                --Euclidean Algorithm
          x := unitCanonical x
          y := unitCanonical y
          while not zero? y repeat
              (x, y) := (y, x rem y)
              y := unitCanonical y     -- this doesn't affect the
                                       -- correctness of Euclid's algorithm,
                                       -- but
                                       -- a) may improve performance
                                       -- b) ensures gcd(x, y)=gcd(y, x)
                                       --    if canonicalUnitNormal
          x
      IdealElt ==> Record(coef1 : %, coef2 : %, generator : %)
      unitNormalizeIdealElt(s : IdealElt) : IdealElt ==
          (u, c, a) := unitNormal(s.generator)
          (a = 1) => s
          [a*s.coef1, a*s.coef2, c]$IdealElt
      extendedEuclidean(x, y) ==         --Extended Euclidean Algorithm
          s1 := unitNormalizeIdealElt([1$%, 0$%, x]$IdealElt)
          s2 := unitNormalizeIdealElt([0$%, 1$%, y]$IdealElt)
          zero? y => s1
          zero? x => s2
          while not zero?(s2.generator) repeat
              qr := divide(s1.generator, s2.generator)
              s3 := [s1.coef1 - qr.quotient * s2.coef1,
                 s1.coef2 - qr.quotient * s2.coef2, qr.remainder]$IdealElt
              s1 := s2
              s2 := unitNormalizeIdealElt s3
          if not(zero?(s1.coef1)) and not sizeLess?(s1.coef1, y) then
              qr := divide(s1.coef1, y)
              s1.coef1 := qr.remainder
              s1.coef2 := s1.coef2 + qr.quotient * x
              s1 := unitNormalizeIdealElt s1
          s1

      TwoCoefs ==> Record(coef1 : %, coef2 : %)
      extendedEuclidean(x, y, z) ==
          zero? z => [0, 0]$TwoCoefs
          s := extendedEuclidean(x, y)
          (w := z exquo s.generator) case "failed" => "failed"
          zero? y => [s.coef1 * w, s.coef2 * w]$TwoCoefs
          qr := divide((s.coef1 * w), y)
          [qr.remainder, s.coef2 * w + qr.quotient * x]$TwoCoefs

      principalIdeal l ==
          l = [] => error "empty list passed to principalIdeal"
          rest l = [] =>
              uca := unitNormal(first l)
              [[uca.unit], uca.canonical]
          rest rest l = [] =>
              u := extendedEuclidean(first l, second l)
              [[u.coef1, u.coef2], u.generator]
          v := principalIdeal rest l
          u := extendedEuclidean(first l, v.generator)
          [[u.coef1, :[u.coef2*vv for vv in v.coef]], u.generator]

      expressIdealMember(l, z) ==
          z = 0 => [0 for v in l]
          pid := principalIdeal l
          (q := z exquo (pid.generator)) case "failed" => "failed"
          [q*v for v in pid.coef]

      multiEuclidean(l, z) ==
          n := #l
          zero? n => error "empty list passed to multiEuclidean"
          n = 1 => [z]
          l1 := copy l
          l2 := split!(l1, n quo 2)
          u := extendedEuclidean(*/l1, */l2, z)
          u case "failed" => "failed"
          v1 := multiEuclidean(l1, u.coef2)
          v1 case "failed" => "failed"
          v2 := multiEuclidean(l2, u.coef1)
          v2 case "failed" => "failed"
          concat(v1, v2)


)abbrev category FIELD Field
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ The category of commutative fields, i.e. commutative rings
++ where all non-zero elements have multiplicative inverses.
++ The \spadfun{factor} operation while trivial is useful to have defined.
++
++ Axioms:
++   \spad{a*(b/a) = b}
++   \spad{inv(a) = 1/a}

Field() : Category == Join(EuclideanDomain, UniqueFactorizationDomain,
  DivisionRing, canonicalUnitNormal, canonicalsClosed) with
    --operations
      "/": (%,%) -> %
        ++ x/y divides the element x by the element y.
        ++ Error: if y is 0.
    add
      --declarations
      x, y : %
      n : Integer
      -- definitions
      UCA ==> Record(unit : %, canonical : %, associate : %)
      unitNormal(x) ==
          if zero? x then [1$%, 0$%, 1$%]$UCA else [x, 1$%, inv(x)]$UCA
      unitCanonical(x) == if zero? x then x else 1
      associates?(x, y) == if zero? x then zero? y else not(zero? y)
      inv x ==((u := recip x) case "failed" => error "not invertible"; u)
      x exquo y == (y = 0 => "failed"; x / y)
      gcd(x, y) ==
          x = 0 and y = 0 => 0
          1
      euclideanSize(x) == 0
      prime? x == false
      squareFree x == x::Factored(%)
      factor x == x::Factored(%)
      x / y == (zero? y => error "catdef: division by zero"; x * inv(y))
      divide(x, y) == [x / y, 0]

)abbrev category FINITE Finite
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ The category of domains composed of a finite set of elements.
++ We include the functions \spadfun{lookup} and \spadfun{index} to give a bijection
++ between the finite set and an initial segment of positive integers.
++
++ Axioms:
++   \spad{lookup(index(n)) = n}
++   \spad{index(lookup(s)) = s}
Finite() : Category == Join(SetCategory, ConvertibleTo InputForm,
                            Comparable, Hashable) with
    --operations
      size : () -> NonNegativeInteger
        ++ size() returns the number of elements in the set.
      index : PositiveInteger -> %
        ++ index(i) takes a positive integer i less than or equal
        ++ to \spad{size()} and
        ++ returns the \spad{i}-th element of the set. This
        ++ operation establishes a bijection
        ++ between the elements of the finite set and \spad{1..size()}.
      lookup : % -> PositiveInteger
        ++ lookup(x) returns a positive integer such that
        ++ \spad{x = index lookup x}.
      random : () -> %
        ++ random() returns a random element from the set.
      enumerate : () -> List %
        ++ enumerate() returns list of elements of the set.
  add
      random() == index((1+random(size()$%))::PositiveInteger)

      enumerate() == [index(i::PositiveInteger) for i in 1..size()]

      convert(x : %) : InputForm ==
          packageCall('index, [convert(lookup(x))@InputForm]
                     )$InputFormFunctions1(%)

      hashUpdate!(s : HashState, x : %) : HashState ==
          hashUpdate!(s, lookup(x))$Integer

      if not(% has OrderedSet) then

          smaller?(x : %, y : %) : Boolean ==
              lookup(x) <$PositiveInteger lookup(y)

)abbrev category FLINEXP FullyLinearlyExplicitOver
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ S is \spadtype{FullyLinearlyExplicitOver R} means that S is a
++ \spadtype{LinearlyExplicitOver R} and, in addition, if R is a
++ \spadtype{LinearlyExplicitOver Integer}, then so is S
FullyLinearlyExplicitOver(R : Ring) : Category ==
  LinearlyExplicitOver R with
    if (R has LinearlyExplicitOver Integer) then
            LinearlyExplicitOver Integer
 add
  if not(R is Integer) then
      if (R has LinearlyExplicitOver Integer) then
          reducedSystem(m : Matrix %) : Matrix(Integer) ==
              reducedSystem(reducedSystem(m)@Matrix(R))

          reducedSystem(m : Matrix %, v : Vector %) :
                Record(mat : Matrix(Integer), vec : Vector(Integer)) ==
              rec := reducedSystem(m, v)@Record(mat : Matrix R, vec : Vector R)
              reducedSystem(rec.mat, rec.vec)

)abbrev category GCDDOM GcdDomain
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References: Davenport & Trager 1
++ Description:
++ This category describes domains where \spadfun{gcd} can be
++ computed but where there is no guarantee of the existence
++ of \spadfun{factor} operation for factorization into irreducibles.
++ However, if such a \spadfun{factor} operation exist, factorization will be
++ unique up to order and units.

GcdDomain() : Category == Join(IntegralDomain, LeftOreRing) with
    --operations
      gcd : (%, %) -> %
            ++ gcd(x, y) returns the greatest common divisor of x and y.
            -- gcd(x, y) = gcd(y, x) in the presence of canonicalUnitNormal,
            -- but not necessarily elsewhere
      gcd : List(%) -> %
            ++ gcd(l) returns the common gcd of the elements in the list l.
      lcm : (%, %) -> %
            ++ lcm(x, y) returns the least common multiple of x and y.
            -- lcm(x, y) = lcm(y, x) in the presence of canonicalUnitNormal,
            -- but not necessarily elsewhere
      lcm : List(%) -> %
            ++ lcm(l) returns the least common multiple of the elements of the list l.
      gcdPolynomial : (SparseUnivariatePolynomial %, SparseUnivariatePolynomial %) ->
           SparseUnivariatePolynomial %
            ++ gcdPolynomial(p, q) returns the greatest common divisor (gcd) of
            ++ univariate polynomials over the domain
    add
      lcm(x : %, y : %) ==
          y = 0 => 0
          x = 0 => 0
          LCM : Union(%,"failed") := y exquo gcd(x,y)
          LCM case % =>  x * LCM
          error "bad gcd in lcm computation"
      lcm(l : List %) == reduce(lcm, l, 1, 0)
      gcd(l : List %) == reduce(gcd, l, 0, 1)
      SUP ==> SparseUnivariatePolynomial
      gcdPolynomial(p1, p2) ==
          zero? p1 => unitCanonical p2
          zero? p2 => unitCanonical p1
          c1 := content(p1); c2 := content(p2)
          p1 := (p1 exquo c1)::SUP %
          p2 := (p2 exquo c2)::SUP %
          if (e1 := minimumDegree p1) > 0 then
              p1 := (p1 exquo monomial(1, e1))::SUP %
          if (e2 := minimumDegree p2) > 0 then
              p2 := (p2 exquo monomial(1, e2))::SUP %
          e1 := min(e1, e2); c1 := gcd(c1, c2)
          p1 :=
              degree p1 = 0 or degree p2 = 0 => monomial(c1, 0)
              p := subResultantGcd(p1, p2)
              degree p = 0 => monomial(c1, 0)
              c2 := gcd(leadingCoefficient p1, leadingCoefficient p2)
              unitCanonical(c1 * primitivePart(((c2*p) exquo
                                     leadingCoefficient p)::SUP %))
          zero? e1 => p1
          monomial(1, e1)*p1

      lcmCoef(c1, c2) ==
          g := gcd(c1, c2)
          cc1 := (c2 exquo g)::%
          cc2 := (c1 exquo g)::%
          [cc1*c1, cc1, cc2]


)abbrev category GROUP Group
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ The class of multiplicative groups, i.e. monoids with
++ multiplicative inverses.
++
++ Axioms:
++   \spad{leftInverse("*":(%,%)->%,inv)}\tab{30}\spad{ inv(x)*x = 1 }
++   \spad{rightInverse("*":(%,%)->%,inv)}\tab{30}\spad{ x*inv(x) = 1 }
Group() : Category == Join(Monoid, TwoSidedRecip, unitsKnown) with
    --operations
      inv : % -> %               ++ inv(x) returns the inverse of x.
      "/": (%,%) -> %           ++ x/y is the same as x times the inverse of y.
      "^": (%,Integer) -> %    ++ x^n returns x raised to the integer power n.
      conjugate : (%, %) -> %
        ++ conjugate(p, q) computes \spad{inv(q) * p * q}; this is 'right action
        ++ by conjugation'.
      commutator : (%, %) -> %
        ++ commutator(p, q) computes \spad{inv(p) * inv(q) * p * q}.
    add
      import from RepeatedSquaring(%)
      x : % / y : % == x*inv(y)
      recip(x : %) == inv(x)
      x : % ^ n : Integer ==
          zero? n => 1
          n < 0 => expt(inv(x), qcoerce(-n)@PositiveInteger)
          expt(x, qcoerce(n)@PositiveInteger)
      conjugate(p, q) == inv(q) * p * q
      commutator(p, q) == inv(p) * inv(q) * p * q

)abbrev category INTDOM IntegralDomain
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References: Davenport & Trager I
++ Description:
++ The category of commutative integral domains, i.e. commutative
++ rings with no zero divisors.
++
IntegralDomain() : Category ==
  Join(CommutativeRing, EntireRing)


)abbrev category LMODULE LeftModule
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ The category of left modules over an rng (ring not necessarily with unit).
++ This is an abelian group which supports left multiplication by elements of
++ the rng.
++
++ Axioms:
++   \spad{ (a*b)*x = a*(b*x) }
++   \spad{ (a+b)*x = (a*x)+(b*x) }
++   \spad{ a*(x+y) = (a*x)+(a*y) }
LeftModule(R : SemiRng) : Category == AbelianSemiGroup with
      if R has AbelianMonoid then AbelianMonoid
      if R has AbelianGroup then AbelianGroup
      --operations
      "*": (R,%) -> %     ++ r*x returns the left multiplication of the module element x
                          ++ by the ring element r.



)abbrev category LORER LeftOreRing

++ Description:
++   This is category of left ore rings, that is noncommutaive
++   rings without zero divisors where we can compute least left
++   common multiple

LeftOreRing() : Category == EntireRing with
   lcmCoef : (%, %) -> Record(llcm_res : %, coeff1 : %, coeff2 : %)
     ++ lcmCoef(c1, c2) computes (llcm_res, coeff1, coeff2) such that
     ++ llcm_res is least left common multiple of c1 and c2
     ++ and llcm_res = coeff1*c1 = coeff2*c2


)abbrev category LINEXP LinearlyExplicitOver
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ An extension ring with an explicit linear dependence test.
LinearlyExplicitOver(R : Ring) : Category == RightModule(R) with
  reducedSystem : Matrix % -> Matrix R
    ++ reducedSystem(A) returns a matrix B such that \spad{A x = 0} and \spad{B x = 0}
    ++ have the same solutions in R.
  reducedSystem : (Matrix %, Vector %) -> Record(mat : Matrix R, vec : Vector R)
    ++ reducedSystem(A, v) returns a matrix B and a vector w such that
    ++ \spad{A x = v} and \spad{B x = w} have the same solutions in R.

)abbrev category MODULE Module
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ The category of modules over a commutative ring.
++
++ Axioms:
++   \spad{1*x = x}
++   \spad{(a*b)*x = a*(b*x)}
++   \spad{(a+b)*x = (a*x)+(b*x)}
++   \spad{a*(x+y) = (a*x)+(a*y)}
Module(R : CommutativeRing) : Category == BiModule(R, R)
  add
    if not(R is %) then x : %*r : R == r*x

)abbrev category MONOID Monoid
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ The class of multiplicative monoids, i.e. semigroups with a
++ multiplicative identity element.
++
++ Axioms:
++    \spad{leftIdentity("*":(%,%)->%,1)}\tab{30}\spad{1*x=x}
++    \spad{rightIdentity("*":(%,%)->%,1)}\tab{30}\spad{x*1=x}
++
++ Conditional attributes:
++    unitsKnown\tab{15}\spadfun{recip} only returns "failed" on non-units
Monoid() : Category == Join(SemiGroup, MagmaWithUnit)


)abbrev category OAGROUP OrderedAbelianGroup
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ Ordered sets which are also abelian groups, such that the addition preserves
++ the ordering.

OrderedAbelianGroup() : Category ==
        Join(OrderedCancellationAbelianMonoid, AbelianGroup)

)abbrev category OAMON OrderedAbelianMonoid
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ Ordered sets which are also abelian monoids, such that the addition
++ preserves the ordering.

OrderedAbelianMonoid() : Category ==
        Join(OrderedAbelianSemiGroup, AbelianMonoid)

)abbrev category OAMONS OrderedAbelianMonoidSup
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ This domain is an OrderedAbelianMonoid with a \spadfun{sup} operation added.
++ The purpose of the \spadfun{sup} operator in this domain is to act as a supremum
++ with respect to the partial order imposed by \spadop{-}, rather than with respect to
++ the total \spad{>} order (since that is "max").
++
++ Axioms:
++   \spad{sup(a,b)-a \~~= "failed"}
++   \spad{sup(a,b)-b \~~= "failed"}
++   \spad{x-a \~~= "failed" and x-b \~~= "failed" => x >= sup(a,b)}

OrderedAbelianMonoidSup() : Category == OrderedCancellationAbelianMonoid with
    --operation
      sup : (%, %) -> %
        ++ sup(x, y) returns the least element from which both
        ++ x and y can be subtracted.
      inf : (%, %) -> %
        ++ inf(x, y) returns the largest element which can be
        ++ subtracted from x and y.

)abbrev category OASGP OrderedAbelianSemiGroup
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ Ordered sets which are also abelian semigroups, such that the addition
++ preserves the ordering.
++   \spad{ x < y => x+z < y+z}

OrderedAbelianSemiGroup() : Category == Join(OrderedSet, AbelianSemiGroup)


)abbrev category OSGROUP OrderedSemiGroup
++ Author: Gabriel Dos Reis
++ Date Create May 25, 2008
++ Description:  Semigroups with compatible ordering.

OrderedSemiGroup() : Category == Join(OrderedSet, SemiGroup)


)abbrev category OCAMON OrderedCancellationAbelianMonoid
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ Ordered sets which are also abelian cancellation monoids, such that the addition
++ preserves the ordering.

OrderedCancellationAbelianMonoid() : Category ==
        Join(OrderedAbelianMonoid, CancellationAbelianMonoid)

)abbrev category ORDFIN OrderedFinite
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ Ordered finite sets.

OrderedFinite() : Category == Join(OrderedSet, Finite)

)abbrev category OINTDOM OrderedIntegralDomain
++ Author: JH Davenport (after L Gonzalez-Vega)
++ Date Created: 30.1.96
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ Description:
++ The category of ordered commutative integral domains, where ordering
++ and the arithmetic operations are compatible.

OrderedIntegralDomain() : Category ==
  Join(IntegralDomain, OrderedRing)


)abbrev category ORDMON OrderedMonoid
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ Ordered sets which are also monoids, such that multiplication
++ preserves the ordering.
++
++ Axioms:
++   \spad{x < y => x*z < y*z}
++   \spad{x < y => z*x < z*y}

OrderedMonoid() : Category == Join(OrderedSemiGroup, Monoid)

)abbrev category ORDRING OrderedRing
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ Ordered sets which are also rings, that is, domains where the ring
++ operations are compatible with the ordering.
++
++ Axiom:
++   \spad{0<a and b<c => ab< ac}

OrderedRing() : Category == Join(OrderedAbelianGroup, Ring,
         CharacteristicZero) with
     positive? : % -> Boolean
       ++ positive?(x) tests whether x is strictly greater than 0.
     negative? : % -> Boolean
       ++ negative?(x) tests whether x is strictly less than 0.
     sign     : % -> Integer
       ++ sign(x) is 1 if x is positive, -1 if x is negative, 0 if x equals 0.
     abs      : % -> %
       ++ abs(x) returns the absolute value of x.
  add
     positive? x == x>0
     negative? x == x<0
     sign x ==
         positive? x => 1
         negative? x => -1
         zero? x => 0
         error "x satisfies neither positive?, negative? or zero?"
     abs x ==
         positive? x => x
         negative? x => -x
         zero? x => 0
         error "x satisfies neither positive?, negative? or zero?"


)abbrev category COMPAR Comparable
++ Description:
++ The class of sets equipped with possibly unnatural linear order
++ (needed for technical reasons).
Comparable() : Category == SetCategory with
  --operations
    smaller? : (%, %) -> Boolean
      ++ smaller?(x, y) is a strict total ordering on the elements of the set.

)abbrev category PORDER PartialOrder
++ Author: Waldek Hebisch
++ Description:
++ The class of partially ordered sets, that is sets equipped with
++ transitive and reflexive relation \spad{<=}.

PartialOrder() : Category == with
    "<": (%,%) -> Boolean
      ++ x < y is a less than test.
    ">":         (%, %) -> Boolean
      ++ x > y is a greater than test.
    ">=":        (%, %) -> Boolean
      ++ x >= y is a greater than or equal test.
    "<=":        (%, %) -> Boolean
      ++ x <= y is a less than or equal test.

  add

     x >= y == y <= x

     x > y == y < x

     x < y == x <= y and not(y <= x)


)abbrev category ORDSET OrderedSet
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ The class of totally ordered sets, that is, sets such that for each pair of elements \spad{(a, b)}
++ exactly one of the following relations holds \spad{a<b or a=b or b<a}
++ and the relation is transitive, i.e.  \spad{a<b and b<c => a<c}.
++ This order should be the natural order on given structure.

OrderedSet() : Category == Join(Comparable, PartialOrder) with
  --operations

    max : (%, %) -> %
      ++ max(x,y) returns the maximum of x and y relative to "<".
    min : (%, %) -> %
      ++ min(x,y) returns the minimum of x and y relative to "<".
  add
    -- transitional definitions
    smaller?(x, y) == x < y

  --declarations
    x, y : %
  --definitions
  -- These really ought to become some sort of macro
    max(x, y) ==
        x > y => x
        y
    min(x, y) ==
        x > y => y
        x
    ((x : %) >  (y : %)) : Boolean == y < x
    ((x : %) >= (y : %)) : Boolean == not (x < y)
    ((x : %) <= (y : %)) : Boolean == not (y < x)

)abbrev category PDRING PartialDifferentialRing
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ A partial differential ring with differentiations indexed by a parameter type S.
++
++ Axioms:
++   \spad{differentiate(x+y, e) = differentiate(x, e) + differentiate(y, e)}
++   \spad{differentiate(x*y, e) = x*differentiate(y, e) + differentiate(x, e)*y}

PartialDifferentialRing(S : SetCategory) : Category == Ring with
    differentiate : (%, S) -> %
        ++ differentiate(x, v) computes the partial derivative of x
        ++ with respect to v.
    differentiate : (%, List S) -> %
        ++ differentiate(x, [s1, ...sn]) computes successive partial derivatives,
        ++ i.e. \spad{differentiate(...differentiate(x, s1)..., sn)}.
    differentiate : (%, S, NonNegativeInteger) -> %
        ++ differentiate(x, s, n) computes multiple partial derivatives, i.e.
        ++ n-th derivative of x with respect to s.
    differentiate : (%, List S, List NonNegativeInteger) -> %
        ++ differentiate(x, [s1, ..., sn], [n1, ..., nn]) computes
        ++ multiple partial derivatives, i.e.
    D : (%, S) -> %
        ++ D(x, v) computes the partial derivative of x
        ++ with respect to v.
    D : (%, List S) -> %
        ++ D(x, [s1, ...sn]) computes successive partial derivatives,
        ++ i.e. \spad{D(...D(x, s1)..., sn)}.
    D : (%, S, NonNegativeInteger) -> %
        ++ D(x, s, n) computes multiple partial derivatives, i.e.
        ++ n-th derivative of x with respect to s.
    D : (%, List S, List NonNegativeInteger) -> %
        ++ D(x, [s1, ..., sn], [n1, ..., nn]) computes
        ++ multiple partial derivatives, i.e.
        ++ \spad{D(...D(x, s1, n1)..., sn, nn)}.
  add
    differentiate(r : %, l : List S) ==
        for s in l repeat r := differentiate(r, s)
        r

    differentiate(r : %, s : S, n : NonNegativeInteger) ==
        for i in 1..n repeat r := differentiate(r, s)
        r

    differentiate(r : %, ls : List S, ln : List NonNegativeInteger) ==
        for s in ls for n in ln repeat r := differentiate(r, s, n)
        r

    D(r : %, v : S) == differentiate(r, v)
    D(r : %, lv : List S) == differentiate(r, lv)
    D(r : %, v : S, n : NonNegativeInteger) == differentiate(r, v, n)
    D(r : %, lv : List S, ln : List NonNegativeInteger) ==
        differentiate(r, lv, ln)

)abbrev category PFECAT PolynomialFactorizationExplicit
++ Author: James Davenport
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ This is the category of domains that know "enough" about
++ themselves in order to factor univariate polynomials over
++ their fraction field.
-- FIXME: Domain itself need not have unique factorization, but
-- to express this we would have to replace Factored by
-- different domain.

PolynomialFactorizationExplicit() : Category == Definition where
  P ==> SparseUnivariatePolynomial %
  Definition ==>
    UniqueFactorizationDomain with
    -- operations
       squareFreePolynomial : P -> Factored(P)
              ++ squareFreePolynomial(p) returns the
              ++ square-free factorization of the
              ++ univariate polynomial p.
       factorPolynomial : P -> Factored(P)
              ++ factorPolynomial(p) returns the factorization
              ++ into irreducibles of the univariate polynomial p.
       factorSquareFreePolynomial : P -> Factored(P)
              ++ factorSquareFreePolynomial(p) factors the
              ++ univariate polynomial p into irreducibles
              ++ where p is known to be square free
              ++ and primitive with respect to its main variable.
       gcdPolynomial : (P, P) -> P
              ++ gcdPolynomial(p, q) returns the gcd of the univariate
              ++ polynomials p qnd q.
              -- defaults to Euclidean, but should be implemented via
              -- modular or p-adic methods.
       solveLinearPolynomialEquation : (List P, P) -> Union(List P,"failed")
              ++ solveLinearPolynomialEquation([f1, ..., fn], g)
              ++ (where the fi are relatively prime to each other)
              ++ returns a list of ai such that
              ++ \spad{g/prod fi = sum ai/fi}
              ++ or returns "failed" if no such list of ai's exists.
       if % has CharacteristicNonZero then
         conditionP : Matrix % -> Union(Vector %,"failed")
              ++ conditionP(m) returns a vector of elements, not all zero,
              ++ whose \spad{p}-th powers (p is the characteristic of the domain)
              ++ are a solution of the homogenous linear system represented
              ++ by m, or "failed" is there is no such vector.
         charthRoot : % -> Union(%,"failed")
              ++ charthRoot(r) returns the \spad{p}-th root of r, or "failed"
              ++ if none exists in the domain.
              -- this is a special case of conditionP, but often the one we want
      add
        if % has CharacteristicNonZero then
            charthRoot f ==
                -- to take p'th root of f, solve the system X-fY=0,
                -- so solution is [x, y]
                -- with x^p=X and y^p=Y, then (x/y)^p = f
                zero? f => 0
                m : Matrix % := matrix [[1, -f]]
                ans := conditionP m
                ans case "failed" => "failed"
                (ans.1) exquo (ans.2)
        if % has Field then
            solveLinearPolynomialEquation(lf, g) ==
                multiEuclidean(lf, g)$P
        else
            solveLinearPolynomialEquation(lf, g) ==
                LPE ==> LinearPolynomialEquationByFractions %
                solveLinearPolynomialEquationByFractions(lf, g)$LPE

)abbrev category PID PrincipalIdealDomain
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ The category of constructive principal ideal domains, i.e.
++ where a single generator can be constructively found for
++ any ideal given by a finite set of generators.
++ Note that this constructive definition only implies that
++ finitely generated ideals are principal. It is not clear
++ what we would mean by an infinitely generated ideal.

PrincipalIdealDomain() : Category == GcdDomain with
    --operations
      principalIdeal : List % -> Record(coef : List %, generator : %)
         ++ principalIdeal([f1, ..., fn]) returns a record whose
         ++ generator component is a generator of the ideal
         ++ generated by \spad{[f1, ..., fn]} whose coef component satisfies
         ++ \spad{generator = sum (input.i * coef.i)}
      expressIdealMember : (List %,%) -> Union(List %,"failed")
         ++ expressIdealMember([f1, ..., fn], h) returns a representation
         ++ of h as a linear combination of the fi or "failed" if h
         ++ is not in the ideal generated by the fi.

)abbrev category RMODULE RightModule
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ The category of right modules over an rng (ring not necessarily with unit).
++ This is an abelian group which supports right multiplation by elements of
++ the rng.
++
++ Axioms:
++   \spad{ x*(a*b) = (x*a)*b }
++   \spad{ x*(a+b) = (x*a)+(x*b) }
++   \spad{ (x+y)*x = (x*a)+(y*a) }
RightModule(R : SemiRng) : Category == AbelianSemiGroup with
      if R has AbelianMonoid then AbelianMonoid
      if R has AbelianGroup then AbelianGroup
      --operations
      "*" : (%, R) -> %
          ++ x*r returns the right multiplication of the module element x
          ++ by the ring element r.

)abbrev category RING Ring
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ The category of rings with unity, always associative, but
++ not necessarily commutative.

--Ring(): Category == Join(Rng, Monoid, LeftModule(%: Rng)) with
Ring() : Category == Join(Rng, SemiRing, NonAssociativeRing,
                          unitsKnown)
                          -- Algebra(Integer)) -- typechecker crashes on this

)abbrev category SRNG SemiRng
++ Author: Waldek Hebisch
++ Description:
++ The category of associative semirings, not necessarily commutative, and not
++ necessarily with a 1.

SemiRng() : Category == Join(NonAssociativeSemiRng, BiModule(%, %), SemiGroup)


)abbrev category SRING SemiRing
++ Author: Waldek Hebisch
++ Description:
++ The category of associative semirings, not necessarily commutative,
++ with 0 and 1.

SemiRing() : Category == Join(NonAssociativeSemiRing, SemiRng, Monoid)


)abbrev category RNG Rng
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ The category of associative rings, not necessarily commutative, and not
++ necessarily with a 1. This is a combination of an abelian group
++ and a semigroup, with multiplication distributing over addition.
++
++ Axioms:
++   \spad{ x*(y+z) = x*y + x*z}
++   \spad{ (x+y)*z = x*z + y*z }
++
++ Conditional attributes:
++   \spadnoZeroDivisors\tab{25}\spad{  ab = 0 => a=0 or b=0}
Rng() : Category == Join(NonAssociativeRng, SemiRng) with
      annihilate? : (%,%) -> Boolean
             ++ \spad{annihilate?(x,y)} holds when the product
             ++ of \spad{x} and \spad{y} is \spad{0}.
    add
      annihilate?(x,y) == zero?(x * y)


)abbrev category SGROUP SemiGroup
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ the class of all multiplicative semigroups, i.e. a set
++ with an associative operation \spadop{*}.
++
++ Axioms:
++    \spad{associative("*":(%,%)->%)}\tab{30}\spad{ (x*y)*z = x*(y*z)}
++
++ Conditional attributes:
++    \spad{CommutativeStar}\tab{30}\spad{ x*y = y*x }
SemiGroup() : Category == Magma

)abbrev category HASHABL Hashable
++ Author: W. Hebisch
++ Description: All domains for which we can compute hash function
++  compatible with equality.
Hashable() : Category == BasicType with
      hash : % -> SingleInteger
         ++ hash(s) calculates a hash code for s.
      hashUpdate! : (HashState, %) -> HashState
         ++ hashUpdate!(hs, s) computes new HashState from old and s
         ++ used for incremental computation of hash values.
         ++ hashUpdate! might destructively work on its first argument.
  add
      hash(s : %) : SingleInteger ==
          value(hashUpdate!(new()$HashState, s))$HashState

)abbrev category SETCAT SetCategory
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ \spadtype{SetCategory} is the basic category for describing a collection
++ of elements with \spadop{=} (equality) and \spadfun{coerce} to output form.
++
++ Conditional Attributes:
++    canonical\tab{15}data structure equality is the same as \spadop{=}
SetCategory() : Category == Join(BasicType, CoercibleTo OutputForm) with
    --operations
      latex : % -> String
         ++ latex(s) returns a LaTeX-printable output
         ++ representation of s.
  add
      latex(s : %) : String ==
          of := s::OutputForm
          tf := of::TexFormat
          sl := tex(tf)
          reduce(concat, sl)


)abbrev category STEP StepThrough
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ A class of objects which can be 'stepped through'.
++ Repeated applications of \spadfun{nextItem} is guaranteed never to
++ return duplicate items and only return "failed" after exhausting
++ all elements of the domain.
++ This assumes that the sequence starts with \spad{init()}.
++ For infinite domains, repeated application
++ of \spadfun{nextItem} is not required to reach all possible domain elements
++ starting from any initial element.
++
++ Conditional attributes:
++   infinite\tab{15}repeated \spad{nextItem}'s are never "failed".
StepThrough() : Category == SetCategory with
    --operations
      init : constant -> %
        ++ init() chooses an initial object for stepping.
      nextItem : % -> Union(%,"failed")
        ++ nextItem(x) returns the next item, or "failed" if domain is exhausted.

)abbrev category UFD UniqueFactorizationDomain
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ A constructive unique factorization domain, i.e. where
++ we can constructively factor members into a product of
++ a finite number of irreducible elements.

UniqueFactorizationDomain() : Category == GcdDomain with
    --operations
      prime? : % -> Boolean
            ++ prime?(x) tests if x can never be written as the product of two
            ++ non-units of the ring,
            ++ i.e., x is an irreducible element.
      squareFree    : % -> Factored(%)
            ++ squareFree(x) returns the square-free factorization of x
            ++ i.e. such that the factors are pairwise relatively prime
            ++ and each has multiple prime factors.
      squareFreePart : % -> %
            ++ squareFreePart(x) returns a product of prime factors of
            ++ x each taken with multiplicity one.
      factor : % -> Factored(%)
            ++ factor(x) returns the factorization of x into irreducibles.
 add

  import from NonNegativeInteger
  import from Factored(%)

  squareFreePart x ==
      unit(s := squareFree x) * _*/[f.factor for f in factorList s]

  prime? x == numberOfFactors factor x = 1

--Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
--All rights reserved.
--
--Redistribution and use in source and binary forms, with or without
--modification, are permitted provided that the following conditions are
--met:
--
--    - Redistributions of source code must retain the above copyright
--      notice, this list of conditions and the following disclaimer.
--
--    - Redistributions in binary form must reproduce the above copyright
--      notice, this list of conditions and the following disclaimer in
--      the documentation and/or other materials provided with the
--      distribution.
--
--    - Neither the name of The Numerical ALgorithms Group Ltd. nor the
--      names of its contributors may be used to endorse or promote products
--      derived from this software without specific prior written permission.
--
--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
--IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
--TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
--PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
--OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
--EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
--PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
--PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
--LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
--NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
