Error: for loop in TCL Ffile - tcl

i am new to ns2.
In the following code
for {set i 0 }{$i < $val(nn)}{incr i }
{
set n$i [$ns node]
$n$i set X_[expr 10+round(rand()*40)]
}
I want to create 50 nodes but while executing the tcl file it shows the error as "invalid command name "$n0" while executing "$n$i set X_[expr 10+round(rand()*40)]". I have provided nn to be 50.

You've got two classes of problems with the code you posted.
Basic syntax problems
for {set i 0 }{$i < $val(nn)}{incr i }
{
This won't work because you need spaces between arguments to for (yes, for isn't a keyword in Tcl; it's just a regular command) and you must put the start of the body at the end of the line. You are strongly recommended to use One True Brace style coding; that's what Tcl's syntax makes most easy.
Here's how to fix that:
for {set i 0} {$i < $val(nn)} {incr i} {
Note that all I've done to fix it is move around (and insert) spaces.
Deeper syntax problems
set n$i [$ns node]
$n$i set X_[expr 10+round(rand()*40)]
These lines have a problem in that you're trying to use double substitution. Well sort of. The $ handling is really dumb, in that it checks for a non-empty “nice” variable name afterwards, substituting it if it is there and becoming a plain old $ otherwise. This means that $n$i is the concatenation of what you get from $n and $i.
The easiest fix is to use another variable as well:
set thisnode [$ns node]
set n$i $thisnode
$thisnode set X_[expr 10+round(rand()*40)]
You can even roll those first two lines into one, since the result of set is the value that was just set:
set n$i [set thisnode [$ns node]]
$thisnode set X_[expr 10+round(rand()*40)]
But we really ought to encourage you to use arrays for this sort of thing, as they do allow double-substitution of a sort.
set n($i) [$ns node]
$n($i) set X_[expr 10+round(rand()*40)]
Those extra (…) make a big difference!
You could also use a list to store the generated items:
lappend n [$ns node]
[lindex $n end] set X_[expr 10+round(rand()*40)]
But I'd really be tempted to use a helper variable in that case:
lappend n [set thisnode [$ns node]]
$thisnode set X_[expr 10+round(rand()*40)]
Other things
You also ought to put your expression in curly braces. It doesn't matter in this particular case as it's not got any substitutions in it, but it's an extremely good habit to get into as it makes it much easier for Tcl to compile the expression in general; i.e., when the overall expression is a literal, Tcl can compile it ahead of time and that's fast, whereas when the expression is non-literal it can't be compiled until the last moment, has to be compiled each time through the loop, and can have a whole bunch of other hazards too. It would make a much larger difference if you were doing a loop over millions of things rather than 50…
It might be worth factoring the expression into a little procedure, for clarity:
proc random {from to} {
expr {$from + round(rand() * ($to-$from))}
}
$n($i) set X_[random 10 50]
Write it (and debug it!) once and reuse it elsewhere. It's the Lazy Programmers' Way.
I'm guessing that this is really an NS2 question too. In which case you'll probably run into problems still: the underscore between the X and the [expr …] is a little surprising, unless you really have got objects with large numbers of very similar variables where you want to read (and then discard the value of) a random one of them. That would be… rather surprising, yes? I suspect you might be better off with:
for {set i 0} {$i < $val(nn)} {incr i} {
set n($i) [$ns node]
$n($i) set X [expr {10+round(rand()*40)}]
}
Do you need to keep the references around? If not, you might even be OK with:
for {set i 0} {$i < $val(nn)} {incr i} {
[$ns node] set X [expr {10+round(rand()*40)}]
}
But that that's probably not what you want though; in real code you'll be wanting to refer to the nodes from elsewhere so you can put in links between them…

Tcl works with whitespace-separated words (See http://tcl.tk/man/tcl8.5/TclCmd/Tcl.htm rules 1,2,3), and the syntax of the for command is
for start test next body
http://tcl.tk/man/tcl8.5/TclCmd/for.htm
You need this:
for {set i 0} {$i < $val(nn)} {incr i} {
set n$i [$ns node]
[set n$i] set X_[expr {10+round(rand()*40)}]
}

Related

How to pass integers to tcl procedure in vmd

I am new in tcl programming and I need to write a script for vmd that calculates two distances between two couples of atoms and print them in an output file. I do not understand why measure can not take atom_1, etc. This is my script and thank you for your help
proc distance {distance_1 atom_1 atom_2 distance_2 atom_3 atom_4 output} {
set outfile [open $output w]
puts $outfile "frame, $distance_1, $distance_2"
set nf [molinfo top get numframes]
for {set i 0} {$i < $nf} {incr i} {
set d1 [measure bond {$atom_1 $atom_2} frame $i]
set d2 [measure bond {$atom_3 $atom_4} frame $i]
puts $outfile "$i , $d1 , $d2"
}
close $outfile
}
The problem here is:
measure bond {$atom_1 $atom_2} frame $i
The issue is that {…} in Tcl actually means “quote this exactly, with no substitutions at all”. Instead of sending a list of two numbers in, it passes a list of two non-numbers (the literal strings $atom_1 and $atom_2).
The fix is to replace {$atom_1 $atom_2} with [list $atom_1 $atom_2].
Yes, proc and for and if make use of this behaviour. It's just that they pass things back to the Tcl interpreter engine as part of their execution.

Loop Calling Processes and assigning values in Tcl

I am currently using a loop to iterate values into a process (neighbors) in Tcl.
for {set i 0} {$i < $val(nn)} {incr i} {
for {set j 0} {$j < $val(nn)} {incr j} {
$ns at 0.0 "neighbors $node($i) $node($j) $i $j"
}
}
The above allows all the values I need to go into the process. However, inside the process some values are assigned (to a list) and no longer needed to be looped through. A brief snippet from the process:
} else {
puts "..... Do nothing .... $nd1 - $nd2"
if {([lsearch -exact $heads $nd1] != -1) || ([lsearch -exact $members $nd1] != -1) } {
incr $nd1
}
}
This is the end of a loop in the process. The puts is just a marker, but it checks if an item is contained in either of 2 two lists. If it is in either list, increment it, and move on the next possible value. That value needs to no longer be checked/looped through because it has already been put inside a list.
How do I prevent the value from continuing to be used? The 'process calling' loop will ALWAYS override what happens in the process, so even assigned values will continue to be used. Is there a different way to call processes in Tcl? Or at least, a different way to feed values to a process in Tcl? Or I guess, pull them out?
As a note, here is my process that I want to feed to (n1 and n2 are memory locations, nd1 nd2 are actual number identifiers)
set heads {}
set members {}
proc neighbors {n1 n2 nd1 nd2} {
global heads members bool allNodes
puts "Members --- $members"
puts "heads --- $heads"
if {([lsearch -exact $heads $nd1] == -1) && ([lsearch -exact $members $nd1] == -1) } {
lappend heads $nd1
set currentHead $n1
puts "Current Head: $currentHead $n1 $nd1"
} else {
puts "..... Do nothing .... $nd1 - $nd2"
if {$nd1 in $heads || $nd1 in $members} then return
#here I want it to go to the next nd1 value and NEVER use it again if it
#has already been processed
}
#Otherwise, do neighbor test with nd2
If the neighbors operation is symmetric (often true), you do the check of everything against everything else like this:
for {set i 0} {$i < $val(nn)} {incr i} {
for {set j $i} {$j < $val(nn)} {incr j} {
$ns at 0.0 [list neighbors $node($i) $node($j) $i $j]
}
}
with the inner loop starting at $i (or [expr {$i - 1}] if you don't want to check things against themselves) instead of zero. This ensures that $j is always not less than $i, effectively (approximately) halving the amount of work you need to do.
(Style point: it's considered good style to use [list ...] to prepare code for later execution, and not "..."; the former is more efficient, and the latter has some ugly cases when working with values that may have spaces in.)
What you can't do (at least not easily; there might be a method to do it) is use the result of the neighbors operation to stop future calls to neighbors from happening, as you've already scheduled them to occur by the time any of them can possibly express an opinion. It's probably easier in your case to keep a state variable and check against it for the option to do an early reject. That's a fundamental limitation of using delayed command invocation instead of direct: passing values back to do things like skipping future iterations is quite difficult (and downright tricky before Tcl 8.6; that has coroutine which simplifies the task a lot).
It feels like you want to do this:
proc neighbors {n1 n2 nd1 nd2} {
global heads members bool allNodes
if {$nd1 in $heads || $nd2 in $members} then return
... do the neighborly stuff ...
}
See https://tcl.tk/man/tcl8.6/TclCmd/expr.htm#M15 for the in operator.

For loop increment by a non-integer in TCL

I want to implement the following C code in TCL:
Float power_pitch = 8
float offset = 7.5
float threshold = 100
for(i=power_pitch+offset ; i<= threshold ; i += power_pitch)
I want to implement above forloop in TCL. I have tried the following code in TCL:
set power_pitch 8
set offset 7.5
set threshold 100
for { set i [expr $power_pitch + $offset] } { $i <= $threshold } { incr i $power_pitch}
but when I execute above code I get the following error:
expected integer but got "15.5 "
while executing incr i $power_pitch
Could you help me to implement above forloop in TCL?
The incr command only works with integers. Otherwise, use:
set i [expr {$i + $power_pitch}]
The for command itself won't mind. (Be aware of float rounding issues; they're not Tcl-specific, but can hit with anything that isn't an integer multiple of a power of 2…)
Donal has already provided the answer to the question, I'd just like to make an observation in two points about the for command.
for is very nearly free-form
while an integral counting loop is a typical use of for, it's by no means the only option
The for command has the synopsis
for start test next body
where start, next, and body are command strings (i.e. appropriate as an argument to eval; they can be empty, contain single commands, or be full scripts) and test is a boolean expression string (i.e. appropriate as an argument to expr and evaluating to something that is or can be coerced into a boolean value).
Usually, start is used to set up for test and body, and next is supposed to bring the state incrementally closer to having test return a false value, but that's just a convention, not a requirement. The following are perfectly valid (but rather smelly) invocations:
for {set n 0 ; puts -nonewline X} {[incr n] < 5} {puts -nonewline X} {
puts -nonewline [string repeat - $n]
}
for {set f [open foo.txt] ; set n 0} {$n >= 0} {puts $line} {
set n [chan gets $f line]
}
Give for any combination of command strings and boolean expression, and it will run. It might execute its body forever or not even once, but it will run. Don't limit yourself to for {set i 0} {$i < 10} {incr i} {...} invocations, that's 1950s thinking.
Even if you just want to use it for counting loops, there are still lots of options, for instance:
for {set i 0} {$i < $limit} {incr i} {...} ;# simple increment
for {set i 0} {$i < $limit} {incr i $n} {...} ;# stepping increment/decrement
for {set i 0} {$i < $limit} {incr i $i} {...} ;# doubling increment
for {set i 0} {$i < $limit} {set i [expr {...}]} {...} ;# arbitrary change
Free your mind, the rest will follow.
Documentation: chan, expr, for, incr, open, puts, set, string

TK/TCL, trouble understanding this tic tac toe code snippet

Can anyone help explain to me what the snippet below does. This code snippet is taken from http://wiki.tcl.tk/12374. It is meant to create a tic tac toe game. There are not many resources out there for understanding Tk/Tcl so this is giving me significant difficulty.
proc DrawBoard {{redraw 0}} {
global S B GAME C
if {$redraw} { ;# Must redraw everything
.c delete all
set w2 [expr {$B(w2) - 15}] ;# Make a little margins
set h2 [expr {$B(h2) - 15}]
set hbar [expr {$h2 / 3.0}]
set vbar [expr {$w2 / 3.0}]
set B(0) [list -$w2 -$h2 -$vbar -$hbar] ;# All 9 cells
set B(1) [list -$vbar -$h2 $vbar -$hbar]
set B(2) [list $vbar -$h2 $w2 -$hbar]
set B(3) [list -$w2 -$hbar -$vbar $hbar]
set B(4) [list -$vbar -$hbar $vbar $hbar]
set B(5) [list $vbar -$hbar $w2 $hbar]
set B(6) [list -$w2 $hbar -$vbar $h2]
set B(7) [list -$vbar $hbar $vbar $h2]
set B(8) [list $vbar $hbar $w2 $h2]
for {set i 0} {$i < 9} {incr i} { ;# Rectangle for each cell
.c create rect $B($i) -tag b$i -fill {} -outline {}
.c bind b$i <Button-1> [list DoClick $i]
set B($i) [ShrinkBox $B($i) 25]
}
.c create line -$w2 $hbar $w2 $hbar -tag bar ;# Draw the cross bars
.c create line -$w2 -$hbar $w2 -$hbar -tag bar
.c create line $vbar -$h2 $vbar $h2 -tag bar
.c create line -$vbar -$h2 -$vbar $h2 -tag bar
.c itemconfig bar -width 20 -fill $::C(bars) -capstyle round
}
.new config -state [expr {$GAME(tcnt) == 0 ? "disabled" : "normal"}]
for {set i 0} {$i < 9} {incr i} {
.c itemconfig b$i -fill {} ;# Erase any win lines
DrawXO $GAME(board,$i) $i
}
foreach i $GAME(win) { ;# Do we have a winner???
.c itemconfig b$i -fill $C(win)
}
}
Ok, the most significant question I have regards w2, h2, hbar, vbar variables. Particularly with how they are declared. For instance, set w2 [expr {$B(w2) - 15}]. How can w2 be defined referring to itself??? The author uses these variables to draw the tic tac toe lines, but I don't even know how what these variables mean. Does these variables specify some dimension of the canvas so that the author can use it to bind particular regions to click activities?
If I understand these four variables, everything else will make sense!
Here is the image of what the board looks like:
Variables in Tcl (Tk is just a window drawing toolkit that lives on top of Tcl) are defined when they are written to; there's usually no explicit declaration. The only exception to this is with variables directly in a namespace, where it is best practice to use the variable command to declare them before first use, like this:
namespace eval exampleNamespace {
variable xmpl1 "abc def"
# Or equivalently...
variable xmpl2
set xmpl2 "abc def"
# You have to use the second style with arrays...
variable arrayXmpl
set arrayXmpl(1) "pqr stu"
set arrayXmpl(2) "qwerty uiop"
}
Local variables in procedures don't need declaring, though if you want to access a variable that isn't local you have to use a command (often global or upvar) to bring it into scope.
proc variableExample {formalArgument1 formalArgument2} {
set localVar1 "abc"
set localVar2 "def"
global thisOtherVar
append thisOtherVar "ghi" $formalArgument1
puts "Currently, got $localVar1 $localVar2 and '$thisOtherVar'"
}
It's pretty conventional to put the global at the top of the procedure, but it's totally not necessary. It's effect persists from where you do it until the end of the procedure call. Tcl's semantics are strictly operational with extremely tightly defined evaluation order (it's left-to-right, always).
Now, arrays are aggregate variables. Each element of an array is a variable itself. They're distinct from normal simple variables, though the name of the overall array is in the same naming scheme as the simple variables. You can't have a simple foo and a foo(bar) in the same scope (without unsetting one first, which removes the variable). The keys into the elements are strings — the implementation behind the scenes is a high-performance hash table — that are entirely not variables and this means that the B(w2) and w2 variables are entirely distinct; they're not the same thing at all. However, we can use variables (and other Tcl substitutions) in computing the string to use as a key, so we can do this:
set name "w2"
set B($name) "example of "
append B(w2) "array key handling"
puts "this is an $B($name)"
Let's look at the example that you were puzzling over:
set w2 [expr {$B(w2) - 15}]
Breaking it into pieces:
set w2 […]
It's going to write to the variable w2. That's what the set command does with two arguments. The thing that is going to be written in is the result of evaluating another command. We need to look deeper.
expr {$B(w2) - 15}
Breaking it into pieces:
expr {…}
That yields the result of evaluating the expression in the braces. It's strongly recommended that you put braces around all your expressions; it's safer and much faster. What's the expression? (Note that expressions use a different syntax to the rest of Tcl.)
$B(w2) - 15
OK, that's subtracting 15 (the number) from the value read (because of the $) from the w2 element of the array B. The w2 here is just a string. That there's a variable elsewhere with the same name is coincidence.
And that's it. Reassembling the pieces, we see that:
set w2 [expr {$B(w2) - 15}]
Assigns the result of subtracting 15 from the contents of B(w2) to the variable w2. That's all it does. (The array B is a global array; see the global at the top of the procedure.)
The lines:
set w2 [expr {$B(w2) - 15}] ;# Make a little margins
set h2 [expr {$B(h2) - 15}]
set hbar [expr {$h2 / 3.0}]
set vbar [expr {$w2 / 3.0}]
These get the half height and width of the canvas from the global array B, remove 15 pixels for a margin, and then set hbar/vbar to a third of that value so that the coordinates for drawing are easier. It helps once you realize that the canvas has had its drawing origin moved (similar to in scrolling) to the center of its window. And be aware that doing -$hbar is actually being a bit naughty, though cute; it's using string concatenation to negate a value, which is OK when the value is positive and doesn't have an explicit sign, but would be fragile if that ever changed. And it's slow by comparison with doing [expr {-$hbar}], though that's longer; the cost of computation isn't exactly matched with the length of the command.

Tcl tool similar to Quickcheck or ScalaCheck

Is there an automatic test case generated available for Tcl? Similar to quickcheck or scala check? An internet search did not reveal any library.
tl;dr: Nothing that I'm aware of, but you can code it on top of tcltest easily enough.
I looked into some QuickCheck and ScalaCheck tutorials. Interesting, but they have the problem of not guaranteeing to find problems. The examples all nicely show how things can work, when problems are found with short inputs, but with the stochastic input models (poisson distributions I suspect?) used I really don't think there's much chance of finding upper-bound or specific-value failures unless you feed through a very large amount of data indeed.
There's also the problem that Tcl code is in general stateful; testing when you've got state about requires a more complex approach. Basically, you in general need an extra piece of code to put the system into the state you want to test and another to take the system out of that state and return it to quiescent. Good test frameworks have this sort of thing down pat, so it's not actually a real problem. Just a complication you need to be aware of.
But we can use the fact that Tcl is pretty much all a domain-specific language to make our own little fuzz tester. (The upvar and uplevel commands are awesomely useful for this sort of thing.)
package require tcltest 2
proc fuzzInteger {var from to count test} {
upvar 1 $var v
for {set i 0} {$i < $count} {incr i} {
set v [expr {$from+int(rand()*($to-$from))}]
uplevel 1 $test
}
}
proc fuzzList {var P language count test} {
upvar 1 $var v
for {set i 0} {$i < $count} {incr i} {
set v {}
while {rand() <= $P} {
lappend v [lindex $language [expr {int(rand() * [llength $language])}]]
}
uplevel 1 $test
}
}
# Demonstrate by throwing random crap into 'lindex'; it should never produce an error
fuzzList abcList 0.5 {a b c} 500 {
fuzzInteger foobar 0 20 500 {
tcltest::test lindex-fuzztest-[incr count] "fuzzed: lindex {$abcList} $foobar" -body {
lindex $abcList $foobar
} -match glob -result *
}
}
# Print the final report
tcltest::cleanupTests
In this case, there was no need for state setup/cleanup; those would be handled by the -setup and -cleanup clauses to the tcltest::test. Also note that it's an extremely good idea to record what fuzzed values are used in the title of the test or by doing substitutions in the body (the second is harder, BTW; my example above shows the first).