Bwise combined with Maxima

by Theo Verelst

See bottom for hands on description of making this combinatin run

Bwise is a sort of interactive visual graph based programming environment (written in Tcl/Tk), and Maxima is a pretty strong and extensive Math package capable of most average and more than a few more than average mathematical manipulations and computations, with a Tk (and Tcl) user interface.

I'm convinced a combination is a very fruitful idea, so without all too much prior knowledge about Maxima I started to combine the two, to begin with simply in the same wish, which needs to come from Maxima, because it is an application (on windows) which has Tcl/Tk 8.4.1 built in, but compiled in.

See the maxima page for examples on its use. I only used it as yet on windows (XP) which works fine, not on an X-based system (yet) though that should work, too, apart from that libraries seem to be needed. There are various pages on bwise and its use and ideas, simple and complicated, see bwise applications and examples.

It appears, after starting up Maxima, and opening its Tcl console, that mainly the application has about 5 toplevel widgets, of which we are mainly interested in .maxima and .browser . The latter one and its buttons are not really needed to begin with, so we can pack forget it, and we leave the top menu in place.

Using the console again, we can source in bwise, for instance the 0.34 version, which will open the main window in the same toplevel as the Maxima interpreter window is open, and a new window for the procedure list will open, too. Now we have the two applications running together, which works fine, the bwise popup menus seem to work, and its normal operations and data windows, too.

Now let's look at how maxima can be interacted with, after packing the bwise window with -side top -expand y -fill both, setting the size of .maxima window to conf -width 0 -height 0, and the same for its children as far as needed, so that the bwise and maxima windows can be enlarged at the expense of the other under control of the maxima sliding horizontal control line.

(Listing an existing applications widget hierarchy is easy with ilist which is in bwise.)

Looking in the sources of maxima, the Tcl files are under maxima-5.9.0/interfaces/xmaxima/Tkmaxima , where looking at 'bindings.tcl' it appears there are some top level bindings into the maxima interpreter which take the line with the current cursor of the Tk text widget, and interpret and normally process the line as the user presses return.

Checking in the bwise procs_window, it appears the function and argument

CMeval .maxima.text

Will do this, and we can treat the main maxima interpreter window as a Tk text widget (it appears simply to be one), where input can be entered in through a script like this:

.maxima.text insert end 1+2\;
CMeval .maxima.text

Which leads to the expacted answer.

Now we already could start to use bwise with it.

I've made a small example bwise network with two blocks following a terminal block (which doesn't yet get saved right, mind you !) of which the first inserts its input data at the end of the maxima text widget, and the second calls CMeval, which already works:

Image Bwise maxima1.jpg

Since version 8.4.1 is used, it appears this Tk also has the slider problem...

The returning of the answer should be possible by setting the window to the bwise canvas subwidget text window, which might be an interesting trick for multiple integrated computations, but I'd like to know about non-pretty-printed representations, too, for nested or fed-through computations.

(A little comment on the .jpg images, in progressive not too small form they don't bother me enough, png's aren't perfect in all forms either, though possibly nicer for certain applications, but I have seen browsers which don't load them well)


TV 2004-07-23: I've used the preliminary domax function from Calling Maxima from Tcl in the bwise+maxima application I made basically by sourcing bwise into maxima over its Tcl console, and pack forget .browser, which makes the bwise window appear.

Apart from error problems, the setup works, like examplified in the network below

Image Bwise maxbwise1.jpg

Where the changed block functions are:

set term0.out {cos(x)^2+SIN(x)^2}

set Proc1.bfunc { set Proc1.out [domax ${Proc1.in} ]}
set Proc2.bfunc { set Proc2.out [domax "integrate( ${Proc2.in},x)" ]}

The block fed back to the interactive terminal block, which fires a (non-looping) net_funprop functional propagate when return is pressed in its entry, evaluates its input in maxima, and shows the result back in the terminal block.

It is followed by a block which tells maxima to integrate its input formula, and of which the outcome is fed to a text monitor block.

And the setup works ! Which is highly fun and relevant, expecially after some more work...


TV: I add this to make it practically easier to start up bwise and maxima, I assume a recent bwise script and startup in it to be in bwise343start_windows.tcl . The below can be sourced in from a file or pasted (with adaptations, see last part), most conveniently from the tcl console after having started xmaxima. On linux, edit the button of the /usr/bin/xmaxima, just above the last comment lines to source in the file with the below, than the combined application starts automatically.

proc domax { {e} } {
    global passres;
    .maxima.text insert insert "$e;\n" ;
    CMeval .maxima.text;
    set passres {};
    while {$passres == ""}  {vwait passres};
    return $passres
}

