==============================================
Computer Algebra with Pure: A Reduce Interface
==============================================
.. default-domain:: pure
.. module:: reduce
Version 0.4, |today|
| Albert Graef
| Kurt Pagani
One of Pure's distinguishing features as a term rewriting programming language
is that it makes the symbolic manipulation of expressions very easy and
convenient. It is thus a natural environment for hosting a full-featured
computer algebra system (CAS). Computer algebra systems are complex pieces of
software featuring advanced algorithms for simplification of algebraic
expressions, symbolic integration, equation solving and much more.
Reimplementing all these algorithms in Pure would be a major undertaking, to
say the least. A much better option is to interface to an existing CAS which
has already proven its worth to the scientific computing community, has been
tested extensively and is known to be both reliable and efficient.
This is also the approach taken by Pure's :mod:`reduce` module which
interfaces to the well-known Reduce_ system. Along with Macsyma/`Maxima`_,
Reduce is one of the oldest computer algebra systems which has been around
since the 1960s and is widely recognized as a state-of-the-art, powerful and
efficient CAS. It is free/open source software distributed under a BSD-style
license_, actively maintained on its SourceForge_ website, and implementations
exist for all major computing platforms. The :mod:`reduce` module makes the
functionality of Reduce available in Pure in a seamless way. It uses an
"embedded" version of Reduce in the form of a shared library which is easy to
build from the Reduce sources; the Installation_ section below describes how
to do this. More background information and a discussion of the interface can
be found in the `Embedding REDUCE`_ thread on the Pure mailing list.
.. _Reduce: http://reduce-algebra.sourceforge.net/
.. _Maxima: http://maxima.sourceforge.net/
.. _SourceForge: http://sourceforge.net/projects/reduce-algebra/
.. _license: http://www.reduce-algebra.com/license.htm
.. _Embedding REDUCE: http://groups.google.com/group/pure-lang/browse_thread/thread/c11e82ca2e9e8cbb
The interface can be found in the reduce.pure module. It has two parts, a
`low-level interface`_ which consists of a handful of C entry points supplied
by the Reduce library, and a `high-level interface`_ which provides everything
that the Pure programmer needs to use Reduce from Pure. Please note that at
present this module is still experimental. But the basic functionality works,
and you're welcome to discuss the new interface on the mailing list and/or
submit bug reports and patches.
Copying
=======
pure-reduce is available under the same 2-clause BSD license_ as Reduce
itself, please see the accompanying COPYING file and the reduce.pure file for
details.
Installation
============
Get the latest source from
https://bitbucket.org/purelang/pure-lang/downloads/pure-reduce-0.4.tar.gz.
You'll need both the Reduce library (named reduce.so, reduce.dylib or
reduce.dll, depending on the system you have) and a Reduce image file
(reduce.img) to make this module work. A Makefile is included with this
package so that you can build these yourself from the Reduce sources. (In
principle, this only needs to be done once for the initial installation of
this module, but you may want to repeat this procedure every once in a while
to get the latest Reduce version.)
The full Reduce system is a big package, so we have packaged a stripped-down
version of the Reduce source which contains all the bits and pieces needed to
compile the Reduce library and image, and has also been patched up so that it
compiles cleanly on recent Linux systems. At the time of this writing, you can
find this package here:
https://bitbucket.org/purelang/pure-lang/downloads/reduce-algebra-csl-r2204.tar.bz2
(You may want to check the download section on the Pure website for newer
revisions of this package, since we may update the package from time to time
to the latest source from the Reduce svn repository.)
Unpack the reduce-algebra-csl tarball and move the resulting reduce-algebra
directory into the pure-reduce source directory. Run ``make`` and then (if
needed) ``make install`` in the pure-reduce directory (*not* in the
reduce-algebra directory!). You should also run ``make check`` which performs
a few tests in order to verify that the interface works ok (this can be done
without installing the package, but needs the Reduce image and library).
For convenience, the Makefile also has a ``make reduce`` target which builds a
minimal Reduce executable. If you use that option, ``make install`` installs
this executable along with the library and image files, so that you can then
run Reduce directly from the command line by just typing ``reduce``. Please
note that this is a really minimalistic Reduce frontend which is most useful
for testing purposes. (If you want the full Reduce version then you can find
binary Reduce packages for various systems at SourceForge_. But note that
neither the minimalistic nor the full Reduce frontend is required for the
pure-reduce module in any way.)
It is also possible to build the Reduce library and image directly from the
latest source in the Reduce svn repository. You can check out the repository
with the following command:
.. code-block:: console
svn co svn://svn.code.sf.net/p/reduce-algebra/code/trunk reduce-algebra
This pulls down many hundreds of megabytes, so this may take a while. Once the
checkout is finished, you'll end up with a reduce-algebra directory which you
can drop into the pure-reduce source directory and proceed with the
compilation as described above. Note that if you go that route then you should
be prepared to deal with compilation problems in the Reduce sources. Reduce is
a big and complicated software, so the svn sources are not always in a state
which guarantees smooth compilation on all supported systems. If you run into
problems then please consider using our streamlined reduce-algebra-csl package
instead.
..
Low-Level Interface
===================
The low-level interface is a straight wrapper of the C entry points
provided by the Reduce library, also known as the "procedural" or PROC_
interface, for short. It uses an embedded version of Reduce which runs on a
free and open-source Lisp flavour known as CSL_ (Codemist Standard
Lisp). The external C routines are all declared in the ``reduce``
namespace. Normally you shouldn't have to call these functions directly,
since we provide a high-level, idiomatic Pure interface which makes calling
Reduce from Pure much easier, see below.
.. _PROC: http://reduce-algebra.svn.sourceforge.net/viewvc/reduce-algebra/trunk/csl/cslbase/proc.h?view=markup
.. _CSL: http://lisp.codemist.co.uk/
..
High-Level Interface
====================
The high-level interface provides a wrapper of the low-level PROC interface
which makes calling Reduce from Pure easy and convenient. After installing
the module, it can be imported in your Pure scripts as follows::
using reduce;
This starts up Reduce and makes the following variables and functions
available in Pure.
Starting and Stopping Reduce
----------------------------
.. variable:: REDUCE_PATH
This variable holds a colon-delimited search path used to locate the
Reduce image file (see :func:`reduce::start` below). By default this
includes the current directory and the Pure library directory.
.. function:: reduce::start image::string args::smatrix
Initializes the Reduce system. This is done automatically when loading
this module, so normally you shouldn't have to call this manually,
unless the default image file wasn't found or you want to restart the
Reduce system with your own image file or your own set of options. When
calling this operation manually, you need to specify the name of the
Reduce image file and any desired extra arguments as a string vector.
Unless the filename contains a slash, :func:`reduce::start` searches the
directories in :var:`REDUCE_PATH` for the image file. An exception is
raised if the image file isn't found.
.. function:: reduce::finish
Finalizes the Reduce system. You can call this to release the resources
of the Reduce system. (:func:`reduce::start` also invokes this
automatically if a Reduce instance is already running, so it isn't
necessary to call :func:`reduce::finish` in this case.)
Maintenance Operations
----------------------
.. function:: reduce::verbosity n
Sets the verbosity level; 0 means no messages at all (which is the
default when using this module), and the following values may be or'ed
together to pick what you need:
1: messages whenever garbage collection happens
2: messages whenever a module of code is loaded
4: extra details in the garbage collector messages
.. function:: reduce::switch name:string val::int
Lets you change global Reduce options. This works like Reduce's ``on``
and ``off`` declarations; please check the Reduce documentation for
details.
.. function:: reduce::capture flag::int
reduce::output
Captures output from Reduce. If ``flag`` is nonzero,
:func:`reduce::capture` arranges for all output from Reduce to be
buffered. The contents of the buffer can then be read using the
:func:`reduce::output` function which returns a string value. If
``flag`` is zero, capturing is disabled so that output goes to stdout
again.
.. function:: reduce::feed s::string
Feeds input to Reduce. Reduce will read input from the given string
``s``, switching back to stdin after ``s`` has been processed.
.. function:: reduce::load name::string
Loads Reduce packages. This works like Reduce's ``load_package``
command; please check the Reduce documentation for details.
.. function:: reduce::in name::string
Sources the given Reduce (.red) file. This works like the Lisp ``in``
function. Output is captured using :func:`reduce::capture`, see above.
Evaluation
----------
.. _TeXmacs: http://www.texmacs.org
For convenience, the following operations are in the default namespace:
.. function:: simplify x
This is the main entry point. It takes an algebraic expression in Pure
format and tries to simplify it using Reduce. The result is then
converted back to Pure format. Note that you need to quote ``x`` if you
want to prevent it from being evaluated on the Pure side.
.. function:: simplifyd x
A variation of :func:`simplify` which takes care of customary
mathematical notation for limits, integrals and differentials, so that
you can write stuff like ``d f/d x`` and ``lim n inf (1/n)`` and have
that expanded to the corresponding Reduce calls automatically. This also
tries to support most of the idioms and variations of notation which can
be seen in output of the Reduce ``tmprint`` module and which are
commonly used in TeXmacs_ documents.
.. function:: lisp x
This can be used to execute arbitrary Lisp code, which is sometimes
necessary to perform special functions in the Reduce system. Note that
you need to quote ``x`` if you want to prevent it from being evaluated
on the Pure side. This is true, in particular, for the quote itself,
which needs an extra level so that one quote goes through to the Lisp
system (e.g.: ``lisp (''(a b c))``). For convenience, free symbols are
quoted automatically, and Pure lists are mapped to corresponding Lisp
lists and vice versa (so ``lisp [a,b,c]`` actually yields the same
result as ``lisp (''(a b c))``). The result is always a Pure list or an
atomic value.
.. function:: lispval x
This converts a Pure expression to its Reduce equivalent, like
:func:`simplify` does, but without actually simplifying it. As with the
other functions, you need to quote ``x`` if you want to prevent it from
being evaluated on the Pure side. The result is the Pure representation
of a Lisp form which can be passed as a value to other Lisp routines by
employing the :func:`lisp` function. (Normally this requires that you
double-quote the expression so that it doesn't get evaluated by the Lisp
interpreter.) This function isn't for casual usage, but may be useful
if you need to pass a Reduce expression to some Lisp function which
cannot be called through :func:`simplify`.
.. function:: lispsym s::string
This function creates a special Pure identifier for any symbol given as
a string, even symbols which don't conform to Pure syntax. This is
sometimes needed to specify special Lisp symbols in calls to
:func:`lisp`, such as ``lisp (lispsym "oem-supervisor")``. (Note that if
such a special symbol occurs as a literal in a result returned by
:func:`lisp` or :func:`simplify` then it will get mangled into a form
which conforms to Pure syntax.)
.. function:: declare declsym [foo,bar,...]
Declare symbols and their properties; please see the Declarations
section in the Reduce manual for details. The second argument can also
be a singleton symbol. In the present implementation, ``declsym`` must
be one of:
* ``operator``: declares an operator symbol;
* ``precedence``: declares an infix operator and optionally
specifies its precedence (giving the symbol priority over a second
given symbol);
* ``antisymmetric``, ``symmetric``, ``even``, ``odd``, ``linear``,
``noncom`` and ``nonzero``: declares properties of already declared
operator symbols;
* ``depend``, ``nodepend``, ``factor``, ``remfac``, ``order``,
``korder``: declares kernel dependencies and orders. These take both
symbols and "kernels" as arguments (the latter are simple prefix
expressions which denote irreducible subterms such as ``cos x``;
Reduce treats these more or less like variables in algebraic
simplifications).
.. function:: precision prec::int
Sets the internal Reduce precision in decimal digits for floating point
calculations, and returns the previously set precision. This takes
effect when rounded mode is enabled (``reduce::switch "rounded" 1``).
Note that at present this only affects Reduce's internal precision,
floating point values are still returned as double precision numbers in
Pure land.
.. function:: plotreset
This is identical to the ``plotreset`` command provided by Reduce's
gnuplot_ interface, and is sometimes needed to reset the plot subsystem.
.. _gnuplot: http://www.gnuplot.info/
In Pure land, Reduce expressions are represented using Pure's standard
curried notation. Marshalling of numeric data works in a straightforward
fashion and includes all natively supported Pure data types (machine ints,
bigints, doubles, rationals and complex numbers). Some special conversions
are applied to algebraic expressions to make arithmetic operations such as
``+``, ``*`` etc. work as expected. In addition, the ``==``, ``=>``, ``..``
and ``:=`` infix operators can be used to denote equations, replacement
rules, ranges and assignments in Reduce, respectively. (Note that you may
have to quote these in some cases so that they don't get evaluated on the
Pure side.) Also, Reduce's ``arbconst n``, ``arbint n`` and ``arbcomplex
n`` terms can be mapped to Greek symbols ``αn``, ``βn`` and ``ζn`` on the
Pure side. (This may cause issues in environments without proper Unicode
support, so it's disabled by default.) For debugging purposes, all these
automatic conversions can also be turned off on the output side with the
'``#! --disable mapped``' compilation pragma; this needs to be placed
*before* the '``using reduce;``' import clause to take effect. There are a
number of other conditional compilation options which may be used to
selectively turn off some of the conversions; please check the module
source for details.
Lisp expressions are handled in a similar fashion, but here only a few
basic Pure data types (integers, doubles, strings and lists) are converted
to and from corresponding Lisp data. Function applications in Pure's
curried notation are mapped to corresponding Lisp forms. The result of
invoking :func:`lisp` is always one of the supported atomic types or a Pure
list.
The :func:`lisp` function is to be used with care. An orderly Pure
exception is raised if you try to execute a non-existing Lisp function. But
there are some internal functions in Reduce which aren't very forgiving if
you try to execute them with invalid arguments, and will most likely crash
the Reduce system in such cases. You have been warned!
Basic Examples
==============
Here is a simple example showing how to start up Reduce and do some
calculations::
> using reduce;
Reduce (Free CSL version), 27-Sep-12 ...
> simplify $ df ((x+5)^3) x;
3*x^2+30*x+75
> simplify $ intg (exp (2*x)) x;
e^(2*x)/2
> simplify $ solve (x^2+7) x;
[x==sqrt 7*i,x==-sqrt 7*i]
Note that the result returned by :func:`simplify` is always a quoted
expression. If the expression can be further reduced on the Pure side,
you'll have to use Pure's :func:`eval` function to force its evaluation::
> using math;
> eval ans;
[x==0.0+:2.64575131106459,x==0.0+:-2.64575131106459]
The following example shows how you can do a simple plot using Reduce's
gnuplot_ module::
> simplify $ plot [sin x/x, x=='(-20..20), terminal=="wxt"];
0
This pops up a wxWidgets window (``terminal=="wxt"``) with a plot of the given
function in it, see the screenshot_ below. The ``x=='(-20..20)`` argument
specifies the desired range of the ``x`` variable (note that the range needs
to be quoted so that it gets through to Reduce rather than being evaluated on
the Pure side).
.. _screenshot:
.. figure:: gnuplot.png
:scale: 70%
:align: center
Reduce gnuplot example.
The same plot can be written to a PostScript file sinc.ps as follows::
> simplify $ plot [sin x/x, x=='(-20..20), terminal=="postscript", output=="sinc.ps"];
0
The :func:`lisp` function can be used to execute Lisp code in the CSL
interpreter hosting the Reduce system. Here are some basic examples. Note
that, to be on the safe side, we just always quote the argument to
:func:`lisp` here to prevent its evaluation on the Pure side. ::
> lisp ('plus 2 3);
5
> lisp ('car (list a b c d e));
a
> lisp ('cdr [a,b,[c,d],e]);
[b,[c,d],e]
Lisp's truth values are ``t`` and ``nil``; the latter is just the empty list,
so that's what you get if a Lisp predicate evaluates to "false"::
> lisp ('lessp 5 3);
[]
> lisp ('greaterp 5 3);
t
Most simple kinds of Lisp calls should be doable that way, but don't expect
any miracles; the :func:`lisp` function is provided to access special
functionality in the "symbolic mode" of the Reduce system, not to turn Pure
into a full-featured Lisp frontend. The following example illustrates how you
can use the :func:`lisp` function to declare an operator symbol and change or
query its properties::
> lisp ('operator [myop]);
[]
> lisp ('flag [myop] odd);
[]
> lisp ('prop myop);
[odd:t,simpfn:simpiden]
> simplify (myop (-x));
-myop x
If you find it awkward to evaluate Lisp forms in Pure, you can also achieve
the same with the :func:`declare` function which covers most of the common
Reduce declarations that might be needed::
> declare operator myop;
[]
> declare odd myop;
[]
> simplify (myop (-x));
-myop x
For basic Pure-based usage of Reduce, it's convenient to have a simple
read-eval-print loop which lets you type some declarations and expressions to
be simplified (in Pure syntax), and takes care of all the quoting and invoking
:func:`simplify` for you. Here's a little Pure script which does that::
using math, reduce, system;
/* You might want to replace this with the real readline if you have the
corresponding Pure module installed. See the red.pure script in the
distribution for details. */
myreadline prompt::string = fputs prompt stdout $$ fflush stdout $$ gets;
red = loop with
// A simplistic REPL.
loop = case myreadline "> " of
s::string = process s $$ loop if ~null s;
_ = () otherwise;
end;
// Get rid of trailing blanks and semicolons.
process s = process (init s) if any (==last s) [" ",";"];
// Process a declaration or REDUCE expression.
process s = case val s of
val _ = fputs "** syntax error\n" stderr if ~null lasterr;
on flag = reduce::switch (str flag) 1;
off flag = reduce::switch (str flag) 0;
x@(declare _ _) = eval x;
x = puts (str (simplify x)) otherwise;
end;
end;
Now you can run ``red`` at the Pure prompt and start typing the stuff you want
to evaluate, one expression or declaration per line. Enter an empty line or
:kbd:`Ctrl-D` when you're done to return to the Pure command prompt. ::
> red;
> df ((x+5)^3) x
3*x^2+30*x+75
> intg (exp (2*x)) x
e^(2*x)/2
> on rounded
> solve (x^2+7==17) x
[x==3.16227766016838,x==-3.16227766016838]
> off rounded
> solve (x^2+7==17) x
[x==sqrt 10,x==-sqrt 10]
> declare operator myop
> declare odd myop
> myop (-x)
-myop x
> plot [sin x/x, x==(-20..20), terminal=="wxt"]
0
> ^D
()
Note that we barely scratched the surface here; Reduce is a very complex
system with lots of capabilities. The following section explores some of these
areas in more detail.
Examples by Topic
=================
This is a small excerpt from the **REDUCE User's Manual** `[REDUM]`_,
translated to Pure syntax. For any details we refer to that document. With
this guide it should be straightforward to translate back and forth between
Pure and REDUCE syntax for the invocation of REDUCE functions. The one thing
you have to keep in mind is that Pure uses *curried* notation for function
applications, so where a function is invoked as ``f(x,y,z)`` in REDUCE, you'll
have to call it as ``f x y z`` in Pure (with parentheses around each argument
which is a compound expression).
The REDUCE User's Manual as well as the documentation of each package and
other valuable information may be found at:
http://www.reduce-algebra.com/documentation.htm
Differentiation
---------------
The operator ``df`` is used to represent partial differentiation with respect
to one or more variables.
.. describe:: df exprn [var ]+
Differentiation of the function :math:`x^2 y^3 z^4` with respect to
:math:`x,y,z`, two, three and four times respectively, i.e
:math:`\frac{\partial^9 x^2 y^3 z^4}{\partial x^2 \partial y^3 \partial z^4}`:
.. code-block:: pure
> simplify $ df (x^2*y^3*z^4) x 2 y 3 z 4 ;
288
The derivative of :math:`\log \sin (x)^2`:
.. code-block:: pure
> simplify $ df (log(sin x)^2) x;
2*cos x*log (sin x)/sin x
Note the parentheses.
Suppose :math:`z(\cos(x),y)`. Let's calculate :math:`\frac{\partial \sin(z)}
{\partial \cos(x)}` and :math:`\frac{\partial z^2}{\partial x}` :
.. code-block:: pure
> declare depend [z,cos x,y];
[]
> simplify (df (sin z) (cos x));
cos z*df z (cos x)
> simplify (df (z^2) x);
2*df z x*z
Note how to declare dependencies.
The results are :math:`\cos(z) \frac{\partial z}
{\partial \cos(x)}` and :math:`2 z \frac{\partial z} {\partial x}`,
respectively, as expected.
Integration
-----------
``INT`` is an operator in REDUCE for indefinite integration using a
combination of the Risch-Norman algorithm and pattern matching.
.. describe:: intg exprn var
Note that in Pure the operator is called ``intg`` in order not to clash
with the :func:`int` conversion function.
Example 1:
.. math:: \int \frac{1}{a x + b} dx
.. code-block:: pure
> simplify $ intg (1/(a*x+b)) x;
log (a*x+b)/a
Example 2:
.. math:: I(a,b,n) = \int x^2 (a x + b)^n dx
.. code-block:: pure
> I a b n = simplify $ intg (x^2*(a*x+b)^n) x;
> I a b n;
((a*x+b)^n*a^3*n^2*x^3+3*(a*x+b)^n*a^3*n*x^3+2*(a*x+b)^n*a^3*x^3+
(a*x+b)^n*a^2*b*n^2*x^2+(a*x+b)^n*a^2*b*n*x^2-2*(a*x+b)^n*a*b^2*
n*x+2*(a*x+b)^n*b^3)/(a^3*n^3+6*a^3*n^2+11*a^3*n+6*a^3)
> I a b 0 ;
x^3/3
> I 0 b n;
b^n*x^3/3
> I a 0 k;
x^k*a^k*x^3/(k+3)
Example 3:
.. math:: \int \frac{\sqrt{x+\sqrt{x^2+1}}}{x} dx
.. code-block:: pure
> simplify $ intg (sqrt(x+sqrt(x^2+1))/x) x ;
intg (sqrt (sqrt (x^2+1)+x)/x) x
Apparently no solution was found. There is a package ``ALGINT`` in REDUCE
which specifically deals with algebraic functions. The REDUCE User's Manual
`[REDUM]`_ says:
.. pull-quote:: *This package [...] will analytically integrate a wide range
of expressions involving square roots where the answer exists in that class
of functions. It is an implementation of the work described in
J.H. Davenport* `[LNCS102]`_.
.. code-block:: pure
> reduce::load "algint" ;
0
> simplify $ intg (sqrt(x+sqrt(x^2+1))/x) x ;
atan ((sqrt (sqrt (x^2+1)+x)*sqrt (x^2+1)-sqrt (sqrt (x^2+1)+x)*x-sqrt
(sqrt (x^2+1)+x))/2)+2*sqrt (sqrt (x^2+1)+x)+log (sqrt (sqrt
(x^2+1)+x)-1)-log (sqrt (sqrt (x^2+1)+x)+1)
Note how to load packages.
Length, Map and Select
----------------------
``LENGTH`` is a generic operator for finding the length of compound objects.
Besides lists and matrices, this also includes algebraic expressions. The
``MAP`` and ``SELECT`` operators let you manipulate such objects by applying a
function to each element of the structure, or by picking the elements
satisfying a given predicate function. Thus these operations serve pretty much
the same purposes as :func:`#` (or :func:`dim`), :func:`map` and
:func:`filter` in Pure, but in REDUCE they also work with the operands of an
algebraic expression.
.. describe:: length exprn
map fun exprn
select fun exprn
.. code-block:: pure
> simplify $ length (a+b);
2
> simplify $ length (x^n+a*x+2);
3
> simplify $ 'map sqrt [1,2,3];
[1,2^(1/2),3^(1/2)]
> simplify $ 'map log [x^n,x^m,sin x];
[log (x^n),log (x^m),log (sin x)]
Note that ``map`` must be quoted if we want to evaluate it in REDUCE, since
it's also a function in Pure. In this case, we might as well do the
calculation using Pure's ``map``; the result is exactly the same.
.. code-block:: pure
> simplify $ map sqrt [1,2,3];
[1,2^(1/2),3^(1/2)]
> simplify $ map log [x^n,x^m,sin x];
[log (x^n),log (x^m),log (sin x)]
If the function to be applied in calls to ``MAP`` or ``SELECT`` is a compound
expression, it must either contain a single free variable (indicated with the
``~`` prefix, e.g.: ``~w``) or a replacement rule of the form ``var =>
exprn``. In either case the current elements are substituted for the free
variable when the function is applied.
.. code-block:: pure
> simplify $ 'map (y=>df y x) [x^n,x^m,sin x];
[x^n*n/x,x^m*m/x,cos x]
> simplify $ 'map (y=>intg y x) [x^n,x^m,sin x];
[x^n*x/(n+1),x^m*x/(m+1),-cos x]
> simplify $ select (evenp (deg (~w) y)) ((x+y)^5);
x^5+10*x^3*y^2+5*x*y^4
> simplify $ select (w=>evenp (deg w y)) ((x+y)^5);
x^5+10*x^3*y^2+5*x*y^4
Contrast this with Pure where the function argument to :func:`map` is often
specified as a lambda:
.. code-block:: pure
> simplify $ map (\y->df y x) [x^n,x^m,sin x];
[x^n*n/x,x^m*m/x,cos x]
> simplify $ map (\y->intg y x) [x^n,x^m,sin x];
[x^n*x/(n+1),x^m*x/(m+1),-cos x]
In principle, the same correspondences also hold between REDUCE's ``select``
and Pure's :func:`filter`. For instance, consider:
.. code-block:: pure
> simplify $ select (w=>evenp (deg w x)) [2*x^2,3*x^3,4*x^4];
[2*x^2,4*x^4]
The equivalent Pure :func:`filter` is:
.. code-block:: pure
> filter (\w->simplify $ evenp (deg w x)) [2*x^2,3*x^3,4*x^4];
[2*x^2,4*x^4]
Note that REDUCE is now being called inside the predicate function, the rest
of the processing is done in Pure.
Of course, if you want to apply :func:`map`, :func:`filter` and similar Pure
functions to an algebraic expression, you'll first have to extract its
components as a list. Here's a little Pure function which mimics the way in
which ``MAP`` and ``SELECT`` decompose an expression:
.. code-block:: pure
terms x = case x of
f@_ u v = collect f x with
// Collect the operands of variadic Reduce operators.
collect f (f@_ u v) = collect f u+collect f v;
collect f x = [x] otherwise;
end if any (===eval f) [(+),(-),(*),min,max];
= [u,v] if arity f == 2;
_ = [x] otherwise;
end;
For instance, consider:
.. code-block:: pure
> simplify $ 'map (w=>w+1) (df ((x+y)^3) x);
3*x^2+6*x*y+3*y^2+3
With the help of ``terms`` we can also do this using Pure's :func:`map` as
follows:
.. code-block:: pure
> map (+1) $ terms (simplify (df ((x+y)^3) x));
[3*x^2+1,6*x*y+1,3*y^2+1]
> simplify $ foldl (+) 0 ans;
3*x^2+6*x*y+3*y^2+3
While the REDUCE version is shorter and only involves a single call to
:func:`simplify`, with a little bit of programming the Pure solution can be
made just as convenient. More importantly, this method easily generalizes to
other list operations. This makes it possible to apply Pure's full arsenal of
generic list functions which goes beyond what's available in REDUCE.
Partial Fractions
-----------------
The ``PF`` operator transforms an expression into a list of partial fractions
with respect to the main variable. ``PF`` does a complete partial fraction
decomposition.
.. describe:: pf expr var
Let us find the decomposition of:
.. math:: f(x) = \frac{2}{(x+1)^2 \,(x+2)}
.. code-block:: pure
> let f = 2/((x+1)^2*(x+2));
> simplify $ pf f x;
[2/(x+2),(-2)/(x+1),2/(x^2+2*x+1)]
This means:
.. math:: f(x) = \frac{2}{x+2} + \frac{-2}{x+1} + \frac{2}{x^2+2x+1}
If one wants the denominators in factored form, one has to use the
switch ``off exp``:
.. code-block:: pure
> reduce::switch "exp" 0 ;
0
> simplify $ pf f x;
[2/(x+2),(-2)/(x+1),2/(x+1)^2]
Note how the value of a Reduce switch is changed in Pure.
Solving
-------
``SOLVE`` is an operator for solving one or more simultaneous algebraic
equations. It is used with the syntax:
.. describe:: solve expr [var | varlist]
where ``expr`` is a list of one or more expressions. Each expression is an
algebraic equation, or is the difference of the two sides of the equation.
Example 1:
Find the solutions to
.. math:: \log(\sin(x+3))^5 = 8
.. code-block:: pure
> let eqn1 = log(sin (x+3))^5 == 8 ;
> let sol1 = simplify $ solve eqn1 x;
The variable ``sol1`` now contains an entire list of solutions. How many are
there?
.. code-block:: pure
> #sol1 ;
10
The first one is:
.. code-block:: pure
> sol1!0;
x==2*arbint 5*pi+asin (e^(2^(3/5)*cos (2*pi/5))/e^(2^(3/5)*sin (2*pi/5)*i))-3
.. math:: x=
2\cdot n \cdot \pi +{\tt asin}
(\frac{e^{2^{\frac{3}{
5}}\cdot \cos
(\frac{2\cdot \pi }{
5}
)
}}{
e^{2^{\frac{3}{
5}}\cdot \sin
(\frac{2\cdot \pi }{
5}
)
\cdot i}}
)
-3
where ``n`` is an arbitrary integer constant (shown as ``arbint 5`` in the
result of ``simplify``).
It is also possible to obtain the right-hand side of any solution in the list
via REDUCE commands:
.. code-block:: pure
> simplify $ rhs $ first $ solve eqn1 x;
2*arbint 10*pi+asin (e^(2^(3/5)*cos (2*pi/5))/e^(2^(3/5)*sin (2*pi/5)*i))-3
where ``first`` gets the first solution in the list and ``rhs`` obtains the
right-hand side. Hence there is a wealth of possibilities to process the
solution list.
Example 2:
Here are some simpler examples for the sake of clarity:
.. math:: X^2+1 = 0
.. code-block:: pure
> simplify $ solve [X^2+1==0] X;
[X==i,X==-i]
.. math:: (x+3\,y = 7) \wedge (y-x = 1)
.. code-block:: pure
> simplify $ solve [x+3*y==7,y-x==1] [x,y] ;
[[x==1,y==2]]
To get the multiplicities, turn on the switch ``multiplicities``:
.. code-block:: pure
> simplify $ solve [x^2==2*x-1] x;
[x==1]
> reduce::switch "multiplicities" 1;
0
> simplify $ solve [x^2==2*x-1] x;
[x==1,x==1]
For details consult the REDUCE user manual.
Even and Odd Operators
----------------------
An operator can be declared to be even or odd in its first argument by the
declarations ``EVEN`` and ``ODD`` respectively.
.. code-block:: pure
> declare operator [f1,f2];
[]
> declare odd f1;
[]
> declare even f2;
[]
> simplify $ f1(-a);
-f1 a
> simplify $ f2 (-a);
f2 a
> simplify $ f1 (-a) (-b);
-f1 a (-b)
Linear Operators
----------------
An operator can be declared to be linear in its first argument over powers
of its second argument.
.. math:: L(a\,x^5+b\,x+c,x) = L(x^5,x)\cdot a + L(x,x)\cdot b +L(1,x)\cdot c
.. code-block:: pure
> declare operator L;
[]
> declare linear L;
[]
> simplify $ L (a*x^5+b*x+c) x ;
L (x^5) x*a+L x x*b+L 1 x*c
.. math:: L(a+b+c+d,y) = L(1,y)\cdot (a+b+c+d)
.. code-block:: pure
> simplify $ L (a+b+c+d) y;
L 1 y*a+L 1 y*b+L 1 y*c+L 1 y*d
Note that ``L x y`` binds stronger than ``(*)`` in Pure.
Non-commuting Operators
-----------------------
An operator can be declared to be non-commutative under multiplication by the
declaration ``NONCOM``.
.. code-block:: pure
> declare operator [u,v];
[]
> simplify (u(x)*u(y)-u(y)*u(x));
0
> declare noncom [u,v];
[]
> simplify (u(x)*u(y)-u(y)*u(x));
u x*u y-u y*u x
Symmetric and Antisymmetric Operators
-------------------------------------
An operator can be declared to be symmetric with respect to its arguments by
the declaration ``SYMMETRIC``. Similarly, the declaration ``ANTISYMMETRIC``
declares an operator antisymmetric.
.. code-block:: pure
> declare operator [A,S];
[]
> declare symmetric S;
[]
> declare antisymmetric A;
[]
> simplify $ A x x ;
0
> simplify $ (A x y z) + (A x z y) ;
0
> simplify $ S y x ;
S x y
> simplify $ A y x ;
-A x y
Creating/Removing Variable Dependencies
---------------------------------------
There are several facilities in REDUCE, such as the differentiation operator
and the linear operator facility, which can utilize knowledge of the
dependencies between various variables. Such dependencies may be expressed by
the command ``DEPEND``.
.. code-block:: pure
> declare operator D ;
[]
> declare depend [D,x,y];
[]
> simplify $ df D a;
0
``D`` does not depend on ``a``, thus differentiating with respect to ``a``
yields 0, but
.. code-block:: pure
> simplify $ df D x;
df D x
because ``D`` is declared to depend on ``x``.
If we also let ``a`` depend on ``x``, then:
.. code-block:: pure
> declare depend [a,x];
[]
> simplify $ df (D*a) x;
df D x*a+df a x*D
**Note:** Dependencies remain active until they are explicitly removed:
.. code-block:: pure
> declare nodepend [a,x];
> simplify $ df a x;
0
> simplify $ df (D*a) x;
df D x*a
Internal Order of Variables
---------------------------
It is possible for the user to change the internal order of variables
by means of the declaration ``KORDER``. The syntax for this is:
.. describe:: declare korder [v1,...,vn]
Unlike the ORDER declaration, which has a purely cosmetic effect on the way
results are printed, the use of KORDER can have a significant effect on
computation time.
.. code-block:: pure
> declare korder [z,y,x];
[]
> x+y+z;
x+y+z
> simplify $ x+y+z;
z+y+x
Parts of Algebraic Expressions
------------------------------
The following operators can be used to obtain a specific part of an expression,
or even change such a part to another expression.
.. describe:: coeff expr::polynomial var
coeffn expr::polynomial var n::int
part expr::algebraic [n::int]
Examples:
.. code-block:: pure
> simplify $ coeff ((y^2+z)^3/z) y ;
[z^2,0,3*z,0,3,0,1/z]
> simplify $ coeffn ((y^2+z)^3/z) y 6;
1/z
> simplify $ part (a+b) 2 ;
b
> simplify $ part (a+b) 1 ;
a
> simplify $ part (a+b) 0 ;
(+)
``PART`` may also be used to substitute a given part of an expression. In
this case, the ``PART`` construct appears on the left-hand side of an
assignment statement (cf. Assignment_), and the expression to replace the
given part on the right-hand side.
.. code-block:: pure
> simplify $ xx:=a+b;
a+b
> simplify $ part xx 2 := c ;
c
> simplify $ xx;
a+c
Polynomials and Rationals
-------------------------
REDUCE is capable of factorizing univariate and multivariate polynomials with
integer coefficients, finding all factors with integer coefficients. The
package for doing this was written by Dr. Arthur C. Norman and Ms. P. Mary Ann
Moore at The University of Cambridge. It is described in `[SYMSAC81]`_.
.. describe:: factorize expr::polynomial [p::prime]
Some examples:
.. code-block:: pure
> simplify $ factorize (x^105-1) ;
[[x^48+x^47+x^46-x^43-x^42-2*x^41-x^40 ... ]
> reduce::switch "ifactor" 1;
0
> simplify $ factorize (12*x^2 - 12) ;
[[2,2],[3,1],[x+1,1],[x-1,1]]
> reduce::switch "ifactor" 0;
0
The following operators should be well known:
.. describe:: gcd expr1::polynomial expr2::polynomial -> polynomial
lcm expr1::polynomial expr2::polynomial -> polynomial
remainder expr1::polynomial expr2::polynomial -> polynomial
resultant expr1::polynomial expr2::polynomial var -> polynomial
decompose expr::polynomial -> list
interpol ) -> polynomial
deg expr::polynomial var ->int
den expr::rational -> polynomial
lcof expr::polynomial var -> polynomial
lpower expr::polynomial var-> polynomial
lterm expr::polynomial var -> polynomial
mainvar expr::polynomial -> expr
num expr::rational -> polynomial
reduct expr::polynomial var -> polynomial
Some examples of each operator:
GCD/LCM
.. code-block:: pure
> simplify $ gcd (x^2+2*x+1) (x^2+3*x+2) ;
x+1
> simplify $ gcd (2*x^2-2*y^2) (4*x+4*y) ;
2*x+2*y
> simplify $ gcd (x^2+y^2) (x-y) ;
1
> simplify $ lcm (x^2+2*x+1) (x^2+3*x+2) ;
x^3+4*x^2+5*x+2
> simplify $ lcm (2*x^2-2*y^2) (4*x+4*y) ;
4*x^2-4*y^2
REMAINDER/RESULTANT
.. code-block:: pure
> simplify $ remainder ((x+y)*(x+2*y)) (x+3*y) ;
2*y^2
> simplify $ remainder (2*x+y) 2 ;
y
> simplify $ resultant (x/r*u+y) (u*y) u ;
-y^2
DECOMPOSE
.. code-block:: pure
> simplify $ decompose (x^8-88*x^7+2924*x^6-43912*x^5+263431*x^4-
> 218900*x^3+65690*x^2-7700*x+234) ;
[u^2+35*u+234,u==v^2+10*v,v==x^2-22*x]
> simplify $ decompose (u^2+v^2+2*u*v+1) ;
[w^2+1,w==u+v]
DEG/DEN
.. code-block:: pure
> simplify $ deg ((a+b)*(c+2*d)^2) d ;
2
> simplify $ deg ((x+b)*(x^6+2*y)^2) x ;
13
> simplify $ den (x/y^2) ;
y^2
LCOF/LPOWER/LTERM
.. code-block:: pure
> simplify $ lcof ((a+b)*(c+2*d)^2) a ;
c^2+4*c*d+4*d^2
> simplify $ lcof ((a+b)*(c+2*d)^2) d ;
4*a+4*b
> simplify $ lcof ((a+b)*(c+2*d)) ('e) ;
a*c+2*a*d+b*c+2*b*d
> simplify $ lpower ((a+b)*(c+2*d)^2) a ;
a
> simplify $ lpower ((a+b)*(c+2*d)^2) d ;
d^2
> simplify $ lpower ((a+b)*(c+2*d)) x ;
1
> simplify $ lterm ((a+b)*(c+2*d)^2) a ;
a*c^2+4*a*c*d+4*a*d^2
> simplify $ lterm ((a+b)*(c+2*d)^2) d ;
4*a*d^2+4*b*d^2
> simplify $ lterm ((a+b)*(c+2*d)) x ;
a*c+2*a*d+b*c+2*b*d
MAINVAR/NUM/REDUCT
.. code-block:: pure
> simplify $ mainvar ((a+b)*(c+2*d)^2) ;
a
> simplify $ mainvar 2 ;
0
> simplify $ num (x/y^2) ;
x
> simplify $ num ('(100/6)) ;
50
> simplify $ num (a/4+b/6) ;
3*a+2*b
> simplify $ reduct ((a+b)*(c+2*d)) a ;
b*c+2*b*d
> simplify $ reduct ((a+b)*(c+2*d)) d ;
a*c+b*c
> simplify $ reduct ((a+b)*(c+2*d)) x ;
0
Substitution
------------
An important class of commands in REDUCE define substitutions for variables and
expressions to be made during the evaluation of expressions.
One such operation is the prefix operator ``SUB``.
.. describe:: sub exprn::algebraic -> algebraic
.. code-block:: pure
> simplify $ sub [x==a+y,y==y+1] (x^2+y^2) ;
a^2+2*a*y+2*y^2+2*y+1
> simplify $ sub [a==sin x, b==sin y] (a^2+b^2) ;
sin x^2+sin y^2
Note that simple substitutions of this kind can also be done directly in Pure,
using the :macro:`reduce` macro.
Assignment
----------
One may assign values to variables in the REDUCE environment. Note that
in Pure the ``set`` operator and ``:=`` are equivalent, i.e. both sides
are evaluated, contrary to the ``:=`` version in REDUCE.
.. describe:: set expr expr
expr := expr
.. code-block:: pure
> simplify $ P := a*x^n + b* x^m + c ; // P:=a*x^n + b* x^m + c;
x^m*b+x^n*a+c
> simplify P ; // return P (from Reduce)
x^m*b+x^n*a+c
> simplify $ df P x; // diff P x
(x^m*b*m+x^n*a*n)/x
> simplify $ Q := intg P x ; // integrate P x, store in Q
(x^m*b*n*x+x^m*b*x+x^n*a*m*x+x^n*a*x+c*m*n*x+c*m*x+c*n*x+c*x)/(m*n+m+n+1)
> simplify $ set Q (a*x^n + b* x^m + c) ;
x^m*b+x^n*a+c
Matrix Calculations
-------------------
A very powerful feature of REDUCE is the ease with which matrix calculations
can be performed. It fits very well into Pure's native matrix type.
To keep it simple we show the usage of the different operators by examples
using the well known `Pauli matrices`. See, e.g.,
http://en.wikipedia.org/wiki/Pauli_matrices for a reference.
.. math:: \sigma_1 = \begin{pmatrix} 0&1\\ 1&0 \end{pmatrix} \,\,\,\,\,
\sigma_2 = \begin{pmatrix} 0&-i\\i&0 \end{pmatrix} \,\,\,\,\,
\sigma_3 = \begin{pmatrix} 1&0\\ 0&-1\end{pmatrix}
.. code-block:: pure
let s0 = {1,0;0,1} ;
let s1 = {0,1;1,0} ;
let s2 = {0,-i;i,0};
let s3 = {1,0;0,-1};
Check the identities
.. math:: \sigma_1^2=\sigma_2^2=\sigma_3^2=
-i \sigma_1 \, \sigma_2 \, \sigma_3 = \sigma_0
where :math:`\sigma_0` denotes the unit matrix.
Note: Instead of ``s1*s1`` we could also write ``s1^2`` here.
.. code-block:: pure
> let r1 = simplify $ (s1*s1) ; r1;
{1,0;0,1}
> let r2 = simplify $ (s2*s2) ; r2;
{1,0;0,1}
> let r3 = simplify $ (s3*s3) ; r3;
{1,0;0,1}
> let r4 = simplify $ (-i*s1*s2*s3) ; r4;
{1,0;0,1}
> let r5 = all (==s0) [r1,r2,r3,r4] ; r5;
1
Check: :math:`\det \sigma_i = -1, \forall i \in \{1,2,3\}.`
.. code-block:: pure
> map (simplify . det) [s1,s2,s3] ;
[-1,-1,-1]
Calculate the eigenvalues/-vectors of :math:`\sigma_2`:
.. code-block:: pure
> let r7 = simplify $ mateigen s2 q; r7;
[[q-1,1,{-c1*i;c2}],[q+1,1,{c3*i;c4}]]
> let r8 = map head r7; r8; // -> [q-1,q+1] => Eigenvalues q=+/-1
[q-1,q+1]
> let r9 = map (head.tail) r7 ; r9; // multiplicities
[1,1]
> let r10 = map last r7 ; r10; // eigenvectors
[{-c1*i;c2},{c3*i;c4}]
Transpose (operator ``tp``):
.. code-block:: pure
> map (simplify.tp) [s1,s2,s3] ; // -> [s1',s2',s3']
[{0,1;1,0},{0,i;-i,0},{1,0;0,-1}]
Trace (operator ``trace``):
.. code-block:: pure
> map (simplify.trace) [s1,s2,s3] ;
[0,0,0]
Cofactor (trivial here):
.. code-block:: pure
> simplify $ cofactor s2 1 1 ;
0
Nullspace of :math:`\sigma_2` + {0,i;0,0}:
.. code-block:: pure
> simplify $ nullspace (s2+{0,i;0,0}) ;
[{0;1}]
Rank:
.. code-block:: pure
> map (simplify . rank) [s0,s1,s2,s3] ;
[2,2,2,2]
Inverse (simply :math:`\frac{1}{matrix}`):
.. code-block:: pure
> let r15 = simplify $ 1/s2 ; r15;
{0,1/i;(-1)/i,0}
> simplify $ s2*r15 ;
{1,0;0,1}
Solving without ``solve``:
.. math:: a_{11}\, x_1 + a_{12}\,x_2 = y_1 \\
a_{21}\, x_1 + a_{22}\,x_2 = y_2
.. code-block:: pure
> simplify $ (1/{a11,a12;a21,a22}*{y1;y2}) ; // A^-1 * y' ;
{(-a12*y2+a22*y1)/(a11*a22-a12*a21);(a11*y2-a21*y1)/(a11*a22-a12*a21)}
Limits
------
From the package description:
LIMITS is a fast limit package for REDUCE for functions which are continuous
except for computable poles and singularities, based on some earlier work by
Ian Cohen and John P. Fitch.
This package defines a LIMIT operator, called with the syntax:
.. describe:: limit expr::alg var limpoint::alg -> alg
.. math:: \lim_{x \to \infty} x\,\sin \frac{1}{x} = ?, \,\,\,
\lim_{x \to 0} \frac{1}{x} = ?
.. code-block:: pure
> simplify $ limit (x*sin(1/x)) x infinity ;
1
> simplify $ limit (1/x) x 0 ;
inf
Notes: This package loads automatically.
Author: Stanley L. Kameny.
Ordinary differential equations solver
--------------------------------------
The ``ODESOLVE`` package is a solver for ordinary differential equations.
Problem 1:
.. math:: \frac{dy}{dx} = x^2 + e^x
.. code-block:: pure
> declare depend [y,x]; // declare: y depends on x
[]
> simplify $ odesolve [df y x == x^2+exp(x)] [y] x ;
[y==(3*C+3*e^x+x^3)/3]
Problem 2:
.. math:: \frac{d^2\,y}{dx^2} = y(x) \,\,\, \wedge \,\,\,
y(0) = A \,\,\, \wedge \,\,\,
y(1) = B
.. code-block:: pure
> simplify $ odesolve [(df y x 2) == y] [y] x [[x==0,y==A],[x==1,y==B]] ;
[y==(-e^(2*x)*A+e^(2*x)*B*e+A*e^2-B*e)/(e^x*e^2-e^x)]
Remember to remove dependencies:
.. code-block:: pure
> declare nodepend [y,x];
[]
Series Summation and Products
-----------------------------
``SUM``: A package for series summation
From the package description:
The package implements the Gosper algorithm for the summation of series. It
defines operators ``SUM`` and ``PROD``. The operator ``SUM`` returns the
indefinite or definite summation of a given expression, and ``PROD`` returns
the product of the given expression.
This package loads automatically.
Author: Fujio Kako.
Calculate
.. math:: \sum_{n=1}^N \, n^3,\,\,\, \sum_{k=0}^{n-1} (a+k\,r),\,\,\,
\sum_{k=1}^{n+1} \frac{1}{(p+(k-1)\,q)\cdot (p+k\,q)},\,\,\,
\prod_{k=1}^N \frac{k}{k+2}
.. code-block:: pure
> simplify $ sum (n^3) n 1 N ;
(N^4+2*N^3+N^2)/4
> simplify $ sum (a+k*r) k 0 (n-1) ;
(2*a*n+n^2*r-n*r)/2
> simplify $ sum (1/((p+(k-1)*q)*(p+k*q))) k 1 (n+1) ;
(n+1)/(n*p*q+p^2+p*q)
> simplify $ prod (k/(k+2)) k 1 N ;
2/(N^2+3*N+2)
Taylor Series
-------------
``TAYLOR``: Manipulation of Taylor series
From the package description:
This package carries out the Taylor expansion of an expression in one or more
variables and efficient manipulation of the resulting Taylor series.
Capabilities include basic operations (addition, subtraction, multiplication
and division) and also application of certain algebraic and transcendental
functions.
Author: Rainer Schöpf.
Example:
.. math:: e^{x^2 + y^2} = 1+y^{2}+x^{2}+y^{2}\cdot x^{2}+O(x^{3},y^{3})
For details consult the package documentation in the REDUCE distribution.
.. code-block:: pure
> simplify $ taylor (exp (x^2+y^2)) x 0 2 y 0 2 ;
x^2*y^2+x^2+y^2+1
> simplify $ taylor (exp x) x 0 3;
(x^3+3*x^2+6*x+6)/6
> simplify $ implicit_taylor (x^2+y^2-1) x y 0 1 5 ;
(-x^4-4*x^2+8)/8
> simplify $ inverse_taylor (exp(x)-1) x y 0 8;
(-105*y^8+120*y^7-140*y^6+168*y^5-210*y^4+280*y^3-420*y^2+840*y)/840
Note that the "big O" residual terms are omitted in the results returned by
``simplify``, although REDUCE will print them.
Boolean Expressions
-------------------
The truth values within REDUCE are ``t`` and ``nil = ()``. Not all predicates
(functions returning a truth value) can be called by ``simplify``, however,
so one has to use the ``lisp`` function in some circumstances.
Some examples:
.. code-block:: pure
> simplify $ evenp 200 ;
t
> simplify $ evenp 201 ;
[]
> lisp (fixp 200) ;
t
where ``fixp`` tests for integers.
The following example shows a pitfall. Since there is a ``numberp`` function
in both Pure and REDUCE, the function needs to be quoted to make the
expression go through to REDUCE:
.. code-block:: pure
> lisp (numberp x) ;
0
> lisp (numberp 111) ;
1
> lisp ('numberp x) ;
[]
> lisp ('numberp 111) ;
t
In the first case ``numberp x`` evaluates to zero in Pure, so the ``lisp``
function gets ``0`` and returns ``0``. In the second case (quoted) the
function ``numberp`` is evaluated in REDUCE and returns ``nil``, i.e.
``[]`` in Pure. Of course, both results are correct but there may be other
cases where equally named functions have different meanings in the two
environments.
Some other useful predicates in REDUCE are ``ordp`` and ``freeof``:
.. code-block:: pure
> lisp (ordp x y) ;
t
> lisp (ordp y x) ;
[]
> lisp (ordp "abc" "abd") ;
t
> lisp (ordp "abd" "abc") ;
[]
> lisp (ordp 3 5) ;
[]
> lisp (ordp 5 3) ;
t
> simplify $ freeof (x^2+y) x ;
0
> simplify $ freeof (x^2+y) z ;
1
> simplify $ freeof (x^n*y^m) (y^m) ;
0
Mathematical Functions
----------------------
REDUCE provides many mathematical functions which can take arbitrary scalar
expressions as their single argument:
- ACOS ACOSH ACOT ACOTH ACSC ACSCH ASEC ASECH ASIN ASINH
- ATAN ATANH ATAN2 COS COSH COT COTH CSC CSCH DILOG EI EXP
- HYPOT LN LOG LOGB LOG10 SEC SECH SIN SINH SQRT TAN TANH ERF
Note that Pure also defines some these functions in its :mod:`math` module, so
these may have to be quoted to prevent evaluation on the Pure side. For
instance:
.. code-block:: pure
> simplify $ cos 4.3;
cos (43/10)
> using math;
warning: external 'exp' shadows previous undefined use of this symbol
warning: external 'sin' shadows previous undefined use of this symbol
warning: external 'cos' shadows previous undefined use of this symbol
> simplify $ cos 4.3;
(-21601483)/53896027
Some examples:
.. code-block:: pure
> simplify $ cos (-x) ;
cos x
> simplify $ cos (n*pi) ;
cos (80143857*n/25510582)
> simplify $ (quote e)^(3*i*(quote pi)/2) ;
-i
> simplify $ sec (quote pi);
-1
> let simplify $ log10 10 ;
1
> simplify $ erf (-a);
-erf a
The special functions are in two separate packages ``SPECFN`` and ``SPECFN2``:
- Bernoulli Numbers and Euler Numbers;
- Stirling Numbers;
- Binomial Coefficients;
- Pochhammer notation;
- The Gamma function;
- The Psi function and its derivatives;
- The Riemann Zeta function;
- The Bessel functions J and Y of the first and second kind;
- The modified Bessel functions I and K;
- The Hankel functions H1 and H2;
- The Kummer hypergeometric functions M and U;
- The Beta function, and Struve, Lommel and Whittaker functions;
- The Airy functions;
- The Exponential Integral, the Sine and Cosine Integrals;
- The Hyperbolic Sine and Cosine Integrals;
- The Fresnel Integrals and the Error function;
- The Dilog function;
- Hermite Polynomials;
- Jacobi Polynomials;
- Legendre Polynomials;
- Spherical and Solid Harmonics;
- Laguerre Polynomials;
- Chebyshev Polynomials;
- Gegenbauer Polynomials;
- Euler Polynomials;
- Bernoulli Polynomials.
- Jacobi Elliptic Functions and Integrals;
- 3j symbols, 6j symbols and Clebsch Gordan coefficients;
In ``SPECFN2`` are the generalized hypergeometric functions and
Meijer’s G function.
Author: Chris Cannam, with contributions from Winfried Neun, Herbert Melenk,
Victor Adamchik, Francis Wright and several others.
Definite Integrals
------------------
``DEFINT``: Calculating definite integrals by using the Meijer G integration
formula.
.. math:: \int_0^\infty e^{-x} \, dx
.. code-block:: pure
> reduce::load "defint" ;
0
> simplify $ intg (exp(-x)) x 0 infinity ;
1
.. math:: \int_0^\infty x^2\,\cos(x)\,e^{-2\,x} \, dx
.. code-block:: pure
> simplify $ intg (x^2*cos(x)*exp(-2*x)) x 0 infinity ;
4/125
.. math:: \int_0^1 x\,e^{-\frac{1}{2}\,x} \, dx
.. code-block:: pure
> simplify $ intg (x*exp(-1/2*x)) x 0 1 ;
2*sqrt e*(2*sqrt e-3)/e
.. math:: \int_0^1 x\, \log(1+x) \, dx
.. code-block:: pure
> simplify $ intg (x*log(1+x)) x 0 1 ;
1/4
.. math:: \int_y^{2\,y} \cos(2\,x)\, dx
.. code-block:: pure
> simplify $ intg (cos(2*x)) x y (2*y);
(sin (4*y)-sin (2*y))/2
Various transformations:
.. code-block:: pure
> simplify $ laplace_transform (exp(-a*x)) x ;
1/(a+s)
> simplify $ hankel_transform (exp(-a*x)) x ;
s^(n/2)*gamma (n/2)*hypergeometric [(n+2)/2] [n+1]
((-s)/a)*n/(2*a^(n/2)*gamma (n+1)*a)
> simplify $ y_transform (exp(-a*x)) x ;
(a^n*gamma (n+1)*gamma ((-n)/2)*gamma ((-2*n-1)/2)*gamma
((2*n+3)/2)*hypergeometric [(-n+2)/2] [-n+1] ((-s)/a)+s^n*gamma
(-n)*gamma (n/2)*hypergeometric [(n+2)/2] [n+1] ((-s)/a)*n*pi)/
(2*s^(n/2)*a^(n/2)*gamma ((-2*n-1)/2)*gamma ((2*n+3)/2)*a*pi)
> simplify $ k_transform (exp(-a*x)) x ;
(-a^n*gamma (n+1)*gamma ((-n)/2)*hypergeometric [(-n+2)/2] [-n+1]
(s/a)+s^n*gamma (-n)*gamma (n/2)*hypergeometric [(n+2)/2] [n+1] (s/a)*n)/
(4*s^(n/2)*a^(n/2)*a)
> simplify $ struveh_transform (exp(-a*x)) x ;
2*s^((n+1)/2)*gamma ((n+3)/2)*hypergeometric [1,(n+3)/2] [(2*n+3)/2,3/2]
((-s)/a)/(sqrt pi*a^((n+1)/2)*gamma ((2*n+3)/2)*a)
> simplify $ fourier_sin (exp(-a*x)) x ;
s/(a^2+s^2)
> simplify $ fourier_cos (exp(-a*x)) x ;
a/(a^2+s^2)
Declarations, Switches and Loading
----------------------------------
Lisp evaluation can be used in the REDUCE system, in particular, to declare
operator symbols and their properties (``simplify`` won't do that). E.g.:
.. code-block:: pure
> lisp ('operator [myop]);
> lisp ('flag [myop] odd);
> lisp ('prop myop); // => [odd:t,simpfn:simpiden]
> simplify (myop (-x)); // => -myop x
For the most common kinds of declarations, the :mod:`reduce` module provides
the :func:`declare` function which takes care of the necessary Lisp magic and
is safe to use. The above example can also be done as follows:
.. code-block:: pure
> declare operator myop;
> declare odd myop;
> simplify (myop (-x));
-myop x
Please see the description of :func:`declare` for a list of supported
declarations.
The :mod:`reduce` module also provides a few other basic maintenance functions
which are done with special commands in REDUCE:
.. describe:: reduce::switch "switch-name" 0|1
reduce::load "package-name"
reduce::in "path/filename.red"
reduce::capture 0|1
reduce::feed "text"
As already mentioned, REDUCE switches can be turned on and off with
:func:`reduce::switch`, e.g.::
> reduce::switch "exp" 0 ;
0
Packages can be loaded with the :func:`reduce::load` command::
> reduce::load "defint" ;
0
REDUCE source files can be read in with the :func:`reduce::in` command::
> reduce::in "myreduce.red" ;
0
Last but not least, REDUCE terminal input and output can also be redirected to
string buffers using the :func:`reduce::feed` and :func:`reduce::capture`
functions. For instance, the following code feeds some text with a Lisp form
to REDUCE, which gets read by evaluating the Lisp form ``(eval read)``. The
output is captured and can be inspected with the :func:`reduce::output`
function::
> reduce::feed "(print '(a b c d))";
0
> reduce::capture 1; // start capturing output
0
> lisp ('eval read); // read buffered input and evaluate
[a,b,c,d]
> reduce::output; // inspect buffered output
"(a b c d)\n"
> reduce::capture 0; // stop capturing output
0
Plotting
--------
REDUCE can do 2- and 3-dimensional function plots through its gnuplot_
package. Some examples (note that we have to quote the ``x..y`` ranges here so
that they get through to Reduce, rather than being evaluated on the Pure
side):
.. code-block:: pure
> simplify $ plot (sin x/x) (x=='(-15..15));
// Multiple ranges.
> simplify $ plot (sin(x^2 + y^2) / sqrt(x^2 + y^2)) [x=='(-12..12), y=='(-12..12)];
// Specifying options.
> simplify $ plot (cos (sqrt(x^2 + y^2))) [x=='(-3..3),y=='(-3 .. 3)] hidden3d;
// Specifying points.
> simplify $ plot [[0,0],[0,1],[1,1],[0,0],[1,0],[0,1],[0.5,1.5],[1,1],[1,0]];
// Output options.
> simplify $ plot (sin x) [x=='(0..10),terminal==postscript,output=="sin.ps"];
References
----------
.. _[REDUM]:
[REDUM]
*REDUCE User’s Manual*, Version 3.8, Anthony C. Hearn, Santa Monica, CA, USA.
.. _[LNCS102]:
[LNCS102]
*On the Integration of Algebraic Functions*, LNCS 102, Springer Verlag, 1981.
.. _[SYMSAC81]:
[SYMSAC81]
P. M. A. Moore and A.C. Norman, *Implementing a Polynomial Factorization and
GCD Package*, Proc. SYMSAC ’81, ACM (New York) (1981), 109-116.