0

So I wanted to calculate a sum from a particular projecteuler question using gp. Here's the, admittedly unreadable, code:

{
n = 10000;
m=100;
sum(k=1,n,eulerphi(k),0.) - (sum(k=1,n,eulerphi(k)*(k * binomial(n-k,m-1) + sum(p = max(m + k - n - 1,1), k-1, (k-p)*binomial(n+p-k-1,m-2),0.)), 0.))/binomial(n,m)
}

This code takes two minutes or three to output the answer on my fairly modest machine but it does it without going over the default parisize = 8000000 (around 8 MB of memory).

Now, I read somewhere that gp2c which compiles gp scripts into c code can improve performance.

So I just made a program.gp file:

calculate() = {n = 10000; m=100; sum(k=1,n,eulerphi(k),0.) - (sum(k=1,n,eulerphi(k)*(k * binomial(n-k,m-1) + sum(p = max(m + k - n - 1,1), k-1, (k-p)*binomial(n+p-k-1,m-2),0.)), 0.))/binomial(n,m)}

And run it with gp2c-run program.gp.

In the interactive prompt that comes up, I just executed calculate(). However, to my surprise, I got a stack overflow with it asking me to increase the stack size even when I changed parisizemax to almost 2 GB.

? default(parisizemax, 2000000000)
  ***   Warning: new maximum stack size = 2000003072 (1907.352 Mbytes).
? calculate()
  *** calculate: Warning: increasing stack size to 16000000.
  *** calculate: Warning: increasing stack size to 32000000.
  *** calculate: Warning: increasing stack size to 64000000.
  *** calculate: Warning: increasing stack size to 128000000.
  *** calculate: Warning: increasing stack size to 256000000.
  *** calculate: Warning: increasing stack size to 512000000.
  *** calculate: Warning: increasing stack size to 1024000000.
  *** calculate: Warning: increasing stack size to 2000003072.
  ***   at top-level: calculate()
  ***                 ^-----------
  *** calculate: the PARI stack overflows !
  current stack size: 2000003072 (1907.352 Mbytes)
  [hint] you can increase 'parisizemax' using default()

  ***   Break loop: type 'break' to go back to GP prompt

Why does the same program, when compiled to c need so much extra memory? For reference, the same program with n = 1000 instead of 10000 only shows the answer after increasing the stack size to 256000000 (250 MB) whereas it just needs the default 8 MB when just using gp. Something doesn't add up.

Oussema
  • 103
  • 3
  • 1
    This is really a [pari] question and NOT [pari-gp]. It looks like some memory leakage problem (since all you have is a couple of loops). I would suggest you are wasting your time trying to improve performance with gp2-c. (there is no reason it should be faster). Suggestion 1: Remove the 0.'s and do the computation with pure integers. Suggestion 2: The inner summation 'sum(p, (k-p)*binomial(n+p-k-1,m-2)' can probably be mathematically simplified to remove the sum. – Andrew May 14 '21 at 13:00
  • Thank you Andrew! I'll keep your advice in mind. – Oussema May 14 '21 at 15:30

1 Answers1

2

By default, neither gp2c nor gp2c-run generate code to handle the PARI stack, meaning you will get stack overflows quickly. Use gp2c-run -g program.gp: the -g flag will cause gp2c to clean up the stack as the computation progresses. There is such an example in the gp2c tutorial.

K.B.
  • 861
  • 5
  • 14
  • Is there a good reason to use gp2c without -g? – Charles Sep 15 '21 at 01:25
  • 1
    Three minor ones: studying the code core is simpler without GC statements, you may want to handcraft them later at the (usually few) places where they're really needed, and the code may end up a little faster without GC. But for a quick test or when you don't plan to look at the C code, -g should be your default. – K.B. Sep 25 '21 at 11:18