Version 3 of Numerical array operations

Updated 2004-02-19 18:45:47

if { 0 } { Arjen Markus (18 february 2004) Several languages, among which Fortran 90, have array operations, to use Fortran 90 syntax:

   real, dimension(1:100) :: a, b, c

   b = 1.0
   do i = 1,size(a)
      a(i) = i
   enddo

   c= b / a 

would fill the array b with the value 1.0, in the do-loop each element of a is given a value (otherwise the last assignment is pretty dull) and each element of the array c is assigned the reciprocal value of the corresponding element of a.

In other words: arrays need not be manipulated only through do-loops (or for-loops, if you like).

This intrigued me: can we get the same thing into Tcl? The answer is obvious: yes!

The script below does very little error handling and it is currently limited to one-dimensional arrays (i.e., Tcl lists of simple numbers) only. But it is just a proof of concept :)


Note that arrays here are not Tcl's hash tables, but numerically indexed collections - for which one best uses lists in Tcl.

AM It is not always easy to come up with words that have an unambiguous meaning. I did not want to use "list" as that would have reminded people too much of other list operations...

See also the NAP package and the LA package (to a lesser extent).


}

 # numarray.tcl --
 #    Array operations on lists of numbers
 #

 proc merge { list1 list2 } {
    set result {}
    foreach e1 $list1 e2 $list2 {
       lappend result $e1 $e2
    }
    return $result
 }

 proc numrange { varname vmin vmax vstep } {
    upvar $varname var

    if { $vmax < $vmin } {
       return -code error "Minimum must be smaller than maximum"
    }
    if { $vstep <= 0.0 } {
       return -code error "Step must be positive"
    }

    set value $vmin
    set var   {}
    while { $value < $vmax+0.5*$vstep } {
       lappend var $value
       set value [expr {$value+$vstep}]
    }
 }

 proc numset { varname expression } {
    upvar $varname var

    #
    # Replace the substrings "$var" by a corresponding
    # list value - if the variable is a list
    #
    set _length_ 1
    while { [string first \$ $expression] >= 0 } {
       regexp {\$(\w+)} $expression ==> _v_
       catch { upvar $_v_ $_v_ }

       if { [llength [set $_v_]] > 1 } {
          set _length_ [llength [set $_v_]]
          regsub {\$\w+} $expression "\[lindex \@$_v_ @_i_\]" expression
       } else {
          regsub {\$\w+} $expression "@$_v_" expression
       }
    }

    set expression [string map {@ $} $expression]

    set _result_ {}
    for { set _i_ 0 } { $_i_ < $_length_ } { incr _i_ } {
       lappend _result_ [expr $expression]
    }
    set var $_result_
 }

 #
 # Simple test cases
 #
 catch { console show }
 numrange v 0.0 10.0 1.1
 puts "v: $v"
 numset w {$v*$v}

 set p 1.0
 numset v {$v+$w+$p}

 puts "w: $w"
 puts "v: $v"

 #
 # Now some graphics
 #
 package require Tk

 numrange phi 0.0 [expr {2.0*3.1415926}] [expr {0.02*3.1415926}]
 numset   rad {1.0+cos($phi)}
 numset   x   {100 + 100 * $rad * cos($phi)}
 numset   y   {200 + 100 * $rad * sin($phi)}

 pack [canvas .c -bg white -width 400 -height 400]
 .c create line [merge $x $y]

[ Category Concept

Category Language

]