Template-driven interfaces for numerical subroutines.
This paper describes a set of interfaces for numerical subroutines. Typing a short (often one-line) description allows one to solve problems in application domains including least-squares data fitting, differential equations, minimization, root finding, and integration. Our approach of template-driven programming makes it easy to build such an interface: a simple one takes a few hours to construct, while a few days suffice to build the most complex program we describe.
Introduction
Numerical subroutine packages are one of the oldest and most effective approaches to software re-
use. Experts familiar with a good library can rapidly combine tested and robust components into useful
software.
As effective as they are for experts, however, most large libraries are difficult for the casual user.
Suppose, for instance, that a programmer desires to find a root of a nonlinear equation. This usually entails
looking up the appropriate routine, modifying a sample program, compiling the program with links to the
appropriate libraries, testing (and possibly debugging) the code, and interpreting the output to find the
answer. This process can easily take an hour or two. Rice [1989, p. 2] summarizes the problem:
The user must write code in the target programming language which creates the input and output
data structures and which invokes the procedures. This code is usually lengthy compared
to invocation of the library procedures.
Many solutions have been proposed for this problem. Gill, Murray, Picken, Wright [1979] describe
principles for constructing subroutine libraries that are easy to use. Large environments such as MATLAB
and S provide elegant interfaces to sophisticated software libraries. Such environments are excellent for
both expert and novice users, but require many programmer-years to build.
We wish to make it easy for individual programmers to quickly build effective interfaces for their
software libraries. In this paper we describe a set of programs that provide an interface to the Port subroutine
library described by Fox [1984]. Each program solves a popular form of a common numerical prob-
lem. Here, for instance, is a dialog in which we first find a root of the function sin(x) in the interval [3 , 4]
and then find a root of x in the interval [0.1 , 0.9]:
__________________
Maria Fernandez is currently with the Department of Computer Science, Princeton University, Princeton, NJ 08544. Electronic
addresses: jlb@research.att.com, mff@princeton.edu, bwk@research.att.com,
nls@research.att.com.
(The dollar sign is the system prompt.) Behind the scenes, the Root program uses a template to write, compile
and execute a Fortran program that calls the appropriate subroutine. We refer to this approach as
"template-driven programming".
We undertook to construct similar interfaces for other parts of the Port library, with the following
design goals:
. The interfaces should be accessible to novices, yet powerful enough to be convenient for experienced
users.
. The problem specifications should be succinct.
. The interfaces should be easy to build, from a few hours and a few dozen lines of code, to a day or
two and a few hundred lines.
This paper illustrates the technique on several major parts of the Port library. Section 2 introduces
our template-driven approach to building interfaces, and Section 3 describes least-squares data fitting in
detail. Section 4 surveys several problem domains, and Section 5 describes the more complex problem
domain of differential equations. Other applications of template-driven programming are described in Section
6, and conclusions are offered in Section 7.
2. Template-Driven Programming
In this section we will introduce our template-driven approach to building interfaces by studying the
implementation of the Root program that we saw earlier. That program calls the Port function dzero to
find the zero of a function over a specified interval. The documentation of most function libraries illustrates
the use of a function with a small example. We generalize that example to a template program that calls the
double precision dzero
external f
stop
double precision function f(x)
double precision f, x
return
This template has three parameters, EXP, LO, and HI, which are surrounded by at-signs ("@"). The Root
program reads the three arguments from its command line, substitutes them into this template to produce a
Fortran program, then compiles and executes the Fortran program, which writes the answer.
It is straightforward to implement this approach on many systems. We have, of course, tailored our
implementation to our computing environment: the numerical routines are from the Port library, we call the
routines from Fortran programs, and our interfaces are implemented in Awk. Here is the body of an Awk
implementation of a minimal Root program:
BEGIN {
dotemplate("root.tplt", "junk.f", subarr)
system("f77 junk.f -lport 2>junk.err; a.out")
exit
(Aho, Kernighan and Weinberger [1988] describe the Awk programming language.) The first three lines
read the command-line arguments, the fourth line calls the dotemplate function to instantiate the template
root.tplt into the Fortran file junk.f, and the fifth line compiles the program and executes the
object code, which writes the answer.
The dotemplate function is passed the name of a template file, the name of an output file, and a
substitution array of name-value pairs; here is a trivial implementation:
function dotemplate(templatefile, outfile, subarr, i) {
while (getline <templatefile > {
for (i in subarr)
print $0 >outfile


Appendix

describes a more complete function for instantiating templates.
This minimal program correctly handles correct programs; it is implemented with a 9-line template
and 14 lines of Awk. The complete Root program is more careful with error checking: Does the command
line have precisely three arguments? Did the Fortran compile successfully? If not, then report the error
messages. The complete Root program, including the template itself and code for error checking and template
interpretation, requires about 40 lines (or lines with a library of template functions).
The Root program is easy to implement as a template-driven Awk program, but hard to implement
directly in Fortran. One possible Fortran implementation parses an expression and interprets it at run time;
another choice is to write and compile a Fortran program from within Fortran. Neither choice is particularly
appealing. Our implementation parcels out the jobs to the right tools: an Awk program interprets the
template, the UNIX- shell calls the Fortran compiler to compile the expression, the Port library supplies an
effective solver. Although we've used the tools most convenient on our home system, similar tools could
be used in other environments to implement the essential ideas: simple, concise interfaces that use
template-driven programs.
3. Least-Squares Regression
In the data-fitting problem we are given a set of x, y pairs that are assumed to be modeled by the
equation is a vector of reals. The goal is to find the vector p that minimizes the sum of
the squares of the residuals
min
The library offers several routines for various forms of this task, all based on the excellent algorithm of
Dennis, Gay and Welsch [1981] (widely known as NL2SOL).
We provide access to that algorithm through a program called L2fit (for Least Squares Fit). We will
illustrate our program on a file that contains data on traveling salesman tours through point sets randomly
distributed on the unit square. The x value is the number of points and the y value is the length of a certain
tour through the points. We have reason to believe that the tour length should grow as a
and c are real numbers (synonyms for in the model type the following
command:
About ten VAX-8550 CPU seconds later, the program writes the computed values of a, b and c, in alphabetical
order on the second line. As a side effect of the computation, L2fit produces the Troff output file
l2fit.out, which is displayed in Figure 1.
_______________________________________________________________________________________


Command line: l2fit -troff -s0.6 -lxy a+b*x*c data/tourlen.d
Least squares regression type: Unweighted
Input data file: data/tourlen.d
Input expression: a+b*x*c a
Canonical
Parameters
Final: 0.630579 0.733034 0.499881
Standard errors: 0.12083 0.0166733 0.00240624
Algorithm termination: x- and relative function convergence
100 1000 100001050
Circles: input (x,y) pairs. Line: least squares fit
100 1000 10000
Circles: residuals y - f (x,p).

Figure

1. L2FIT output on TSP data.
_______________________________________________________________________________________
The text at the top of Figure 1 summarizes the computation. The command line typed by the user is
repeated; this is indispensable when searching through a pile of L2fit runs. In this case, the -lxy flag
requests that graphs be plotted with logarithmic x and y scales. The data is in the file data/tourlen.d.
Two flags were added to the command line shown earlier to prepare the l2fit.out file for inclusion in
this Troff document: -troff applies the appropriate document production programs and the -s0.6
shrinks the graphs down to 60% of their default size. The final values of the parameters are displayed,
along with their standard errors (multiplying by 1.96 gives 95% confidence intervals).
The top graph displays both the input data and the fitted function . The
residuals in the bottom graph are quite well-behaved: they appear to decrease in value as x grows, but they
are roughly normally distributed. These two graphs together give us confidence that the tour length grows
as . The next command was therefore
The new l2fit.out file (which is not included in this paper) shows that the computed values of a and b
are quite close to their old values, but the standard error of a decreases from 0.121 to 0.044 and that of b
decreases from 0.0167 to 0.0010. The graphs are essentially unchanged.
This example is typical of the user's view of a session with L2fit. L2fit provides the following services
behind the scenes:
. It uses a template to write a Fortran program that calls the appropriate Port routine. It compiles the
program and checks the Fortran compilation status to find errors in the input expression.
. It executes the program and reads and interprets the output of the least-squares routine. Some values
are extracted directly, while others require more processing (for instance, the standard errors are the
square roots of the diagonals of the covariance matrix).
. It performs certain straightforward data processing tasks, such as checking that each line in the input
file contains two numeric fields, counting the number of parameters in the expression to determine
how large to make the vector p, and sorting the x values to draw the function in the output graph.
. It uses another template to prepare a summary page in l2fit.out. That template uses the Troff
language for typesetting and the Grap language for graphical display of data described by Bentley
and Kernighan [1986].
. It performs minor translations among the various languages used. The variable a in the input expression
is replaced by p(1) in the Fortran program and by the computed value in the Grap output. The
Fortran exponentiation operator "*", the Grap operator "-" and the Eqn operator "sup" are
properly exchanged. The Grap log function returns the base-ten logarithm, so it is replaced with a
natural logarithm function.
Mechanizing the job makes it much easier and faster to use the least-squares fitting routines in Port. But
more importantly, L2fit supports better data fitting by automatically generating graphical displays along
with numerical answers.

Figure

contains a second example of L2fit output. In this case each x value is the number of objects
in a search tree and the y value is the corresponding average number of nodes visited during a search. Theory
suggests that a logarithmic growth is one possibility, so we try the functional form y
Because there are ten y observations at each x value, the -w flag calls for a weighted regression: each x
value is assigned the mean y value, together with a weight inversely proportional to the sample standard
deviation at that x.
The primary graph shows that the best fit equation x is not an accurate
description of the data. Note that the small variances at larger x values give them greater weight; the fit is
better in that region. The weighted residuals have reasonable dispersal, but their means show a great deal
of structure. For this data, the computed parameters have very little meaning; the pictures show that the
model is poor. A second experiment, fitting the model c to this data, shows that the data is
accurately described by 19.2 - 26.0x - 0.39 .


Appendix

A describes L2fit in more detail. Because L2fit is a UNIX system filter, it may be combined
with other tools on that system. For instance, one may desire to fit data to an exponential model,
which is accomplished by this command:
_


Command line: l2fit -troff -s0.6 -w -lx a+b*log(x) 1 1 data/kdnodes.d
Least squares regression type: Weighted
Input data file: data/kdnodes.d
Input expression: a+b*log(x) a
Canonical
Parameters
Final: 15.621 0.281858
Standard errors: 0.484768 0.0440454
Algorithm termination: x- and relative function convergence
100 1000 10000 1000001418
Circles: input (x,y) pairs. Line: least squares fit
100 1000 10000 100000
-5Circles: weighted residuals [y - f (x,p)]/stddev(x).

Figure

2. L2FIT output on search tree data.
_______________________________________________________________________________________
The mathematical model underlying least-square regression assumes that the residual errors are independently
chosen from the same normal distribution. If the errors are normal on a logarithmic scale, however,
one should take the logarithm of both variables before performing the regression, as in this command:
print log($1), log($2) }' datafile | l2fit -lxy 'a
The Awk program takes the logarithm of both fields in the input file. Awk programs are useful for many
common tasks in data analysis, such as filtering out subsets of data and re-expressing data. Some people
use L2fit to perform a single fit on a single data set. At the other extreme, we have built scripts that perform
a dozen L2fit regressions and combine them into a single Troff output file.
single program can cover all possible cases of data fitting, and L2fit is missing some desirable
features. For instance, one might want to specify a Fortran routine as the function to be fit. The underlying
NL2SOL program can easily handle functions of many variables, but the L2fit interface is restricted to the
single independent variable x. Interested users can use L2fit on similar problems with the -t flag to leave
temporary files that may be used as templates for solving the more complex problems.


Appendix

describes the implementation of L2fit in detail. A simple version of L2fit performs only
the least-squares regression to calculate the parameters; it does not prepare the graphical summary. It is
implemented as a 50-line Awk program and a 40-line Fortran template. The complete L2fit is a 330-line
Awk program that uses a 45-line Fortran template; it also uses a 60-line Troff and Grap template to produce
the output.
4. A Survey of Problem Domains
In this section we survey template-driven interfaces for Port routines in several problem domains.
We start with programs that use the format
<lower bound> <upper bound>
The Int program performs numerical integration; here is a numerical approximation to - 1
e
1/x dx:
The default error tolerance is can be adjusted by an input flag.
We saw the Root program earlier; here is an invocation to find a root of x in the
interval [0.1 , 0.9]:
If we want more insight about the function, we can plot it over the interval with the command
show 'x - exp(1-x)*(1+log(x))' .1 .9
This produces a file show.out that contains a picture like this:
Show has many of the same options as L2fit (logarithmic scales, output suitable for Troff input, saving the
temporary files, text labels, etc.), as well as an option for changing the number of points at which the function
is plotted. A more sophisticated version of Show can plot multiple equations and x, y data files. The
related Smooth program computes a smooth function through its input x, y data set; its output is a set of x,
Smooth(x) pairs, and it produces a picture of the smoothed function as a side-effect.
For some purposes, numeric function values are more useful than plots; the Feval program (for function
evaluation) computes such values:
Feval is given a single Fortran expression; it reads a sequence of x values from its input and prints the corresponding
output values. As with most programs on the UNIX system, the input is terminated by typing
"Control-d". Feval is the only program in this paper designed to be used interactively.
The Min program performs multivariate minimization over a region specified by upper and lower
bounds for each variable. We first apply it to our favorite univariate function and interval:
The variables to be minimized are named a, b, c, etc., just as in L2fit, and ranges are given as inequalities
(both b>5 and c<=10 also work). The first output value is the real value of a where the function is mini-
mized, and the second is the value of the function at that real. Here is a more substantial input file, using a
long format in which each field is given on a separate line:
Problem 5 from Hock and Schittkowski [1981]
# Min at
The first four lines are comments, the fifth line contains the expression to be minimized, the next two lines
give the bounds, and the last two lines specify the starting values of the two variables. The file is named
hock5; it is invoked by this command:
The five programs sketched in this section were all straightforward to implement as template-driven
Awk programs. They share a library of Awk functions that contains about 150 lines of code (a shorter
implementation of L2fit also uses that library). Beyond the library code, Feval takes just 6 lines of Awk,
Root and Int are both implemented in lines (including 10-line Fortran templates), Show takes 110 lines
(with a 30-line Troff/Grap template), and Min takes 180 lines (with a 50-line Fortran template).
5. Differential Equations
Simple problems in the domains we have seen so far have simple descriptions. We turn now to differential
equations, where elementary problems are more difficult to describe. Because of this, problem
descriptions are more complicated, even though they often rely heavily on conventions and abbreviations
appropriate to the domain. Our goal in this section is not to present the details of the programs, but rather
to give the flavor of our succinct descriptions of these complicated mathematical objects.
We start by considering the solution of ordinary differential equations or ODEs in the explicit form
in the interval (t start , t stop ), where f is a vector-valued function of time t and the solution
vector x(t). Given initial conditions x(t start ) this problem typically has a unique solution. For exam-
ple, the ODE system S has the solution
This ODE for S and C is solved numerically by the command:
odes vars "S,C" ode "S'=C; C'=-S" x 0 1 on 0 1
This interface uses the ODES solver from the Port library. The fields in this command can be grouped into
name-value phrases, where a phrase consists of one or more fields and is usually identified by the first field
in the phrase.
odes: The name of the underlying numerical software, also the name of this interface.
vars: Assigns the names "S" and "C" to the dependent variables, so
ode: Determines the components f of the ODE system to be solved. In this case,
x: Initial conditions for the dependent variables, x(t start
on: The time interval, t
The above command is converted into 60 lines of Ratfor, a Fortran preprocessor dialect, by a 140-line
Awk program. The Awk script for the ODE interface was initially written in a couple of hours. A few
additional hours added control of the initial time step, error recovery, etc.
We can solve more complicated problems by considering a broad class of partial differential
equations (or PDEs) in one space variable in the semi-linear divergence form
-x
where u(t , x) is a vector of PDE variables, a and f are vector-valued functions of their arguments, for
etc. The boundary conditions have the form
where b L and b R are vector-valued functions.
We start by considering the heat equation for the temperature variable T. The equation is T
over the time range and the space range 0 - x - 1. The initial condition is that T(0 ,
the boundary conditions are T(t , These initial and boundary conditions conflict at
t, the solution of the PDE is approximately erfc(x/2-'t ). Thus, for the
default initial time-step of -"e , where e is the machine rounding error (roughly 5-10 - 9 on the VAX archi-
tecture) the first plot is a unit spike of width roughly . The evolution of this system and its final solution
are shown in this
10.5The code has automatically gone from 2 mesh points to 33, enough to model this nasty function on
the first time step to the default 0.1% accuracy. The solution finally relaxes to its equilibrium value of 1 - x
at time are needed.
The graph above was produced by this command:
We will, once again, sketch the fields in this command by describing the phrases:
poss: The program name, for Partial and Ordinary differential equations in Space with Smooth
splines (this name was derived from POST, for Partial and Ordinary differential equations in Space
and Time).
vars: Assigns the single PDE variable the name T (names must be upper case).
af: The equations are given in the form f. The letter d specifies the differential -x; d
Tx=Tt states that T the partials of T with respect
to x and t.
bc: This specifies the boundary conditions, with left and right separated by the "-" character; the
left condition is T(t , and the right is T(t ,
t: The phrase t 0 1 gives the range for t, and the next phrase gives the range for x.
u: Specifies the initial condition, u(0 ,
The underlying Port software generates the necessary Jacobian information, the partial derivatives of
a, f and bc with respect to the dependent variables u, u t , etc., by finite-difference methods. Thus, the user
does not need to provide such information. This was crucial for the success of these interfaces; specifying
the partial derivatives is too cumbersome for most users. When the user needs exact, instead of approxi-
mate, derivatives, the interface uses Maple to compute them symbolically. (Char et al [1988] describe
Maple.)
Although the description of the heat equation is less than transparent for a naive user, it is much more
succinct than traditional approaches to the problem. The above specification is translated into 170 lines of
Ratfor. The Awk program that performs the translation is 220 lines long and was originally written in an
afternoon; several additional half-hour sessions have since added bells and whistles, such as being able to
set storage limits and change integration methods.
We have built interfaces for several kinds of differential equation solvers. The software underlying
Poss is an adaptive PDE solver in one space variable based on an adaptive mesh spline fitter and the fixed
mesh PDE solver POST; it dynamically determines what mesh to use to obtain the solution to the desired
accuracy. Another program solves PDEs using a fixed mesh, based on an extension of the POST software,
while another interface uses continuation code for solving problems that become difficult as a parameter
changes. Other interfaces solve stiff ordinary differential equations in implicit form with the IODE solver
of the Port library. Benvenuti et al [1991] use these interfaces to solve a number of problems, including the
drift-diffusion, energy balance and fluid dynamics models of semiconductor device behavior.
As an experiment, we built a significantly more sophisticated interface to the Port PDE solvers. Figure
3 describes a PDE in four variables used for semiconductor device modeling (graciously supplied by
Bill Coughran). The specification uses the notation d[con,x] to denote -con/-x; this allows it to pass
complete information about the partial derivatives to the underlying solver, whereas the earlier code always
used finite-difference derivatives. For completeness, Figure 4 shows the same PDE described in the original
interface, together with some help from the UNIX shell for naming parameters.
The program that processes the description in Figure 3 was constructed using the language development
tools described by Kernighan and Pike [1984, Chapter 8]. It serves as an interface to three different
but related Port routines, for handling ODEs, implicit ODEs, and PDEs. The program is implemented with
160 lines of Lex (for lexical analysis), 1070 lines of Yacc (for parsing), 2100 lines of C, and a 250-line Fortran
template. (All of these files could probably be shortened by half by the coding style that we used in the
Awk programs.) In addition to handling the syntactic structure shown above, the program performs extensive
error checking; for instance, it identifies the line number in the source file of Fortran syntax errors.
This interface also ensures that the variables and equations are appropriate for the type of equation. It also
gives more useful error messages; earlier interfaces may pass faulty equations through to the Fortran tem-
plate, so that errors are reported by the compiler.
_
problem pde
pdevar pot con temp vel # potential, concentration, temperature, velocity
precision double # Double precision solution
error 1d-2 1d-2
scaled Boltzmann's constant
scaled effective mass
scaled mobility
scaled elementary charge
scaled ambient temperature
scaled saturation velocity
voltage applied at right
scaled background doping
init pot log(abs( N ))+V*x/2d-2
init con N
init temp T0
init vel 0

Figure

3. A description of a PDE.
_______________________________________________________________________________________
There are tradeoffs between Awk and Yacc as implementation languages. Awk is best suited for fast
implementation, particularly if the execution speed of the resulting product is not of primary concern. Awk
is convenient for string processing and symbol-table management. It is also good at handling keyword-
value pairs; it is weak at parsing anything more complicated. By contrast, Yacc is intended for languages
with richer grammatical structure, especially nested constructions. A Yacc-based program (with semantic
actions implemented in C) will also execute much faster; error detection and recovery are also better. The
price of using Yacc is that implementation time will be significantly longer.
6. Other Template-Driven Programs
Template-driven programs apply far beyond interfaces for numerical functions. An obvious extension
is to nonnumeric functions: given an efficient sort function, we can make a sort pipe that uses a template
C program. Templates could also provide pipe-like interfaces to functions in domains such as
regular-expression pattern matching, random number generation, cryptology, and data compression. In
many of these applications, however, it is more effective to call the function from a single C program
# C concentration
scaled Boltzmann"s constant
scaled effective mass
scaled mobility
scaled elementary charge
scaled ambient temperature
scaled saturation velocity
scaled background doping
voltage applied at right
TAUP="($M * $MU * $T0/($Q*T))"
KP="(1.5*$MU*C)"
poss \
vars "P,C,T,V;" \
af "d
d $KP *
bc "P-log(abs($N)); C-$N; T-$T0; Vx | \
errpar 1e-2 1e-2

Figure

4. A Poss Description of the PDE in Figure 3.
_______________________________________________________________________________________
without using a template.
Templates are most effective when an object must be processed by a compiler. Most of the examples
we have seen so far in this paper deal with Fortran expressions; it is possible to build and interpret an
expression tree at run time, but it is easier to pass the expression to the compiler via a template. We will
now study a program that uses a template to study the run-time cost of various C expressions. Here is most
of the template, which repeatedly evaluates the expression in a tight loop:
#include <math.h>
{ double d1, d2, d3, d4, d5;
int n;
for { @EXP@; }
The complete schema also includes declarations and initializations for variables of type int and float.
Here is an interactive session with the resulting ctime program:
set
4.0 mics/loop 0.4u 0.0s 0r
30.0 mics/loop 3.0u 0.0s 4r
41.0 mics/loop 4.1u 0.0s 5r
The first line uses the ctime keyword set to assign the variables d2 and d3 nonzero values. Subsequent
pairs of lines contain the expression typed by the user followed by the averaged cost and the output of the
time command. This timing program is by no means perfect: an optimizer could move some computation
out of the timing loop, and it ignores caching. Nevertheless, we have found this program to be
useful in its limited domain.
Apart from its applications, though, the ctime program illustrates the power of template-driven pro-
gramming. The complete programs is about lines: 20 lines of template, 20 lines of primary Awk func-
tions, and 20 lines of supporting Awk functions that we copied from other programs (such as template
instantiation and error message reporting). We wrote the ctime program in a couple of hours, and converted
it to the Fortran ftime in about ten minutes. In a couple of hours we built a version that times C
constructs across a half dozen types of machines that are easily reached by network from our home
machine. The template-driven style made it easy to construct all of these variants.
7. Conclusions
The interfaces that we have described provide easy access to most of the major areas in the Port
library. We have aimed at handling the common cases, which cover a high percentage of users, if not a
high percentage of the total CPU time used in Port routines. Although many of our users are novices, we
have been pleasantly surprised that numerical experts also seem to make extensive use of the interfaces.
The template-driven interfaces are easy to build in hours or days; they don't require weeks. The
investment of time in building one is usually returned, with interest, in the first few applications. We
believe that building an interface can easily pay for itself as a numerical routine is being tested and
debugged. The quality of our software improved as a result of having these interfaces available: we can
now quickly answer questions about the functional behavior and time complexity of our routines, and generate
broad but short test cases.
The code for several of these interfaces is available from netlib. To receive an index to the collection
and instructions on how to get what you want, type
echo "send index from templates" | mail netlib@research.att.com
The semi-symbolic nature of these Awk interfaces has changed the way we build numerical routines
in Fortran. For example, in the solution of two-dimensional PDEs, the coupling of variables is important.
If the variables are coupled in a nonlinear lower-triangular manner, then various iterative methods may be
cost-effective compared to the default direct factorization schemes. An interface could ask the user to state
whether the problem is triangular, but that adds complexity for the user and may lead to errors. It is easy
for an Awk program to determine whether a given expression contains a specified variable, and thereby
compute the triangular structure of the equations to be solved.
The programs that we describe all operate independently. Most are batch programs, not interactive.
They are not cooperative: there is no elegant way to take the output of one into another. Integrating these
interfaces into the philosophy of scientific computing tools proposed by Coughran and Grosse [1989]
remains an important open problem.

Acknowledgments

We are grateful for the helpful comments of Rick Becker, Bill Coughran, Eric Grosse, Colin Mal-
lows, Daryl Pregibon, Margaret Wright, and several anonymous referees.



--R


Typesetting Graphs"
"Eval- uation of the influence of convective energy in HBTs using a fully hydrodynamic model"


"A philosophy for scientific computing tools"
"An adaptive nonlinear least-squares algorithm"

"The design and structure of a Fortran program library for optimization"


"Composition of libraries, software parts and problem solving environments,"
--TR
GRAPMYAMPERSANDmdash;a language for typesetting graphs
The AWK programming language
A philosophy for scientific computing tools
The Design and Structure of a Fortran Program Library for Optimization
An Adaptive Nonlinear Least-Squares Algorithm
The UNIX Programming Environment
Test Examples for Nonlinear Programming Codes

--CTR
Tzvetan T. Drashansky , Sanjiva Weerawarana , Anupam Joshi , Ranjeewa A. Weerasinghe , Elias N. Houstis, Software architecture of ubiquitous scientific computing environments for mobile platforms, Mobile Networks and Applications, v.1 n.4, p.421-432, Dec. 1996
maple;fortran;unix shell