Updated 2011-01-07 13:53:14 by Jorge

Arjen Markus At the Third European Tcl/Tk Users Meeting I presented a "mathematical workbench". This page shows a small example of this work. The idea is described in the abstract:

A handheld calculator is a great way to do all kinds of ad hoc calculations. You do not write a C or Fortran program with hard-coded numbers to add them for balancing your books. In a similar way doing mathematics - for instance solve some geometrical problem - requires a handheld calculator suitable for that type of calculations.

The essential ingredients are an interactive program that interprets dedicated commands, and a few conventions to make its use more or less uniform.

This paper describes the application of Tkcon and such a set of conventions to provide the interface. It illustrates the concepts with three different mathematical tools: complex numbers, ordinary differential equations and (statistical) optimisation.

The script below contains a few commands that illustrate the idea compactly:

  • You can define a function of x via [func $expression]
  • You can define the derivative of that function via [deriv funcname]
  • You can get the value of a function for a specific value

If you run the script from within Tkcon or a similar shell, you can experiment with it.

(Note: the full workbench contains much more convenient commands)

The workbench is available at the Starkit Distribution Archive [1].

AM A small but significant improvement: xderiv_impl now uses the original function, so that you can use it to calculate the second-order derivative and so on! [Did this improvement make it into the latest starkit?]

5Jan2011 JM Is there any demo on the starkit? if so, how is it named?

AM (7 january 2011) I will have to brush off the code - if you are interested, I can do so, but I have not really expanded it of late. The idea still interests me, but with Tcllib and Tklib there is a whole bunch of quite useable modules available.

JM (7 january 2011) Thanks, for now I will look through your other posts, which are very interesting.
 # functions.tcl --
 #
 #    Package for analysing real functions
 #    (sample Workbench module)
 #
 # Notes:
 #    This package provides basic analysis functionality for real
 #    functions of one variable.
 #
 # Version information:
 #    version 0.1: initial implementation, july 2002

 package provide Functions 0.1

 namespace eval ::Workbench {

    variable nextID 0

 # uniqueID --
 #    Create a unique ID (private)
 #
 # Arguments:
 #    expression   Expression using "x" as independent variable
 #                 evaluating to the function value
 #
 # Result:
 #    Name of a new command implementing the function
 #
 # Side effect:
 #    Create a new command that takes one argument, x, and
 #    returns the function value
 #
 proc uniqueID {typename} {
    variable nextID 

    incr nextID

    return "${typename}##$nextID"
 }
 } ;# End of namespace

 namespace eval ::Functions {
 
    namespace export func deriv

 # func --
 #    Create a new function
 #
 # Arguments:
 #    expression   Expression using "x" as independent variable
 #                 evaluating to the function value
 #
 # Result:
 #    Name of a new command implementing the function
 #
 # Side effect:
 #    Create a new command that takes one argument, x, and
 #    returns the function value
 #
 proc func {expression} {
    set name [::Workbench::uniqueID "X-FUNCTION"]
    interp alias {} $name {} [namespace current]::xfunc_impl $expression
    return $name
 }

 # xfunc_impl --
 #    Implementation of an "x function"
 #
 # Arguments:
 #    expression   Expression using "x" (hidden via [interp alias])
 #    x            Independent variable
 #
 # Result:
 #    Function value
 #
 proc xfunc_impl {expression x} {
    expr $expression
 } 

 # deriv --
 #    Create a new function that evaluates to the derivative of the given
 #    function
 #
 # Arguments:
 #    funcname     Name (!) of the function
 #    step         Step for the numerical derivation
 #
 # Result:
 #    Name of a new command implementing the function's derivative
 #
 # Side effect:
 #    Create a new command that takes one argument, x, and
 #    returns the original function's derivative
 #
 proc deriv {funcname {step 0.01} } {
    upvar $funcname fname
    set name [::Workbench::uniqueID "X-DERIVATIVE"]
    set expression [lindex [interp alias {} $fname] 1]
    interp alias {} $name {} [namespace current]::xderiv_impl  $fname [expr {$step*0.5}]
    return $name
 }

 # xderiv_impl --
 #    Implementation of the derivative of an "x function"
 #
 # Arguments:
 #    fname     Name (!) of the function 
 #    step         Step size for numerical derivation
 #    xv           Independent variable
 # Result:
 #    Value of derivative
 #
 # Note:
 #    By using the 
 #
 proc xderiv_impl {fname step xv} {
    set x   [expr {$xv-$step}]
    set fx1 [$fname $x]
    set x   [expr {$xv+$step}]
    set fx2 [$fname $x]
    expr {($fx2-$fx1)/(2.0*$step)}
 }

 } ;# End of namespace

 #
 # Import the functions procedures
 #
 namespace import ::Functions::*

 #
 # Simple demo
 #
 if { [file tail [info script]] == [file tail $::argv0] } {
    puts "Simply a parabola: y = x^2"
    set f [func {$x*$x}]
    set df [deriv f]
    set x 0.0
    while { $x < 10.1 } {
       puts "[$f $x] [$df $x]"
       set x [expr {$x+1.0}]
    }

    puts "A more complex function"
    set f [func {sin($x)*$x}]
    set df [deriv f]
    set x 0.0
    while { $x < 10.1 } {
       puts "[$f $x] [$df $x]"
       set x [expr {$x+0.1}]
    }
 }