Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More GMP work #1075

Merged
merged 21 commits into from
Jan 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
1898ea7
gmpints: introduce fake_mpz_t
fingolfin Jan 21, 2017
8c018e0
gmpints: merge GMPorINTOBJ_INT and ObjInt_Int
fingolfin Jan 21, 2017
e918054
gmpints: rewrite PrintInt using mpz_get_str
fingolfin Jan 21, 2017
1c6d8ee
gmpints: rewrite HexStringInt and STRING_INT using fake_mpz_t
fingolfin Jan 21, 2017
b591686
gmpints: remove GMP_INTOBJ
fingolfin Jan 21, 2017
9a3689f
gmpints: rewrite FuncIntHexString
fingolfin Jan 21, 2017
99418d3
gmpints: replace TypLimb -> mp_limb_t, TypGMPSize -> mp_size_t
fingolfin Jan 21, 2017
b700ea4
gmpints: replace INTEGER_ALLOCATION_SIZE by INTEGER_UNIT_SIZE
fingolfin Jan 21, 2017
af567b1
gmpints: cleanup gmpints.h
fingolfin Jan 21, 2017
6a5815f
gmpints: simplify ModInt
fingolfin Jan 21, 2017
b8a188c
gmpints: remove NEW_INTPOS
fingolfin Jan 21, 2017
8454a6f
gmpints: add IS_INT, IS_POSITIVE, REQUIRE_INT_ARG
fingolfin Jan 21, 2017
1c8ae24
gmpints: change REQUIRE_INT_ARG to use ErrorMayQuit
fingolfin Jan 21, 2017
cdba5d4
gmpints: use REQUIRE_INT_ARG in two more places
fingolfin Jan 21, 2017
3e44492
gmpints: fix RemInt error handling
fingolfin Jan 21, 2017
42c4845
gmpints: add JACOBI_INT and change Jacobi() to use it
fingolfin Jan 21, 2017
0950124
gmpints: add POWERMODINT and INVMODINT
fingolfin Jan 21, 2017
9561e9d
gmpints: add PVALUATION_INT
fingolfin Jan 21, 2017
fbf656a
tests: replace legal header in intarith.tst
fingolfin Jan 21, 2017
9bc7f34
gmpints: explain the buffer in PrintInt
fingolfin Jan 23, 2017
cad52ab
gmpints: improve initial documentation comment
fingolfin Jan 23, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/integer.gd
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ DeclareGlobalFunction( "NextPrimeInt" );
##
## <Description>
## returns <M><A>r</A>^{<A>e</A>} \pmod{<A>m</A>}</M> for integers <A>r</A>,
## <A>e</A> and <A>m</A> (<M><A>e</A> \geq 0</M>).
## <A>e</A> and <A>m</A>.
## <P/>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it obvious enough that $e \neq 0$?

Negative values seem to work (now) if $r$ is invertible, so that should maybe be documented explicitly?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But e can (still) be 0. And negative values were supported before, just not documented.
Documenting this more explicitly is fine by me, but I'd prefer to not do this as part of this PR (which has been in the works for very long by now)...

## Note that <Ref Func="PowerModInt"/> can reduce intermediate results and
## thus will generally be faster than using
Expand Down
52 changes: 4 additions & 48 deletions lib/integer.gi
Original file line number Diff line number Diff line change
Expand Up @@ -1161,40 +1161,7 @@ end);
##
#F PowerModInt(<r>,<e>,<m>) . . . . . . power of one integer modulo another
##
InstallGlobalFunction(PowerModInt,function ( r, e, m )
local pow, f;

# handle special cases
if m = 1 then
return 0;
elif e = 0 then
return 1;
fi;

# reduce `r' initially
r := r mod m;

# if `e' is negative then invert `r' modulo `m' with Euclids algorithm
if e < 0 then
r := 1/r mod m;
e := -e;
fi;

# now use the repeated squaring method (right-to-left)
pow := 1;
f := 2 ^ (LogInt( e, 2 ) + 1);
while 1 < f do
pow := (pow * pow) mod m;
f := QuoInt( f, 2 );
if f <= e then
pow := (pow * r) mod m;
e := e - f;
fi;
od;

# return the power
return pow;
end);
InstallGlobalFunction(PowerModInt, POWERMODINT);


