constructing mathematical formulas with Bwise blocks

tv

TV (Oct 25 '04) I've changed a few little things in the prettyprint and the procs for block functions.

Not knowing exactly yet where this will go/end, but having a pretty good idea as to the usefulness, I'm starting a page where I look into constructing mathematical formulas from bwise blocks, where the idea is that these blocks construct a formula graphically on the Tk canvas of Bwise (which is a normal, vanilla, even way back compatible canvas, no extensions either), which can also be evaluated, and in this case I want to make the bwise graph (the interconnected blocks) render a complete formula, in preferably Expr format, or in Maxima format, but first as repeated function call where expressions are dealt with inside explicitly formed procedures (functions).

So that finally when a formula has been constructed, it can be filled in and used both as tcl expression, or as maxima expression, and preferably all automatically.

Maxima allows much more complicated formulas and lets say operators, like integration and differentiation and all kinds of algebraic manipulation, which in this way can be given a graphical interface, which can be quite a complicated matter because there are many options, but interesting.

The idea to begin with is that a bwise graph will contain blocks which stand for constants, functions and operators, and that these are connected up according to normal bwise logic, see for instance bwise applications and examples.

In its simplest form, making use of the tcl expr command, this could go as follows, assume we make blocks based on simple basic arithmetic, such as doubling a number, adding two numbers, etc, as example:

Image TV Wiki exaformula1.jpg

The saved canvasfile:


 global bcount scopeindex wireindex shellindex drumindex entrycount moncount proccount seqcount stackcount termindex  textcount 
 set bcount 0
 set scopeindex 0
 set wireindex 6
 set shellindex 0
 set drumindex 0
 set moncount 1
 set textcount 2
 .mw.c create rectangle 10.0 10.0 50.0 40.0 -activedash {} -activefill {} -activeoutline {} -activeoutlinestipple {} -activestipple {} -activewidth 0.0 -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledoutline {} -disabledoutlinestipple {} -disabledstipple {} -disabledwidth 0 -fill yellow -offset 0,0 -outline darkblue -outlineoffset 0,0 -outlinestipple {} -state {} -stipple {} -tags {double newblock block} -width 1.0
 .mw.c create text 30.0 40.0 -activefill {} -activestipple {} -anchor n -disabledfill {} -disabledstipple {} -fill darkblue -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {double crb label} -text double -width 0
 .mw.c create text 9.0 29.0 -activefill {} -activestipple {} -anchor se -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {double crb pinname in} -text in -width 0
 .mw.c create line -10.0 30.0 10.0 30.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {double newblock pin in typein} -width 2.0
 .mw.c create text 51.0 29.0 -activefill {} -activestipple {} -anchor sw -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {double crb pinname out} -text out -width 0
 .mw.c create line 70.0 30.0 50.0 30.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {double newblock pin out typeout} -width 2.0
 .mw.c create rectangle 172.0 68.0 212.0 113.0 -activedash {} -activefill {} -activeoutline {} -activeoutlinestipple {} -activestipple {} -activewidth 0.0 -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledoutline {} -disabledoutlinestipple {} -disabledstipple {} -disabledwidth 0 -fill yellow -offset 0,0 -outline darkblue -outlineoffset 0,0 -outlinestipple {} -state {} -stipple {} -tags {add newblock block} -width 1.0
 .mw.c create text 192.0 113.0 -activefill {} -activestipple {} -anchor n -disabledfill {} -disabledstipple {} -fill darkblue -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {add crb label} -text add -width 0
 .mw.c create text 171.0 87.0 -activefill {} -activestipple {} -anchor se -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {add crb pinname i1} -text i1 -width 0
 .mw.c create line 152.0 88.0 172.0 88.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {add newblock pin i1 typein} -width 2.0
 .mw.c create text 171.0 102.0 -activefill {} -activestipple {} -anchor se -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {add crb pinname i2} -text i2 -width 0
 .mw.c create line 152.0 103.0 172.0 103.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {add newblock pin i2 typein} -width 2.0
 .mw.c create text 213.0 87.0 -activefill {} -activestipple {} -anchor sw -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {add crb pinname out} -text out -width 0
 .mw.c create line 232.0 88.0 212.0 88.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {add newblock pin out typeout} -width 2.0
 .mw.c create rectangle 275.0 103.0 315.0 148.0 -activedash {} -activefill {} -activeoutline {} -activeoutlinestipple {} -activestipple {} -activewidth 0.0 -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledoutline {} -disabledoutlinestipple {} -disabledstipple {} -disabledwidth 0 -fill yellow -offset 0,0 -outline darkblue -outlineoffset 0,0 -outlinestipple {} -state {} -stipple {} -tags {divide newblock block} -width 1.0
 .mw.c create text 295.0 148.0 -activefill {} -activestipple {} -anchor n -disabledfill {} -disabledstipple {} -fill darkblue -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {divide crb label} -text divide -width 0
 .mw.c create text 274.0 122.0 -activefill {} -activestipple {} -anchor se -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {divide crb pinname num} -text num -width 0
 .mw.c create line 255.0 123.0 275.0 123.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {divide newblock pin num typein} -width 2.0
 .mw.c create text 274.0 137.0 -activefill {} -activestipple {} -anchor se -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {divide crb pinname den} -text den -width 0
 .mw.c create line 255.0 138.0 275.0 138.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {divide newblock pin den typein} -width 2.0
 .mw.c create text 316.0 122.0 -activefill {} -activestipple {} -anchor sw -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {divide crb pinname out} -text out -width 0
 .mw.c create line 335.0 123.0 315.0 123.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {divide newblock pin out typeout} -width 2.0
 .mw.c create rectangle 45.0 95.0 85.0 125.0 -activedash {} -activefill {} -activeoutline {} -activeoutlinestipple {} -activestipple {} -activewidth 0.0 -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledoutline {} -disabledoutlinestipple {} -disabledstipple {} -disabledwidth 0 -fill yellow -offset 0,0 -outline darkblue -outlineoffset 0,0 -outlinestipple {} -state {} -stipple {} -tags {const newblock block} -width 1.0
 .mw.c create text 65.0 125.0 -activefill {} -activestipple {} -anchor n -disabledfill {} -disabledstipple {} -fill darkblue -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {const crb label} -text const -width 0
 .mw.c create text 86.0 114.0 -activefill {} -activestipple {} -anchor sw -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {const crb pinname out} -text out -width 0
 .mw.c create line 105.0 115.0 85.0 115.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {const newblock pin out typeout} -width 2.0
 .mw.c create rectangle 107.0 173.0 147.0 203.0 -activedash {} -activefill {} -activeoutline {} -activeoutlinestipple {} -activestipple {} -activewidth 0.0 -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledoutline {} -disabledoutlinestipple {} -disabledstipple {} -disabledwidth 0 -fill yellow -offset 0,0 -outline darkblue -outlineoffset 0,0 -outlinestipple {} -state {} -stipple {} -tags {slider newblock block} -width 1.0
 .mw.c create text 127.0 203.0 -activefill {} -activestipple {} -anchor n -disabledfill {} -disabledstipple {} -fill darkblue -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {slider crb label} -text slider -width 0
 .mw.c create text 148.0 192.0 -activefill {} -activestipple {} -anchor sw -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {slider crb pinname out} -text out -width 0
 .mw.c create line 167.0 193.0 147.0 193.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {slider newblock pin out typeout} -width 2.0
 .mw.c create rectangle 409.0 146.0 469.0 186.0 -activedash {} -activefill {} -activeoutline {} -activeoutlinestipple {} -activestipple {} -activewidth 0.0 -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledoutline {} -disabledoutlinestipple {} -disabledstipple {} -disabledwidth 0 -fill yellow -offset 0,0 -outline darkblue -outlineoffset 0,0 -outlinestipple {} -state {} -stipple {} -tags {Text1 newblock block} -width 1.0
 .mw.c create text 439.0 186.0 -activefill {} -activestipple {} -anchor n -disabledfill {} -disabledstipple {} -fill darkblue -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {Text1 crb label} -text Text1 -width 0
 .mw.c create text 408.0 165.0 -activefill {} -activestipple {} -anchor se -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {Text1 crb pinname in} -text in -width 0
 .mw.c create line 389.0 166.0 409.0 166.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {Text1 newblock pin in typein} -width 2.0
 .mw.c create text 415.0 156.0 -activefill {} -activestipple {} -anchor nw -disabledfill {} -disabledstipple {} -fill navy -font {courier 10} -justify left -offset 0,0 -state {} -stipple {} -tags {Text1 textfield} -text 0.466666666667 -width 0
 .mw.c create line 335.0 123.0 389.0 166.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {wire0 connect wire divide out Text1 in} -width 1.0
 .mw.c create line -10.0 30.0 105.0 115.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {wire1 connect wire double in const out} -width 1.0
 .mw.c create line 70.0 30.0 152.0 88.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {wire2 connect wire double out add i1} -width 1.0
 .mw.c create line 152.0 103.0 167.0 193.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {wire3 connect wire add i2 slider out} -width 1.0
 .mw.c create line 232.0 88.0 255.0 138.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {wire4 connect wire add out divide den} -width 1.0
 .mw.c create line 255.0 123.0 167.0 193.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {wire5 connect wire divide num slider out} -width 1.0

 # now the block related variables\n
 set double.bfunc {set double.out [expr 2.0*${double.in}]}
 set double.bfunc_init {}
 set double.in {8}
 set double.out {16.0}
 set add.bfunc {set add.out [expr ${add.i1}+${add.i2}]}
 set add.bfunc_init {}
 set add.i1 {16.0}
 set add.i2 {52}
 set add.in {}
 set add.out {30.0}
 set divide.bfunc {set divide.out [expr ${divide.num}/${divide.den}]}
 set divide.bfunc_init {}
 set divide.den {30.0}
 set divide.in {}
 set divide.num {52}
 set divide.out {1.73333333333}
 set const.bfunc {set const.out 8}
 set const.bfunc_init {}
 set const.out {8}
 set slider.bfunc {set slider.out [.sl.value.s get]}
 set slider.bfunc_init {}
 set slider.out {52}
 set Text1.bfunc {global mc; $mc itemco [tag_and { Text1 textfield }] -text ${Text1.in} }
 set Text1.bfunc_init {}
 set Text1.in {0.466666666667}


 proc slidsend { {n} {v} } {
 #  send "$n $v"

 }
 proc slidsendupdate { } {
 #   send update
 #net_funprop const
 #net_funprop slider
 foreach i [net_funct Text1] {net_funprop $i}
 }

 sliders {{value}}

The example canvas, simply sourcing in the above one top of bwise lets you use it, makes some computation, based on tcl expr and the bwise graph data flow logic, and even lets you automatically recompute when changing one of the inputs to the computation using the slider.

Every block is a simple computation. (On day I'll make a back-extractor for 'new*' commands based on an exisiting canvas to make nicer sharable canvas files... Unless somebody beats me to it!:))

Most people in the computer corner will understand we could also make a single expr formula to evaluate the above graphs' computation, and we will now look into how we could do that automatically.

I wanted another evaluation function for the blocks, leaving the normal one in place, so I changed the lookup proc for the blockfunction to for this purpose return a special block function variable name, which is intended for our current symbolic processing:

 proc blockfunc { {block} {type {}} } {
   set o {}
   if {$type != {} } {set type _$type};
 #  append o  $block . bfunc $type ;
   append o  $block . bfuncsymb $type ;
   return $o
 } 

this proc is called in the net_funprop bwise firing propagation routine, so now the block fire rule for each block is contained in the the variable $blockname.bfuncsymb . Now we are going to assume each bwise block in the graph we are dealing with has a corresponing procedure with the same name, and the alternative fire rule will simply reflect that each block performs its function on the input pins, which carry the functional composition of the previous blocks.

This long oneliner sets up the new block fire rule for that purpose that each block outputs it's name followed by arguments consisting of the literal contents of it's input pins, enclosed by brackets ():

 # search for the canvas items with 'block' tag, for which there is one for each bwise block
 foreach i [tag_and {block}] {
    # get the block names corresponding to the found item numbers
    set bl [block_name_fromid $i];
    set ps {};
    #list all full pin variable names
    foreach j [block_get_pinnames $bl typein] {
       append ps "\${$bl.$j} "
    };
    # construct the $blockname.bfuncsymb variable content to make 
    # this string when fired: [blockname $input1 ... $inputn]
    set "$bl.bfuncsymb" "set $bl.[block_get_pinnames $bl typeout] " ;
    append "$bl.bfuncsymb" "\"\\\[$bl $ps\\\] \"" 
 }

Running the above network now, gives an outcome independent of input values, which is (at the output of 'divide' the last computation block in the chain):

  [divide [slider ]  [add [double [const ]  ]  [slider ]  ]  ] 

and that is the correct recursive function call construct which corresponds with the above bwise graph, assuming all functions exist and do what the blocks with corresponding names do. To see the structure, lets prettyprint (without changing the brackets, except leaing out the outer ones for the implicit toplevel eval):

  divide [
     slider 
  ] [
     add [
        double [
           const 
        ]
     ] [
        slider
     ]
  ]

The procs corresponding with these blocks are easy to make of course:

 proc divide {num den} { return [expr $num / $den] }
 proc double { {in} } { return [expr 2.0*$in] } 
 proc slider {} { return [.sl.value.s get] }
 proc const {} {return 8}
 proc add {i1 i2} {return [expr $i1+$i2]}
 proc divide {num den} {return [expr $num/$den]}

When running the original network by the slider or by funprop-ing both the const and slider block, we now get the same value as simply evaluating the above constructed formula, which was the intention.

Remember that it is possible to fully automatically create blocks from tcl procedures, see: Automatically generate Bwise blocks from procedures .

With the changed block function variable to point to our new block function to only do functional composition of results, no actual bwise block firing of he normal kind takes place, so that the text block will not change its graphics or reflect the value at its regular input pin. The block pin variables, of the normal form $blockname.$pinname do work normally, but now interact with our new ${$blockname.bfuncsymb} fire scripts, where they are told to only carry argument composition data, which can be seen in the Data windows from the corresponding blockwise popup menu.

Image TV Wiki funccomp1.jpg

The bfuncsymb field (corresponding in this case with the global tcl variable add.bfuncsymb) indicates the script executed as block function at the moment, which would normally be the bfunc field, and clearly it simply appends the arguments, states the block basename, and encloses that result in unevaluated bracketss. The output of this example block thus becomes a tcl function composition which calls a tcl procedure with the name of the block (assuming that exists) and as arguments the outcome of the previous blocks connected to this blocks' inputs, but symbolically, as when one does a functional (de-) composition.

As a little challenge, while maybe somebody feels called to do canvas saving in alternative ways, lets say by using default setting automatically for graphical compoments... :) , and while making some other (non-wiki) pages about one of my purposes with this stuff (mathematically based sound synthesis for instance), I first now plan to make a page on the interesting reverse concept of the example here: constructing a bwise graph from a formula .