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 withgp -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
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/>.