#
# Zmod(n): the integers modulo n
# Author: MBM 1990
#
Zmod := proc(n) local F; option remember;

    if not type(n,integer) or n < 1 then
	ERROR(`1st argument must be an integer > 1`) fi;

    if isprime(n)
    then F := FiniteField(n,1)
    else F := CommutativeRing(Finite(n));
    fi;

    F[DomainName] := Zmod;

    # Rep := Maple Integer
    addProperties(F,{CannonicalForm,UniquelyRepresented});
    F[Type] := subs('m' = n, proc(x) type(x,integer) and x >= 0 and x < m end);
    F[`=`] := <evalb(x=y)>;
    F[Input] := subs('m' = n, proc(x)
    	    if type(x,integer) then modp(x,m) else FAIL fi
        end);
    F[0] := 0;
    F[`+`] := subs('m' = n, proc() modp(convert([args],`+`),m) end);
    F[`-`] := subs('m' = n, proc(x,y)
	    if nargs = 1 then modp(-x,m) else modp(x-y,m) fi
        end);
    F[1] := 1;
    F[`*`] := subs('m' = n, proc(x) modp(convert([args],`*`),m) end);
    F[`^`] := subs('m' = n, <modp(x &^ y,m)|x,y>);
    if isprime(n)
    then F[Inv] := subs('m' = n, <modp(1/x,m)|x>)
    else F[Inv] := subs('m' = n, proc(x) local t;
	    t := traperror(modp(1/x,m));
	    if t = lasterror then FAIL else t fi
	end);
    fi;
    F[Random] := rand(n);
    F[Index] := <x|x>;
    F[Lookup] := <x|x>;
    F[Universe] := subs('m' = n, proc() option remember; $0..m-1 end);
    op(F)

end:

save `Zmod.m`;
quit
