Tips for golfing in PARI/GP

6

PARI/GP is a free computer algebra system. It is designed for (algebraic) number theory, not golfing, but that's part of the attraction. Unsurprisingly, it fares best at mathematical tasks; its support for string manipulation is primitive. (Having said that, advice for golfing non-mathematical tasks is also welcome.)

As usual, please post one tip per answer.

These tips should be at least somewhat specific to PARI/GP; advice which applies to 'most' languages belongs at Tips for golfing in <all languages>. Some general tips which don't need to be included:

  1. Compress whitespace. (In GP all whitespace outside of strings is optional.)
  2. Use single-character variables. (There are 50 choices, a-z and A-Z except I and O.)
  3. Use < and > rather than <= and >= when possible.
  4. Chain assignments. (a=b=c or a+=b*=c)

Charles

Posted 2016-04-21T19:00:51.057

Reputation: 2 435

Answers

6

Use operators to replace commands (or longer operators!) when possible.

length(v)#v (saves 5-7 bytes)

matsize(M)[2]#M (saves 9-11 bytes)

matsize(M)[1]#M~ (saves 8-10 bytes)

floor(x)x\1 (saves 3-5 bytes)

round(x)x\/1 (saves 2-4 bytes)*

shift(x,n)x>>n or x<<n (saves 2-6 bytes)

sqr(x)x^2 (saves 1-3 bytes)

deriv(x)x' (saves 4-6 bytes)

mattranspose(M)M~ (saves 11-13 bytes)

factorial(n)n! (saves 8-10 bytes)

&&& (saves 1 byte; note that this syntax is deprecated)

||| (saves 1 byte; only works in older versions)

* Prior to 2.8.1 (2016) the \/ operator did not work correctly on t_REAL numbers—update if you haven't!

Charles

Posted 2016-04-21T19:00:51.057

Reputation: 2 435

x\/1: is that designed to be a round operator, or just some sort of magic? – primo – 2016-04-23T05:41:32.987

@primo: Yes, it's a round operator. Not very well-known, though, so I thought I'd mention it. Of course round(x/6) to x/6 is an even bigger win... – Charles – 2016-04-23T23:14:00.290

4

Use set-builder notation to replace apply and select.

apply(x->thing1(x)&&thing2(x),select(condition,v))[thing1(x)&&thing2(x)|x<-v,condition(x)]

or

apply(x->thing1(x)&&thing2(x),v)[thing1(x)&&thing2(x)|x<-v]

but if you're applying a named function, apply is better, since the arguments are implicit:

[functionName(x)|x<-v]apply(functionName,v)

Charles

Posted 2016-04-21T19:00:51.057

Reputation: 2 435

3

  • In a string context (e.g. the arguments of print or Str), commas are unnecessary:

    i=99
    print(i" bottles of beer on the wall")
    

    This is even true if one of the arguments is an assignment. The following is equivalent to the above:

    print(i=99" bottles of beer on the wall")
    
  • Unassigned variables evaluate to their name in a string context:

    for(i=1,2,print(i" bottl"e" of beer on the wall.");e=es)
    

    produces:

    1 bottle of beer on the wall.
    2 bottles of beer on the wall.
    
  • In a multi-line context { ... }, the closing brace is unnecessary.

    print({"this is line one
    this is line two")
    

Documentation

In REPL:
?* - show all commands.
?<command> - show brief documentation for a command.

Online documentation:
http://pari.math.u-bordeaux.fr/dochtml/html.stable/

primo

Posted 2016-04-21T19:00:51.057

Reputation: 30 891

2

Some replacements:

  • poldegree(f) -> #f'
  • subst(f,x,y) -> x=y;eval(f) if x is not used elsewhere
  • subst(f,x,0) -> f%x but its type is t_POL instead of t_INT
  • polcoeff(s+O(x^(n+1)),n) -> Pol(s+O(x^n*x))\x^n but its type is t_POL
  • polcoeff(s+O(x^(n+1)),n) -> Vec(s+O(x^n++))[n] if the constant term of s is nonzero
  • Vecrev(v)~ -> Colrev(v)

alephalpha

Posted 2016-04-21T19:00:51.057

Reputation: 23 988

2

Use specialized loops.

GP provides (at least) the following loops: for, forcomposite, fordiv, forell, forpart, forprime, forstep, forsubgroup, forvec, prod, prodeuler, prodinf, sum, sumalt, sumdiv, sumdivmult, suminf, sumnum, sumnummonien, sumpos.

So don't write s=0;for(i=1,9,s+=f(i));s when you could write sum(i=1,9,f(i)), don't write for(n=1,20,f(prime(n))) when you could write forprime(p=2,71,f(p)), and certainly don't write apply(v->print(v),partitions(4)); instead of forpart(v=4,print(v)).

prodeuler can be useful as a product over the primes, but note that it returns a t_REAL rather than a t_INT, so rounding at the end may be necessary depending on the task.

sumdiv can be a real lifesaver compared to a simple loop over divisors.

forvec is a replacement for a whole collection of loops. You can replace (ungolfed)

{
for(i=0,9,
  for(j=i,99,
    for(k=i,200,
      f(i,j,k)
    )
  )
);
}

with

forvec(v=[[0,9], [0,99], [0,200]],
  call(f, v)
,
  1 \\ increasing sequences only
)

Charles

Posted 2016-04-21T19:00:51.057

Reputation: 2 435

1

Avoid return when possible.

The final value in the function is returned, so don't write ...;return(x) but just ...;x.

If you must use return, note that the bare for return yields the PARI value gnil, which is falsy (coerced into a GP 0 or PARI gen_0 as needed), so you can usually write return rather than return(0).

And (almost?) needless to say, but if you have two values to choose from, much better to return if(condition,x,y) than if(condition,return(x));y.

Charles

Posted 2016-04-21T19:00:51.057

Reputation: 2 435