proc maximaFilter { {win} {sock} } {
    linkLocal $win  plotPending
    global pdata
#TV added:
    global passres
###
    if { [eof $sock] } {
        # puts "at end"
        close $sock
        return ""
    }
    set it [read $sock]
    # puts "read=<$it>"
    if { [string first "\032\032" $it] >= 0 &&
       [regexp  -indices "\032\032(\[^:]+):(\[0-9]+):\[^\n]*\n" $it junk file line] } {

       dblDisplayFrame [getMatch $it $file] [getMatch $it $line]
       append res [string range $it 0 [expr { [lindex $junk 0] -1 } ]]
       append res [string range $it [expr { 1+[lindex $junk 1]}] end]
       set it $res
    }
    if { [string first "\032\031tcl:" $it] >= 0 &&  [regexp  -indices "\032\031tcl:(\\[^\n]*)\n" $it junk com]} {
        eval $com
        append res [string range $it 0 [expr { [lindex $junk 0] -1 } ]]
        append res [string range $it [expr { 1+[lindex $junk 1]}] end]
        set it $res
    }
    # puts it=<$it>
    if { [regexp -indices "\{plot\[d23]\[fd]" $it inds] } {
        set plotPending [string range $it [lindex $inds 0] end]
        set it ""
        if { [regexp {\(C[0-9]+\) $} $it ff] } {
            regexp "\{plot\[d23]\[df].*\}" $ff it
            #   set it $ff
        }
    }
    if { [info exists plotPending] } {
        #puts "plotPending=<$plotPending>,it=<$it>"
        append plotPending $it
        set it ""
        if { [regexp -indices "\n\\(D\[0-9\]+\\)" $plotPending  inds] } {
            set it [string range $plotPending [lindex $inds 0] end]
            set plotPending [string range $plotPending 0 [lindex $inds 0]]
            set data $plotPending
            unset plotPending
            #puts itplot=<$it>,$inds
            #puts plotdata=<$data>
            doShowPlot $win $data
 
        }
    }
 
    $win insert end $it "output"
    $win mark set  lastStart "end -1char"
#TV added:
if [string compare -length 2 $it "(C"] {
#    set i [string first "\n(%i" $it];
    set i [string first "\n(C" $it];
    if {$i <= 0} {set i end-1} {incr i -1}
    #set passres [string range $it [expr [string first )\  $it]+2] $i]
    set passres [string range $it [expr [string first \)\   $it]+2] $i]
  }
###
    if { [regexp {\(C[0-9]+\) $|\(dbm:[0-9]+\) $|([A-Z]+>[>]*)$} $it junk lisp]  } {
        #puts "junk=$junk, lisp=$lisp,[expr { 0 == [string compare $lisp {}] }]"
        #puts "it=<$it>,pdata={[array get pdata *]},[$win index end],[$win index insert]"

        if { [info exists pdata($sock,wait) ] && $pdata($sock,wait) > 0 } {
            #puts "it=<$it>,begin=$pdata($sock,begin),end=[$win index {end linestart}]"
            #puts dump=[$win dump -all "insert -3 lines" end]
            setAct pdata($sock,result) [$win get $pdata($sock,begin) "end -1char linestart" ]
            #puts result=$pdata($sock,result)
            set pdata($sock,wait) 0
        }
        $win mark set lastStart "end -1char"
        $win tag add  input "end -1char" end
        oset $win atMaximaPrompt [expr { 0 == [string compare $lisp ""] }]

    }
    $win see end
    return
}

#########################################################################
# This is the script that sources the above when you've put it in files
# and set the whole of the maxima windows ready to start
# You'll have to adapt pths and filenames to suit your setup
##########################################################################
append auto_path " c:/Theo/Tcl/lib/"
cd e:/Theo/
source bwise343start_windows.tcl
update
cd e:/Theo/Maxima
source procmaxstart1.tcl
pack forget .browser
update
domax "display2d:false"
# procs_window
update
wm geom . 950x650+50+50
update

Now you'll see on top the maxima interpreter, and in the bottom of the window the Bwise application window, and as separate window the function window.

To get a maxima result, use for instance from the tcl console window:

 domax 1+9
10

to get maxima results. In bwise blocks, the same function can be used.

Image TV Wiki bwisemax4.jpg

Example block creating:

newproc {set brace.out "${brace.expr}(${brace.in})"} brace {in expr}
newproc {set domax2.out [domax ${domax2.e}] } domax2 e out 40 {} {} 300 200

The latter can be made with Automatically generate Bwise blocks from procedures (or the 'block' button in the latest function window update, see interactive command composer):

proc_toblock domax

An alternative approach is to call the commandline version of maxima from a bwise block for each invokation of the block function. On Linux / Unix this at least can work fine: Bwise blocks using exec maxima .