11
\$\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\$

10 Answers 10

9
\$\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\$
2
  • 1
    \$\begingroup\$ x\/1: is that designed to be a round operator, or just some sort of magic? \$\endgroup\$
    – primo
    Apr 23, 2016 at 5:41
  • 1
    \$\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, 2016 at 23:14
6
\$\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\$
1
6
\$\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)
  • Pol(s+O(x^n)) -> s%x^n if s is a rational function (e.g., 1/(1-x)) and n > 0
  • (1-x^n)/(1-x) -> x^n\(x-1)
  • matrix(n,n,i,j,e) -> matrix(n,,i,j,e)
  • a[2..#a] / a[2..-1] -> a[^1]
  • a[1..-2] -> a[^#a]
  • if(cond0,a,if(cond1,b,c)) -> if(cond0,a,cond1,b,c)
  • ceil(x) -> -x\-1
\$\endgroup\$
5
\$\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\$
5
\$\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\$
5
\$\begingroup\$

Know your built-ins

Like other computer algebra systems, PARI/GP also has a lot of built-ins for number theory, linear algebra, polynomials, and other branches of algebra.

The easy way to find a built-in is looking at the reference card.

Many built-ins have a prefix to indicate the types they work on. For example:

  • Built-ins for matrices usually have the prefix mat
  • Built-ins for polynomials usually have the prefix pol
  • Built-ins for power series usually have the prefix ser

When you are looking for a built-in, you can type the prefix in the REPL, and press tab. The command-line completion will tell you what functions it has.

To see the help message of a built-in in the REPL, just type ? functionname. For a more detailed help message, sometimes with examples, type ?? functionname.

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

Truthy and Falsy

There isn't a Boolean type in PARI/GP. Truthy and falsy are defined as the following:

  • Values that equal to 0 are falsy. This includes real number 0.0, complex number 0.0+0.0*I, polynomial 0*x, power series 0+O(x^3), modulo object Mod(0,3), and many others.
  • Vector and matrices that are empty or only contains falsy values are falsy. This includes nested falsy vectors like [0, [0, 0, [[]]]].
  • Everything else is truthy. In particular, lists, maps, strings, and Vecsmalls are always truthy even if they are empty or only contains falsy values.

The simplest way to convert a to the "default" truthy / falsy value (i.e., 1 / 0) is !!a.

When testing equality with ==, every falsy value is equal to 0. If you need to distinguish between different falsy values, use ===.

Use - to test equality

For a and b that can subtract, we can do:

  • if(a==b,c,d) => if(a-b,d,c)
  • a==b&&c => a-b||c if we only need the side effect of c.
  • a==b||c => a-b&&c if we only need the side effect of c.

Be careful when testing vector equality: only vectors that have the same length can subtract.

Any and All

There isn't built-in any or all function in PARI/GP.

When checking if a predicate is true for all or any integers in a range, we can just use sum or prod.

When checking if any item in a vector is truthy, we don't need a function: the vector itself is truthy if and only if any item in it is truthy.

When checking if all item in a vector is truthy, the following has the same length:

vecprod(a)
![!i|i<-a]

Initialize with truthy/falsy

When using functions like for, sum, prod, we usually initialize some variable to 0 and 1. If the previous expression returns the opposite truthy/falsy value, we can just use it. For example:

a=some_truthy_value;for(i=0,n,do_something())
=>
for(i=!a=some_truthy_value,n,do_something())
\$\endgroup\$
1
\$\begingroup\$

String replace

PARI/GP doesn't have a string replace built-in, but when you want to replace every occurrence of a in s by b, you can do strjoin(strsplit(s,a),b).

strjoin and strsplit are introduced in PARI/GP 2.13.0, so they are not supported on TIO.

\$\endgroup\$
1
\$\begingroup\$

Default parameters

In PARI/GP, function parameters default to 0. This can be useful when you need to initialize a variable to 0.

For example, instead of f(x)=i=0;..., you can write f(x,i)=....

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Along those lines, if you don't return anything, gnil is returned automatically, and it functions like 0 in most contexts. \$\endgroup\$
    – Charles
    May 11 at 12:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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