)abbrev domain ZMOD IntegerMod
++ Author:
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ IntegerMod(n) creates the ring of integers reduced modulo the integer
++ n.

IntegerMod(p : PositiveInteger):
 Join(CommutativeRing, Finite, ConvertibleTo Integer, StepThrough) == add
  size()           == p
  characteristic() == p
  lookup x == (zero? x => p; (convert(x)@Integer) :: PositiveInteger)

-- Code is duplicated for the optimizer to kick in.
  if p <= convert(shift(max()$SingleInteger, -1))@Integer then
    Rep := SingleInteger
    q := p::SingleInteger

    bloodyCompiler : Integer -> %
    bloodyCompiler n == positiveRemainder(n, p)$Integer pretend %

    convert(x : %) : Integer == convert(x)$Rep
    coerce(x) : OutputForm == coerce(x)$Rep
    coerce(n : Integer) : %  == bloodyCompiler n
    0                    == 0$Rep
    1                    == 1$Rep
    init                 == 0$Rep
    nextItem(n)          ==
                              m := n+1
                              m = 0 => "failed"
                              m
    x = y                == x =$Rep y
    x : % * y : %            == mulmod(x, y, q)
    n : Integer * x : %      == mulmod(bloodyCompiler n, x, q)
    x + y                == addmod(x, y, q)
    x - y                == submod(x, y, q)
    random()             == random(q)$Rep
    index a              == positiveRemainder(a::%, q)
    - x                  == (zero? x => 0; q -$Rep x)

    x : % ^ n : NonNegativeInteger ==
      n < p => powmod(x, n::Rep, q)
      powmod(convert(x)@Integer, n, p)$Integer :: Rep

    recip x ==
       (c1, c2, g) := extendedEuclidean(x, q)$Rep
       not (g = 1) => "failed"
       positiveRemainder(c1, q)

    hashUpdate!(hs, s) == update!(hs, s pretend SingleInteger)$HashState

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

  else
    Rep := Integer

    convert(x : %) : Integer == convert(x)$Rep
    coerce(n : Integer) : %  == positiveRemainder(n::Rep, p)
    coerce(x) : OutputForm == coerce(x)$Rep
    0                    == 0$Rep
    1                    == 1$Rep
    init                 == 0$Rep
    nextItem(n)          ==
                              m := n+1
                              m = 0 => "failed"
                              m
    x = y                == x =$Rep y
    x : % * y : %            == mulmod(x, y, p)
    n : Integer * x : %      == mulmod(positiveRemainder(n::Rep, p), x, p)
    x + y                == addmod(x, y, p)
    x - y                == submod(x, y, p)
    random()             == random(p)$Rep
    index a              == positiveRemainder(a::Rep, p)
    - x                  == (zero? x => 0; p -$Rep x)
    x : % ^ n : NonNegativeInteger == powmod(x, n::Rep, p)

    recip x ==
       (c1, c2, g) := extendedEuclidean(x, p)$Rep
       not (g = 1) => "failed"
       positiveRemainder(c1, p)

    hashUpdate!(hs, s) == update!(hs, SXHASH(s)$Lisp)$HashState

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

--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.
