NAME

gp-inline -- run Pari/GP code inline in a document

SYNOPSIS

gp-inline [--options] filename...

DESCRIPTION

gp-inline extracts and executes Pari/GP code from comments written inline in a document such as TeX or POD, or even in some C code or similar. This can be used to check calculations or formulas alongside their statement in a document. For example in TeX

Blah blah and from which it is seen that $1+1 = 2$.
% GP-Test  1+1 == 2

which is checked by running

gp-inline foo.tex

GP is a mathematical system and these checks will usually be for mathematical calculations and formulas, but can be useful even for just basic arithmetic.

Test

A GP-Test line must evaluate to 0 or 1. The evaluation is inside a function body so semicolons can separate multiple expressions and the last is the result.

% GP-Test  my(n=5); 2*n^2 + n == 55

Requiring a result 0 or 1 helps avoid mistakes like forgetting "== 123" etc. The suggestion is not to end GP-Test with a semicolon so that it can be pasted into GP to see the result when experimenting, but gp-inline works with or without.

The suggestion is also to keep variables local with my to avoid one test depending on another accidentally, but that's not enforced. See "Definitions" below for making global variables.

Multi-line tests can be written with GP style backslashing

% GP-Test  some_thing() \
% GP-Test    == 123

Comments can be included in a test in GP /* ... */ style. Don't use \\ style as the expressions gp-inline constructs don't work properly with that yet.

% GP-Test  105 == 3*5*7  /* its prime factors */

Tests are run with gp -f so any ~/.gprc or $GPRC file is not evaluated. This is designed to give consistent test results without personal preferences wanted for gp interactively etc.

Prefix

The following prefixes are recognised for a GP-Test line (etc)

GP-Test  1+1==2
# GP-Test  1+1==2
% GP-Test  1+1==2
/* GP-Test  1+1==2  */
 * GP-Test  1+1==2
// GP-Test  1+1==2

=for GP-Test  1+1==2

These are comments in Perl, TeX, C, C++, and Perl POD directive =for. In C style /* an optional trailing */ is stripped. Or its comment parts can be on separate lines if desired

/*
   GP-Test  1+1==2
 */

/*
 * GP-Test  1+1==2
 */

A Perl POD =for should be a single line and will usually want a blank line before and after to be valid POD. Those blanks can be a tedious for many tests and in that case the suggestion is to =cut and write a block of tests

=cut

# GP-Test  2+2==4
# GP-Test  4+4==8

=pod

The # prefix here is not needed if already after an __END__ so not evaluated by Perl, but it's a good way for human readers to distinguish those lines from the POD text.

Definitions

Definition lines can create new GP functions or globals

% GP-DEFINE  my_func(n) = 2*n + 3;
% GP-DEFINE  my_vector = [ 1, 2, 3, 5 ];

These lines are arbitrary code passed directly to GP. Generally they should end with a ; to suppress result printing in the usual way, but that's not enforced. Multi-line functions or expressions can use either backslashing or braces

% GP-DEFINE  long_func(n) =   \
% GP-DEFINE    some + long    \
% GP-DEFINE    - expression;

% GP-DEFINE  my_matrix = {[
% GP-DEFINE    1, 2;
% GP-DEFINE    2, 1
% GP-DEFINE  ]};

Definition lines can also make initial settings. For example strictargs=1 is a good way to guard against mistakes in function arguments (assuming you're not deliberately lazy with such things)

% GP-DEFINE  default(strictargs,1);

External GP code modules can be included with the usual read(). Normally this will be in a GP-DEFINE.

% GP-DEFINE  read("my-library.gp");

Test Last

GP-Test-Last tests are run last, after the rest of the input file. This lets a test precede a formula or data definition it depends on. This doesn't happen often, usually only when some a document gives examples of a formula before the full statement. If you keep the function definition with the statement of the formula then GP-Test-Last allows tests to be written before.

We will want f(6)=10 and ...
% GP-Test-Last  f(6) == 10

The unique function satisfying is then f(n) = 2n - 2.
% GP-DEFINE  f(n) = 2*n - 2;

Care should be taken not to redefine globals which GP-Test-Last tests will use. But it's wise anyway not to change the meaning of globals through a document so that rearranging sections etc doesn't upset the checks.

Errors

Syntax errors and type errors in tests and definitions are fatal. The current implementation runs gp --default recover=0 so such problems cause a non-zero exit code. A location string is included in the test expression so the backtrace has something like

*** at top-level: ...inline("foo.tex:153",(()->bar())())
...

which means input file foo.tex line 153 was the offending GP-Test.

Errors in GP-DEFINE statements don't have this location in the backtrace (since they're a "top-level" evaluation). If the offending part is not obvious then try gp-inline --verbose to see a \e trace of each expression. It includes some "foo.tex:150" etc strings which are the source locations.