#############################################################################
Expand Down Expand Up @@ -1805,24 +1772,13 @@ InstallMethod( StandardAssociateUnit,
InstallOtherMethod( Valuation,
"for two integers",
IsIdenticalObj,
[ IsInt,
IsInt ],
[ IsInt, IsInt ],
0,

function( n, m )
local val;

if n = 0 then
val := infinity;
else
val := 0;
while n mod m = 0 do
val := val + 1;
n := n / m;
od;
return infinity;
fi;
return val;

return PVALUATION_INT( n, m );
end );


Expand Down
60 changes: 7 additions & 53 deletions lib/numtheor.gi
Original file line number Diff line number Diff line change
Expand Up @@ -333,45 +333,7 @@ end );
#F Jacobi( <n>, <m> ) . . . . . . . . . . . . . . . . . . . . Jacobi symbol
##
##
InstallGlobalFunction( Jacobi, function ( n, m )
local jac, t;

# check the argument
if m <= 0 then Error("<m> must be positive"); fi;

# compute the Jacobi symbol similar to Euclid's algorithm
jac := 1;
while m <> 1 do

# if the gcd of $n$ and $m$ is $>1$ Jacobi returns $0$
if n = 0 or (n mod 2 = 0 and m mod 2 = 0) then
jac := 0; m := 1;

# $J(n,2*m) = J(n,m) * J(n,2) = J(n,m) * (-1)^{(n^2-1)/8}$
elif m mod 2 = 0 then
if n mod 8 = 3 or n mod 8 = 5 then jac := -jac; fi;
m := m / 2;

# $J(2*n,m) = J(n,m) * J(2,m) = J(n,m) * (-1)^{(m^2-1)/8}$
elif n mod 2 = 0 then
if m mod 8 = 3 or m mod 8 = 5 then jac := -jac; fi;
n := n / 2;

# $J(-n,m) = J(n,m) * J(-1,m) = J(n,m) * (-1)^{(m-1)/2}$
elif n < 0 then
if m mod 4 = 3 then jac := -jac; fi;
n := -n;

# $J(n,m) = J(m,n) * (-1)^{(n-1)*(m-1)/4}$ (quadratic reciprocity)
else
if n mod 4 = 3 and m mod 4 = 3 then jac := -jac; fi;
t := n; n := m mod n; m := t;

fi;
od;

return jac;
end );
InstallGlobalFunction( Jacobi, JACOBI_INT );

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While its great to be able to do all these in GMP, I would quite like to keep GAP functions around as an alternative. The reason is that while implementing GAP in alternative runtimes, the more code one does not have to write in the runtime the better.

I don't know how to do this cleanly right now though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is exactly how I did it before @ChrisJefferson asked me to remove the GAP implementation sigh. It is still around in the .tst files, by the way.

I can add it back here again, but I don't want to rewrite the code a third time, so I'll wait until at least @ChrisJefferson signs off on it, too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caveat: the new Jacobi accepts more inputs than the old (n negative).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed in the chat, I am happy with moving the function to tests, and I will attempt to make a structured attempt at detecting which functions are delegated to C code (and collect/provide GAP implementations where appropriate).


#############################################################################
Expand Down Expand Up @@ -1385,24 +1347,16 @@ end );


InstallGlobalFunction(PValuation,function(n,p)
local a,v;
if not IsPrimeInt(p) or not IsRat(n) then
local v;
if not IsInt(p) or not IsRat(n) or p = 0 then
Error("wrong parameters");
fi;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error message could be more helpful.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I hope somebody will make a PR improving it after this PR has been merged :-)

if IsZero(n) then
if n = 0 then
return infinity;
elif not IsInt(n) then
return PValuation(NumeratorRat(n),p)-PValuation(DenominatorRat(n),p);
elif n<0 then n:=-n;
elif IsInt(n) then
return PVALUATION_INT(n,p);
fi;
a:=1;
v:=0;
while n mod p=0 do
a:=a*p;
v:=v+1;
n:=n/p;
od;
return v;
return PVALUATION_INT(NumeratorRat(n),p) - PVALUATION_INT(DenominatorRat(n),p);
end);

#T ##########################################################################
Expand Down
1 change: 0 additions & 1 deletion src/code.c
Original file line number Diff line number Diff line change
Expand Up @@ -1763,7 +1763,6 @@ void CodeLongIntExpr (
}

/* otherwise stuff the value into the values list */
/* Need to fix this up for GMP integers */
else {
expr = NewExpr( T_INT_EXPR, sizeof(UInt) + SIZE_OBJ(val) );
((UInt *)ADDR_EXPR(expr))[0] = (UInt)TNUM_OBJ(val);
Expand Down
6 changes: 3 additions & 3 deletions src/compiled.h
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,9 @@ extern Obj GF_NEXT_ITER;
due to limb size or other aspects of the representation */

static inline Obj C_MAKE_INTEGER_BAG( UInt size, UInt type) {
/* Round size up to nearest multiple of INTEGER_ALLOCATION_SIZE */
return NewBag(type,INTEGER_ALLOCATION_SIZE*
((size + INTEGER_ALLOCATION_SIZE-1)/INTEGER_ALLOCATION_SIZE));
/* Round size up to nearest multiple of INTEGER_UNIT_SIZE */
return NewBag(type,INTEGER_UNIT_SIZE*
((size + INTEGER_UNIT_SIZE-1)/INTEGER_UNIT_SIZE));
}


Expand Down
Loading