Arjen Markus (31 march 2014) This may be the start of a new package, one to manipulate series of numerical data at a high level in pure Tcl. The code below is a humble experiment. Of course for large amounts of data it would be better to have a compiled extension and there are certainly packages around or in development that can/will do that, but it is also attractive to have a Tcl-only package.
# series.tcl --
# First attempt at creating a package to handle series of numerical data
#
namespace eval ::math::series {
}
# mexpr --
# Evaluate an expression with lists (series) of data
#
# Arguments:
# expression String valid as a Tcl expression
#
# Returns:
# List of the results of the expression evaluated with subsequent values
#
# Note:
# Array elements $x($y) in these expressions do not yet work properly!
# Also avoid variables whose name has the form "__...___"
#
# The current implementation may not be very efficient, because of
# the expression being reparsed each iteration.
#
proc ::math::series::mexpr {expression} {
#
# Extract the variable names
#
set vars [lsort -unique [regexp -all -inline {\$[A-Za-z_]+} $expression]]
set forvars {}
foreach v $vars {
set v [string range $v 1 end]
upvar 1 $v __${v}__
if { [llength [set __${v}__]] > 1 } {
lappend forvars $v [set __${v}__]
} else {
set $v [set __${v}__]
}
}
#
# Evaluate the expression via the list variables
#
if { [llength $forvars] > 0 } {
set __result__ {}
foreach {*}$forvars {
lappend __result__ [expr $expression]
}
} else {
set __result__ [expr $expression]
}
return $__result__
}
#
# procedure to compare the performance
#
proc test_expr {xlist ylist} {
foreach x $xlist y $ylist {
lappend result [expr {$x+$y}]
}
return $result
}
#
# Simple test
#
set x {1 2 3 4 5 6 7 8 9}
set y {2 3 4 5 6 7 8 9 10}
set z 1
puts [::math::series::mexpr {$x+$y}]
puts [::math::series::mexpr {$x+$z}]
puts [test_expr $x $y]
puts [::math::series::mexpr {1+2}]
set x {}
set y {}
for {set i 0} {$i < 1000} {incr i} {
lappend x $i
lappend y $i
}
# Hm, mexpr is about 4 times as slow as test_expr
puts "Time for mexpr: [time {::math::series::mexpr {$x+$y}} 1000]"
puts "Time for test_expr: [time {test_expr $x $y} 1000]"