6
\$\begingroup\$

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)
\$\endgroup\$
6
\$\begingroup\$

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!

\$\endgroup\$
  • \$\begingroup\$ x\/1: is that designed to be a round operator, or just some sort of magic? \$\endgroup\$ – primo Apr 23 '16 at 5:41
  • \$\begingroup\$ @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... \$\endgroup\$ – Charles Apr 23 '16 at 23:14
4
\$\begingroup\$

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)

\$\endgroup\$
3
\$\begingroup\$
  • 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/

\$\endgroup\$
2
\$\begingroup\$

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
)
\$\endgroup\$
2
\$\begingroup\$

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)
\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.