home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 167_01 / spline.doc < prev    next >
Text File  |  1985-11-14  |  21KB  |  534 lines

  1. /* 
  2. HEADER:     CUG
  3. TITLE:        Cubic Spline Functions Theory;
  4. VERSION:    3.00;
  5. DATE:        09/26/86;
  6. DESCRIPTION:    "Mathematical background and development of
  7.         equations used in SPLINE, a full emulation of
  8.         Unix's 'spline' utility.";
  9. KEYWORDS:    spline, graphics, plot, filter, UNIX;
  10. SYSTEM:
  11. FILENAME:    SPLINE.DOC;
  12. WARNINGS:
  13. CRC:        xxxx
  14. SEE-ALSO:    SPLINE.C;
  15. AUTHORS:    Ian Ashdown - byHeart Software;
  16. COMPILERS:
  17. REFERENCES:    AUTHORS: R.W. Hamming;
  18.         TITLE:     Numerical Methods for Scientists and
  19.              Engineers, 2nd Edition
  20.              pp. 349 - 355, McGraw-Hill (1973);
  21.         AUTHORS: Forsythe, Malcolm & Moler;
  22.         TITLE:     Computer Methods for Mathematical
  23.              Computations
  24.              pp. 70 - 83, Prentice-Hall;
  25. ENDREF
  26. */
  27.  
  28.  
  29. byHeart Software
  30. 620 Ballantree Road
  31. West Vancouver, B.C.
  32. Canada V7S 1W3
  33. September 13th, 1986
  34.  
  35.  
  36.         Curve Fitting With Cubic Splines
  37.         --------------------------------
  38.  
  39.              Ian E. Ashdown
  40.             byHeart Software
  41.  
  42.  
  43. ========================================================================
  44.  
  45. Abstract: CURVE FITTING WITH CUBIC SPLINES
  46. ------------------------------------------
  47.  
  48.     A rigorous development of the mathematical theory of cubic
  49. splines and their use in curve fitting in two and three dimensions.
  50. Emphasis is on the implementation of efficent computer algorithms to
  51. calculate coefficients of both nonperiodic and periodic splines using
  52. Gaussian Elimination and sparse matrix representations. Accompanying
  53. program listing presents C source code for a full emulation of the UNIX
  54. (registered trademark Bell Laboratories) SPLINE curve interpolation
  55. utlity.
  56.  
  57. ========================================================================
  58.  
  59.  
  60.  
  61.     Before computer-aided drafting workstations completely replace the
  62. draftsman's pencil and paper, let's examine one of his tools: the
  63. spline. Presented with data in the form of points on an x-y plane, the
  64. draftsman will use a spline - a flexible strip of metal or plastic - to
  65. draw a smooth curve between them.
  66.  
  67.     The technique is very simple. After plotting the data on a sheet of
  68. paper, an appropriately sized spline is held in place at these points
  69. (referred to as "knots") with weights or pins. The draftsman then traces
  70. the curve formed by the spline. For any given set of knots, the curve
  71. generated is independent of the spline chosen, and is thus exactly
  72. reproducible.
  73.  
  74.     From mechanical engineering, elementary beam theory shows that if
  75. the spline is not too severely stressed, it will conform to a curve
  76. described by a set of cubic polynomial equations, one between each pair
  77. of adjacent knots. Adjacent polynomials meet at their common endpoints
  78. (the knots), and their slopes and rates of curvature at these points are
  79. equal. Stated in mathematical terms, these polynomials join continuously
  80. at the knots with continuous first and second derivatives.
  81.  
  82.     Knowing this, we can develop a mathematical model of the draftsman's
  83. splines, and from this model construct a computer program for
  84. interpolating a smooth curve between a set of knots. With a bit of
  85. care in choosing algorithms, such a program can quickly and accurately
  86. generate a curve for a thousand or more data points on the smallest of
  87. personal computers. It can even be adapted to interpolate a smooth
  88. surface between points plotted in three dimensions.
  89.  
  90.     Developing the model involves basic calculus and matrix theory. If
  91. you are unfamiliar with such mathematics, rest assured that the
  92. resultant algorithms are very easy to program, and using a cubic spline
  93. program requires no understanding of the underlying mathematical theory.
  94. Give the program a set of knots and it will dutifully interpolate a
  95. smooth curve in all (well, almost) cases.
  96.  
  97.     Why then discuss the mathematics of cubic splines at all? There are
  98. two answers. One is that seeing how the algorithms are developed gives
  99. you the confidence to use them. The other is that there may be cases
  100. where the algorithms will not perform exactly as desired. Knowing their
  101. theory may enable you to create a modified algorithm to fit the problem
  102. at hand.
  103.  
  104. A Simple Explanation
  105. --------------------
  106.  
  107.     Whether you understand calculus and matrices or not, it helps to
  108. have in mind a mental image of what you are trying to accomplish. Even
  109. if you aren't comfortable with the mathematics, a conceptual model will
  110. serve to illustrate the principles involved.
  111.  
  112.     A cubic polynomial equation is nothing more than a simple algebraic
  113. equation of the form:
  114.  
  115.               3     2
  116.         y = ax  + bx  + cx + d
  117.  
  118. where a,b,c and d are constants. If you plot the knots on a grid and
  119. actually bend a draftsman's spline to fit between them, each section of
  120. the spline between adjacent knots can be matched by a curve generated
  121. by the above equation ... if the appropriate constants are chosen. The
  122. trick is to find those constants for each section of the spline.
  123.  
  124.     Common sense says three things about these curves. One is that they
  125. should join at the knots. Next, the slopes of the curves should be the
  126. same where they join. Third, the curvature of the curves where the join
  127. should be the same. The first is obvious - the curves must form a
  128. continuous line. The second and third are more intuitive, but a few
  129. moments thought should convince you. A semirigid object such as a
  130. spline does not permit abrupt changes in angle or curvature as it is
  131. bent around a rigid pin.
  132.  
  133.     Stating these ideas mathematically will enable you to calculate the
  134. constants for all the cubic polynomial equations needed to model the
  135. spline.
  136.  
  137. A Rigorous Explanation
  138. ----------------------
  139.  
  140.     Beginning in this section, the mathematical theory of cubic splines
  141. will be rigorously developed. If this approach does not appeal to you,
  142. simply skim the text for the information on how to implement the spline
  143. algorithms, then examine the accompanying program listing. The program
  144. header provides all the information you will need to use the program.
  145.  
  146.     Starting with a set of data points (the knots) stated as horizontal
  147. coordinates x[i] (i = 1,...,n) and corresponding vertical coordinates
  148. y[i], the curve-to-be is defined as the composite function:
  149.  
  150.     y(x) = f[i](x) for x[i] <= x < x[i+1], i = 1,...,n-2
  151.                    and x[n-1] <= x <= x[n]
  152.  
  153. where each function f[i](x) is a cubic polynomial as described above.
  154. In other words, y(x) is really a set of functions, each of which is
  155. defined over an interval between two adjacent knots at (x[i],y[i]) and
  156. (x[i+1],y[i+1]).
  157.  
  158.     Furthermore, let's define y'[i] and y"[i] as the first and second
  159. derivatives of y(x) at x = x[i]. Knowing that the set of functions
  160. f[i](x) must join at their endpoints (the knots of the spline) and also
  161. that their first and second derivatives are continuous at these points,
  162. we have the following continuity conditions:
  163.  
  164.     f[i](x[i]) = y[i]        i = 1,...,n-1
  165.     f[i-1](x[i]) = y[i]        i = 2,...,n
  166.     f'[i-1](x[i]) = f'[i](x[i])    i = 2,...,n-1
  167.     f"[i-1](x[i]) = f"[i](x[i])    i = 2,...,n-1
  168.  
  169.     Since each function f[i](x) is a cubic polynomial, it follows that
  170. its second derivative is a linear function (a straight line) between its
  171. endpoints. If we define:
  172.  
  173.     h[i] = x[i+1] - x[i]
  174.  
  175. then linear interpolation gives us:
  176.  
  177.            y"[i] * (x[i+1] - x) + y"[i+1] * (x - x[i])
  178.     f"[i](x) = -------------------------------------------
  179.                      h[i]
  180.  
  181.     Integrating this equation twice and selecting the constants of
  182. integration such that the continuity conditions are satisfied, we can
  183. derive the following interpolation equation:
  184.  
  185.           y[i] * (x[i+1] - x) + y[i+1] * (x - x[i])
  186.     f[i](x) = ----------------------------------------- -
  187.                    h[i]
  188.  
  189.               2  +-       +-
  190.           h[i]     |       | (x[i+1] - x)
  191.           ---- * | y"[i] * |------------- -
  192.            6     |       |    h[i]
  193.              +-       +-
  194.  
  195.           +-          -+ 3 -+           +-
  196.           | x[i+1] - x |    |           | (x - x[i])
  197.           | ---------- |    | +  y"[i+1] * | ---------- -
  198.           |    h[i]    |    |           |   h[i]
  199.           +-          -+   -+           +-
  200.  
  201.           +-        -+ 3 -+  -+
  202.           | x - x[i] |      |   |
  203.           | -------- |      |   |
  204.           |   h[i]   |      |   |
  205.           +-        -+     -+  -+
  206.  
  207.     for i = 1,...,n-1
  208.  
  209.              Interpolation Equation
  210.              ----------------------
  211.  
  212.     Remember this equation - we will later use it to interpolate the
  213. curve defined by y(x) between the given knots. However, we first need to
  214. calculate the unknown coefficients y"[i] for all i between 1 and n.
  215.  
  216.     Differentiating and evaluating the above equation for x[i] yields:
  217.  
  218.               y[i+1] - y[i]   h[i]
  219.     f'[i](x[i]) = ------------- - ---- * (2 * y"[i] + y"[i+1])
  220.               h[i]           6
  221. and
  222.             y[i] - y[i-1]    h[i-1]
  223.     f'[i-1](x[i]) =    ------------- + ------ * (y"[i-1] + 2 * y"[i])
  224.                 h[i-1]      6
  225.  
  226.     Since the first derivatives of the functions at their endpoints are
  227. continuous, these two equations are equivalent. We can rearrange the
  228. terms of their right-hand sides to get:
  229.  
  230.     h[i-1] * y"[i-1] + 2 * (h[i-1] + h[i]) * y"[i] + h[i] * y"[i+1]
  231.  
  232.           +-                 -+
  233.           | y[i+1] - y[i]   y[i] - y[i-1] |
  234.     = 6 * | ------------- - ------------- |
  235.           |        h[i]        h[i-1]    |
  236.           +-                 -+
  237.  
  238.     for i = 2,...,n-1
  239.  
  240.     Expressed in matrix form, the above equations show an interesting
  241. diagonal symmetry that we will later take good advantage of. Using n = 6
  242. as an example, they look like this:
  243.  
  244. +-                   -++-     -+   +-    -+
  245. | h[1] c[2] h[2] 0    0    0    || y"[1] | = | d[2] |
  246. | 0    h[2] c[3] h[3] 0    0    || y"[2] |   | d[3] |
  247. | 0    0    h[3] c[4] h[4] 0    || y"[3] |   | d[4] |
  248. | 0    0    0    h[4] c[5] h[5] || y"[4] |   | d[5] |
  249. +-                   -+| y"[5] |   +-    -+
  250.                  | y"[6] |
  251.                  +-     -+
  252.  
  253. where c[i] = 2 * (h[i-1] + h[i])
  254.  
  255.          +-                -+
  256.          | y[i+1] - y[i]   y[i] - y[i-1] |
  257. and   d[i] = 6 * | ------------- - ------------- |
  258.          |    h[i]          h[i-1]     |
  259.          +-                -+
  260.  
  261. A Variety Of End Conditions
  262. ---------------------------
  263.  
  264.     So far, we have n unknowns y"[i], but only n-2 conditions as
  265. expressed by the above equations. Two more conditions are required to
  266. obtain a unique solution for our curve y(x). Several variations are
  267. possible; we will look at two of the more useful ones here.
  268.  
  269.     The first is to specify that:
  270.  
  271.     y"[1] = j * y"[2] and y"[n] = k * y"[n-1]
  272.  
  273. where j and k are arbitrary constants. With a bit of matrix
  274. manipulation, we get:
  275.  
  276. +-                      -++-       -+   +-      -+
  277. | c[2]  h[2]  0     ....    0       0      || y"[2]   | = | d[2]   |
  278. | h[2]  c[3]  h[3]  ....    0       0      || y"[3]   |   | d[3]   |
  279. | 0     h[3]  c[4]  ....    0       0      || y"[4]   |   | d[4]   |
  280. | ....  ....  ....  ....    ....    ....   || .....   |   | ....   |
  281. | 0     0     ....  h[n-3]  c[n-2]  h[n-2] || y"[n-2] |   | d[n-2] |
  282. | 0     0     ....  0       h[n-2]  c[n-1] || y"[n-1] |   | d[n-1] |
  283. +-                      -++-       -+   +-      -+
  284.  
  285. where c[2] = (2 + j) * h[1] + 2 * h[2]
  286.       c[i] = 2 * (h[i-1] + h[i]), i = 3,...,n-2
  287.       c[n-1] = 2 * h[n-2] + (2 + k) * h[n-1]
  288.  
  289.          +-                -+
  290.              | y[i+1] - y[i]   y[i] - y[i-1] |
  291.       d[i] = 6 * | ------------- - ------------- | , i = 2,...,n-1
  292.          |     h[i]          h[i-1]     |
  293.          +-                -+
  294.  
  295.     If the values of j and k are zero, we have y"[1] = y"[n] = 0. This
  296. is equivalent to a spline whose ends are not constrained beyond the end
  297. knots, and is known as the "natural" cubic spline. A nonzero value for j
  298. or k is equivalent to bending an end of the draftsman's spline, and will
  299. affect all of the interior cubic polynomial functions. However, the
  300. effect on the interior polynomials rapidly decreases as one moves away
  301. from the endpoints.
  302.  
  303.     For some sets of knots, a nonzero value of j or k will result in a
  304. smoother interpolating curve at its corresponding end. A value of 0.5 is
  305. often appropriate. Be forewarned, however, that for some negative values
  306. the curve will be discontinuous. As it approaches these values, the end
  307. of the curve begins to oscillate, the peaks becoming larger and larger
  308. until they reach infinity at the exact values.
  309.  
  310.     The above set of linear equations can be solved using Gaussian
  311. Elimination. However, we must be careful. In its most general form, this
  312. method can require prodigious amounts of memory and millions of floating
  313. point computations. Given 1000 unknowns, Gaussian Elimination needs
  314. storage for over one million floating point numbers and performs some
  315. 334 million multiplications and divisions! The loss of accuracy due to
  316. so many calculations can render the results meaningless.
  317.  
  318.     Fortunately, our coefficient matrix is very sparse and symmetrical.
  319. The non-zero elements can be stored in a few linear arrays, and the
  320. remainder ignored. By observing how Gaussian Elimination solves the
  321. equations, we can modify the method to eliminate operations involving
  322. multiplication by and addition of zero. The result is Algorithm 1, which
  323. has very reasonable memory requirements and execution times - a cubic
  324. spline problem with 1,000 knots can be quickly solved on most personal
  325. computers, even those with less than 64K of memory!
  326.  
  327. ---------------------------------------------------------
  328. Algorithm 1: Nonperiodic Spline Coefficient Determination
  329. ---------------------------------------------------------
  330.  
  331. /* Reduce matrix to upper triangular form */
  332.  
  333. for i = 2 to i = n-2
  334.   begin
  335.     c[i+1] = c[i+1] - h[i] * h[i]/c[i]
  336.     d[i+1] = d[i+1] - d[i] * h[i]/c[i]
  337.   end
  338.  
  339. /* Solve using back substitution */
  340.  
  341. y"[n-1] = d[n-1]/c[n-1]
  342. for i = n-2 to i = 2
  343.   begin
  344.     y"[i] = (d[i] - h[i] * y"[i+1])/c[i]
  345.   end
  346.  
  347. y"[1] = j * y"[2]    /* End conditions */
  348. y"[n] = k * y"[n-1]
  349.  
  350. ---------------------------------------------------------
  351.  
  352.     In practice, array y"[] would initially be used to store the
  353. elements of array d[]. Then, as the elements of y"[] are solved during
  354. back substitution, they overlay the values of d[]. To implement this
  355. space saving technique in the above algorithm, change every instance of
  356. d[] to y"[].
  357.  
  358.     The second variation is more interesting, and comes from the need to
  359. interpolate data extracted from periodic phenomenon. If we plot any
  360. periodic data in polar co-ordinates, a smooth curve between them forms a
  361. closed curve, with the endpoints of the curve meeting. Plotting the same
  362. data in rectilinear co-ordinates with the abscissae expressed over 360
  363. degrees, it's easy to see that we can model the curve with a cubic
  364. spline function.
  365.  
  366.     Since the curve is periodic, the endpoint ordinates are by
  367. definition equal. In other words, y[1] = y[n]. We need to specify the
  368. end conditions such that the first and second derivatives of the curve
  369. are continuous with respect to each other at these points. Stated in
  370. mathematical terms, y'[1] = y'[n] and y"[1] = y"[n].
  371.  
  372.     The second derivatives are easy - they can be expressed directly in
  373. matrix form. To utilize the first derivatives of y(x) at the end points,
  374. we need an equation that relates them to y(x) and its second derivative.
  375. Going back to our derivations for f'[i](x[i]) and f'[i-1](x[i]), and
  376. evaluating them for x[1] and x[n] respectively, we have:
  377.  
  378.               y[2] - y[1]   h[1]
  379.     f'[1](x[1]) = ----------- - ---- * (2 * y"[1] + y"[2])
  380.               h[1]         6
  381. and
  382.             y[n] - y[n-1]    h[n-1]
  383.     f'[n-1](x[n]) = ------------- + ------ * (y"[n-1] + 2 * y"[n])
  384.                h[n-1]      6
  385.  
  386. But y'[1] = y'[n], so that
  387.  
  388.         +-                 -+
  389.         | y[2] - y[1]   y[n] - y[n-1] |
  390.     6 * | ----------- - ------------- | =
  391.         |     h[1]           h[n-1]      |
  392.         +-                 -+
  393.  
  394.     h[n-1] * (y"[n-1] + 2 * y"[n]) + h[1] * (2 * y"[1] + y"[2])
  395.  
  396.     Again with some matrix manipulation, we get:
  397.  
  398. +-                      -++-       -+   +-      -+
  399. | c[2]  h[2]  0     ....    0       h[1]   || y"[2]   | = | d[2]   |
  400. | h[2]  c[3]  h[3]  ....    0       0      || y"[3]   |   | d[3]   |
  401. | 0     h[3]  c[4]  ....    0       0      || y"[4]   |   | d[4]   |
  402. | ....  ....  ....  ....    ....    ....   || .....   |   | ....   |
  403. | 0     0     ....  h[n-2]  c[n-1]  h[n-1] || y"[n-1] |   | d[n-1] |
  404. | h[1]  0     ....  0       h[n-1]  c[n]   || y"[n]   |   | d[n]   |
  405. +-                      -++-       -+   +-      -+
  406.  
  407. where c[i] = 2 * (h[i-1] + h[i]), i = 2,...,n-1
  408.       c[n] = 2 * (h[1] + h[n-1])
  409.  
  410.          +-                -+
  411.          | y[i+1] - y[i]   y[i] - y[i-1] |
  412.       d[i] = 6 * | ------------- - ------------- | , i = 2,...,n-1
  413.          |     h[i]          h[i-1]     |
  414.          +-                -+
  415.  
  416.          +-                  -+
  417.          | y[2] - y[1]   y[n] - y[n-1] |
  418.       d[n] = 6 * | ----------- - ------------- |
  419.          |    h[1]       h[n-1]      |
  420.          +-                  -+
  421.  
  422.     These equations can be solved efficiently and quickly with another
  423. modified version of Gaussian Elimination:
  424.  
  425. ------------------------------------------------------
  426. Algorithm 2: Periodic Spline Coefficient Determination
  427. ------------------------------------------------------
  428.  
  429. /* Initialize array e[] as nth column of matrix M[][] */
  430.  
  431. e[2] = h[1]
  432. for i = 3 to i = n-2
  433.   begin
  434.     e[i] = 0
  435.   end
  436. e[n-1] = h[n-1]
  437. e[n] = c[n]
  438.  
  439. /* Initialize variable f as matrix element M[n][1] */
  440.  
  441. f = h[1]
  442.  
  443. /* Reduce matrix to upper triangular form */
  444.  
  445. for i = 2 to i = n-2
  446.   begin
  447.     c[i+1] = c[i+1] - h[i] * h[i]/c[i]
  448.     d[i+1] = d[i+1] - d[i] * h[i]/c[i]
  449.     e[i+1] = e[i+1] - e[i] * h[i]/c[i]
  450.     d[n] = d[n] - d[i] * f/c[i]
  451.     e[n] = e[n] - e[i] * f/c[i]
  452.     f = -f * h[i]/c[i]    /* Now matrix element M[n][i] */
  453.   end
  454.   f = f + h[n-1]  /* Now matrix element M[n][n-1] */
  455.   d[n] = d[n] - d[n-1] * f/c[n-1]
  456.   e[n] = e[n] - e[n-1] * f/c[n-1]
  457.  
  458. /* Solve using back substitution */
  459.  
  460. y"[n] = d[n]/e[n]
  461. y"[n-1] = (d[n-1] - e[n-1] * y"[n])/c[n-1]
  462. for i = n-2 to i = 2
  463.   begin
  464.     y"[i] = (d[i] - h[i] * y"[i+1] - e[i] * y"[n])/c[i]
  465.   end
  466.  
  467. y"[1] = y"[n] /* End condition */
  468.  
  469. -------------------------------------------------------
  470.  
  471.     Other end conditions are possible. For example, you can specify the
  472. slope of the spline at its endpoints by specifying the first derivatives
  473. at y[1] and y[n]. You can also specify a linear combination of first and
  474. second derivatives at the endpoints. However, the two examples presented
  475. here will generally prove the most useful for interpolative curve
  476. fitting.
  477.  
  478.     Specifying the end conditions and solving the appropriate set of
  479. linear equations gives us the coefficients we need to solve our
  480. interpolation equation. (Note that this equation remains the same no
  481. matter what end conditions have been specified.) For any given value of
  482. x within the range of abscissae spanned by the knots, we need only
  483. determine the two knots between whose abscissae the value lies. This
  484. gives us the value of i to insert in the interpolation equation, and with
  485. it the appropriate coefficients y"[i] and y"[i+1] to use in solving for
  486. the curve's corresponding ordinate y.
  487.  
  488.     What about the related problem of fitting a smooth surface to data
  489. plotted in three dimensions? Well, if the data is regularly spaced in
  490. two of those dimensions (say the x-y plane), we can calculate a family
  491. of curves in parallel x-z planes. Each curve is the intersection of the
  492. x-z plane with the surface. Then, for any perpendicular y-z plane, our
  493. knots are the intersection of the x-z plane curves with the y-z plane.
  494. From these, we can calculate the intersection of our surface with the
  495. y-z plane. With this method, we can uniquely determine any point on the
  496. surface.
  497.  
  498. Final Words
  499. -----------
  500.  
  501.     Demonstrating the above algorithms could have been done using a
  502. small BASIC program. However, the UNIX operating system (see reference
  503. 4) offers a utility called SPLINE that is much more comprehensive.
  504. Heeding once again Richard Stallman's (The GNU Manifesto - DDJ Mar.'85)
  505. call for placing UNIX in the public domain (FGREP - DDJ Sept.'85 was my
  506. previous response), the accompanying "demonstration" program is a full
  507. emulation of the UNIX SPLINE utility.
  508.  
  509.     Cubic splines are an elegant solution to the problem of fitting
  510. curves to a set of given points in an x-y plane. A understanding of the
  511. mathematics used to develop them is not essential. The simplicity and
  512. efficiency of the algorithms involved should encourage anyone interested
  513. in graphics or data analysis to add cubic splines to their software
  514. toolboxes.
  515.  
  516. References
  517. ----------
  518.  
  519. 1. Numerical Methods for Scientists and Engineers
  520.    R.W. Hamming, 2nd Edition
  521.    pp.349 - 355, McGraw-Hill (1973)
  522. 2. Computer Methods for Mathematical Computations
  523.    Forsythe, Malcolm & Moler
  524.    pp. 70 - 83, Prentice-Hall (1977)
  525. 3. Introduction to Numerical Analysis (2nd Edition)
  526.    F.B. Hildebrand
  527.    pp.478 - 494, McGraw-Hill (1974)
  528. 4. UNIX Programmer's Manual, Volume 1
  529.    Bell Telephone Laboratories
  530.    p.145, Holt, Rinehart and Winston (1983)
  531.  
  532.                  - End -
  533. n (FGREP - DDJ Sept.'85 was my
  534. previous response), the accompanying "demonstration" program is