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:
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 [L1 ].
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}]
}
}