(This locations printing is not very good. An equivalent of #line would help. Or is there a way to insert a print before an error backtrace? An iferr() trap loses the backtrace.)

Constants, Vectors and Matrices

Numbers in the document text can be extracted as GP definitions. For example a constant foo=123,

% GP-CONSTANT  foo
   123
% GP-END

Or a vector bar=[1,2,3],

% GP-VECTOR  bar
   1, 2, 3
% GP-END

Or a matrix quux=[1,2; 3,4],

% GP-MATRIX  quux
   1 & 2 \\ 3 & 4
% GP-END

These GP definitions can be used in subsequent tests, and the numbers are also document text or program code, etc. The number forms accepted are

123                  integer
{-}1                 signs, optionally with TeX {}
1.42                 decimal fraction
\frac58              TeX \frac, \tfrac, \dfrac
\tfrac{12}{34}
-3-4i                complex number, lower case i
\tfrac{5}{2+i}       fractions with complex numbers

, &                  vector separator commas
\\                   matrix row separator

Multiple commas etc are treated as just one. The matrix separator \\ is treated as comma in a VECTOR. There should be just one value in a CONSTANT but leading or trailing commas are ignored.

Decimal fractions 12.45 become rationals like 1245/100 to preserve an exact value. If it's some irrational which has been truncated then staying it exact lets you make an exact check of all the decimals given.

The number syntax accepted is quite strict. This is designed to ensure gp-inline doesn't quietly ignore something which it wasn't supposed to.

Various bits of TeX are ignored. These are things often wanted in a list of numbers. However in general it's best to confine GP-CONSTANT etc to just the numbers and keep TeX outside.

=                           initial = sign
&=                          initial TeX align and = sign
\, \; \quad \qquad          various TeX spacing and macros
\kern1.5em                  measures em,ex,pt,mm,cm,in
\hspace{5pt}
\phantom{...}              
\degree
\dotsc \dotsb

\kern should be a single numbered measure em, ex. Don't use a comma for the decimal, and don't use plus etc calculations. \phantom{} cannot contain nested { } braces (though it can contain equivalent \begingroup and \endgroup if desired).

Comments, both TeX or other styles, cannot be in a list of numbers. Perhaps this will change.

Other Notes

When including numbers in a document there's a bit of a choice between writing them in the document and applying checks, versus generating the numbers externally and #include (or equivalent) to bring them in. The latter has the disadvantage of several little files (probably), the former is a little tedious to write manually but then isn't vulnerable to breakage in a generator program.

Various arithmetic programs or computer algebra systems could be used in a similar way to gp-inline. GP has the attraction of a compact syntax for calculations and new functions, and having a range of arbitrary precision basic types such as fractions, complex numbers, polynomials, even quads for exact square roots, plus a lot of number theory things for higher mathematics.

OPTIONS

The command line options are

--run

Run the inline tests in each given file. This is the default action.

--stdin

Read a document from standard input (instead of named files).

--extract

Extract the inline gp code from each file and print to standard output. This output is what --run would run with gp -f.

Usually --extract should be used on just one input file, otherwise the tests of each file are output one after the other and globals left by the first might upset later tests.

--defines

Extract just the definitions from the given files and print to standard output.

This is good for extracting definitions so they can be used separately in further calculations or experiments. It's also possible to go the other way, have definitions in a separate file which the document loads with read(). Usually it avoids mistakes to keep a definition with the formula etc in the document. But generic or very large code could be kept separate.

--help

Print a brief help message.

--version

Print the program version number and exit.

EXIT CODE

gp-inline exits with 0 if all tests in all files are successful, or non-zero if any problems.

BUGS

There's no support for a multi-file document where defines would be carried over from one part to the next. The suggestion is either to cat them together and pass a single file, possibly to gp-inline --stdin; or use --defines to get the definitions from one file and do a read() of them in the next. The latter is good to get the defines out of a main document which can then be read into a separate work-in-progress document which has text and tests destined for the main, when ready.

The GP-VECTOR and GP-MATRIX number syntax is not enough for all purposes. There will always be some layout which is too specific for gp-inline to recognise. The suggestion in that case is to write GP-DEFINE beside the relevant values. The duplication is not nice, but done once and with the define right beside the numbers it's not too bad.

Some sort of GP-POLYNOMIAL to pick a polynomial out some TeX could be good. It could include polynomial fractions (t_RFRAC) since they're a native type in GP and suit generating functions.

SEE ALSO

gp(1)

HOME PAGE

http://user42.tuxfamily.org/gp-inline/index.html

LICENSE

Copyright 2015 Kevin Ryde

gp-inline is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.

gp-inline is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with gp-inline. If not, see <http://www.gnu.org/licenses/>.