How to do += in TCL - math

set windowSize 0
for {set i 0} {$i < 14} {incr i} {
set $windowSize [expr $windowSize + [$tcp($i) set cwnd_]]
}
puts "$windowSize"
This prints out zero, when the values being added are non zero. How to do this without a temp var? Holla if you love TCL. ...dead silence.

set $windowSize substitutes the value of $windowSize before running the command.
You want set windowSize [expr ...], or even simpler:
incr windowSize [$tcp($i) set cwnd_]

Related

constraint dependents in array of classes

How can I constraint 2 variables in an array of classes, when there is a dependent between different items of the array?
class X;
rand bit en;
rand int idx;
constraint cnst1{
idx inside {[0:9]};
}
endclass
class Y;
rand X arr_x[100];
constraint cnst2{
???
}
endclass
I want to create cnst2 that will guarantee that:
each idx optional value (0-9) will be set for at least one of the arr_x[i].idx .
for all of the arr_x[i] that have the same value of idx, at least 1 will have en set to 1.
for example:
let's say that only the following have idx == 9:
arr_x[0].idx == 9;
arr_x[13].idx == 9;
arr_x[44].idx == 9;
arr_x[75].idx == 9;
arr_x[81].idx == 9;
arr_x[93].idx == 9;
need to guarantee that:
arr_x[0].en | arr_x[13].en | arr_x[44].en | arr_x[75].en | arr_x[81].en | arr_x[93].en == 1;
and so on for every idx value;
You want the or array reduction method. Also create a helper array so you can iterate from 0-9. This constraint reads: if at least one element has the value 0-9, then one of those elements has to have en set.
bit iterator[10];
constraint cnst2{
foreach(iterator[i])
arr_x.or(x) with (i ==x.idx) -> // needed if idx will not have every value 0-9
arr_x.or(y) with (i == y.idx && y.en);
}
See sections 18.5.8.2 Array reduction iterative constraints and 7.12.3 Array reduction methods in the IEEE 1800-2017 SystemVerilog LRM.

Recursive TCL proc without explicit return

I am writting a simple "proc" to calculate the factorial. I would like to understand why my function does not work without the return statement.
According to TCL docs, functions that are defined without explicit "return",
return the value of the last executed command in its body.
proc fac { n } {
if { $n == 1 } {
return 1
}
puts $n
set n [expr {$n - 1}]
return [expr {[fac $n ] * $n}]
}
puts [fac 5] # ans 24
When the "return" is removed, I get the following error message:
invalid command name "1"
while executing
"[expr {[fac $n ] * $n}] "
(procedure "fac" line 7)
invoked from within
I expected that without the explicit "return", the function should return 24 as well.
Your expectation is correct. But you have square brackets around expr procedure in the last line. It is:
[expr {[fac $n] * $n}]
This means for the interpreter: 1) execute expr procedure with given argument; 2) execute the result of expr procedure. Because of this, the interpreter tries to execute procedure 1 that doesn't exist and you receive an error.
To fix this error - just remove square brackets from the last line:
proc fac { n } {
if { $n == 1 } {
return 1
}
puts $n
set n [expr {$n - 1}]
expr {[fac $n ] * $n}
}

Fastest route to last key of dict in Tcl

Let's say that I have a Tcl dictionary. I want the fastest way to get the last entered key of the dict (not the value).
Theoretically, I could use:lindex [ dict keys $dict ] end Does anyone know anything else, which is faster?
This is pretty fast:
% set data {a 1 b 2 c 3}
a 1 b 2 c 3
% proc p1 {} {dict get $::data [lindex [dict keys $::data] end]}
% time {p1} 100000
1.87782 microseconds per iteration
But you can shave off about a microsecond by remembering the last key:
oo::object create mydict
oo::objdefine mydict {
variable data last
method add args {
lappend data {*}$args
set last [lindex [dict keys $data] end]
}
method getLast {} {
dict get $data $last
}
}
% mydict add a 1 b 2 c 3
c
% time {mydict getLast} 100000
0.82731 microseconds per iteration
Documentation:
create (method of oo::class),
dict,
lappend,
lindex,
method (object configuration subcommand),
proc,
oo::objdefine (object definition command),
oo::object (class of objects),
set,
time,
variable (object slot subcommand),
{*} (syntax)
I'm seeing [lindex $data end-1] to be faster.
tclsh last.tcl
time_list : 1.0693949999999999 microseconds per iteration
time_dict : 279.470543 microseconds per iteration
last.tcl
set data [dict create]
for {set i 0} {$i < 10000} {incr i} {
dict set data "key_$i" $i
}
set time_dict [time {
set last_key [lindex [dict keys $data] end]
} 1000]
set time_list [time {
set last_key [lindex $data end-1]
} 1000]
puts "time_list : $time_list"
puts "time_dict : $time_dict"

Recursion confusion with local variables

I'm trying to improve my recursion skill(reading a written recursion function) by looking at examples. However, I can easily get the logic of recursions without local variables. In below example, I can't understand how the total variables work. How should I think a recursive function to read and write by using local variables? I'm thinking it like stack go-hit-back. By the way, I wrote the example without variables. I tried to write just countThrees(n / 10); instead of total = total + countThrees(n / 10); but it doesn't work.
with total variable:
int countThrees(int n) {
if (n == 0) { return 0; }
int lastDigit = n % 10;
int total = 0;
total = total + countThrees(n / 10);
if (lastDigit == 3) {
total = total + 1;
}
return total;
}
simplified version
int countThrees(int x)
{
if (x / 10 == 0) return 0;
if (x % 10 == 3)
return 1 + countThrees(x / 10);
return countThrees(x / 10);
}
In both case, you have to use a stack indeed, but when there are local variables, you need more space in the stack as you need to put every local variables inside. In all cases, the line number from where you jump in a new is also store.
So, in your second algorithme, if x = 13, the stack will store "line 4" in the first step, and "line 4; line 3" in the second one, in the third step you don't add anything to the stack because there is not new recursion call. At the end of this step, you read the stack (it's a First in, Last out stack) to know where you have to go and you remove "line 3" from the stack, and so.
In your first algorithme, the only difference is that you have to add the locale variable in the stack. So, at the end of the second step, it looks like "Total = 0, line 4; Total = 0, line 4".
I hope to be clear enough.
The first condition should read:
if (x == 0) return 0;
Otherwise the single 3 would yield 0.
And in functional style the entire code reduces to:
return x == 0 ? 0
: countThrees(x / 10) + (x % 10 == 3 ? 1 : 0);
On the local variables:
int countThrees(int n) {
if (n == 0) {
return 0;
}
// Let an alter ego do the other digits:
int total = countThrees(n / 10);
// Do this digit:
int lastDigit = n % 10;
if (lastDigit == 3) {
++total;
}
return total;
}
The original code was a bit undecided, when or what to do, like adding to total after having it initialized with 0.
By declaring the variable at the first usage, things become more clear.
For instance the absolute laziness: first letting the recursive instances calculate the total of the other digits, and only then doing the last digit oneself.
Using a variable lastDigit with only one usage is not wrong; it explains what is happening: you inspect the last digit.
Preincrement operator ++x; is x += 1; is x = x + 1;.
One could have done it (recursive call and own work) the other way around, so it probably says something about the writer's psychological preferences
The stack usage: yes total before the recursive call is an extra variable on the stack. Irrelevant for numbers. Also a smart compiler could see that total is a result.
On the usage of variables: they can be stateful, and hence are useful for turning recursion into iteration. For that tail recursion is easiest: the recursion happening last.
int countThrees(int n) {
int total = 0;
while (n != 0) {
int digit = n % 10;
if (digit == 3) {
++total;
}
n /= 10; // Divide by 10
}
return total;
}

Tcl error : wrong # args: should be "set varName ?newValue?"

I tried to run the following Tcl script and got the error: wrong # args: should be "set varName ?newValue?"
What does this mean?
Note: The script includes terms specific to VMD program, such as mol and resid. Please disregard them.
#count water molecules between chain A and chain C or between #chain B and chain C
set input_file [open ./name_3_pdb_chain_renamed.dat r]
set data [read $input_file]
set data [split $data "\n"]
close $input_file
set chain_list [lindex $data 0]
cd 7_count_water
set outfile [open count_water3.dat w]
set chain_compare ""
set pdblen [llength $chain_list]
for {set i 0} {$i<$pdblen} {incr i} {
set pid [lindex [lindex $chain_list $i] 0]
set len [llength [lindex $chain_list $i]]
mol load pdb ../2_chain_rename/${pid}_chain_revised.pdb
mol modstyle 0 top NewCartoon
if {$len==4} {
set chain_compare [lappend chain_compare $pid]
}
set 11 [atomselect top all]
set mid [$11 molid]
mol delete $mid
}
set lll [llength $chain_compare]
for {set j 0} {$j< $lll} {incr j} {
set pid [lindex $chain_compare $j]
mol load pdb ../2_chain_rename/${pid}_chain_revised.pdb
set 11 [atomselect top "chain A and name CA"]
set res_len [llength [$11 get resid]]
set res_id [$11 get resid]
#residue length for chain C
set ag [atomselect top "chain C and name CA"]
set ag_len [llength [$ag get resid]]
set ag_id [$ag get resid]
#loop water between chain A and chain C
for {set k 0} {$k<$res_len} {incr k} {
set water_around_a [atomselect top "{resname HOH and {within 5.0 of {chain A and resid [lindex $res_id $k]} and {within 5.0 of chain C}}} "]
set water_around_a_resid [$water_around_a get resid]
set water_around_a_resname [$water_around_a get resname]
#loop antigen residues around water
for {set g 0} {$g < $ag_len} {incr g} {
set ag_around_water [atomselect top "{chain C and resid [lindex $ag_id $g] and {within 5.0 of {resname HOH and {within 5.0 of {chain A and resid [lindex $res_id $k]}}}}} "]
set ag_around_water resid [$ag_around_water get resid]
set ag_around_water_resname [$ag_around_water get resname]
puts $outfile "$pid [lindex $res_id $k] [lindex [$11 get resname] $k] $ag_around_water_resname A: $water_around_a_resname"
}
}
set b11 [atomselect top "chain B and name CA"]
set b_res_len [llength [$b11 get resid]]
set b_res_id [$b11 get resid]
#residue length for chain C
set ag [atomselect top "chain C and name CA"]
set ag_len [llength [$ag get resid]]
set ag_id [$ag get resid]
for {set k 0} {$k<$res_len} {incr k} {
set water_around_b [atomselect top "{resname HOH and {within 5.0 of {chain B and resid [lindex $b_res_id $k]} and {within 5.0 of chain C}}} "]
set water_around_b_resid [$water_around_b get resid]
set water_around_b_resname [$water_around_b get resname]
#loop antigen residues around water
for {set g 0} {$g < $ag_len} {incr g} {
set ag_around_water [atomselect top "{chain C and resid [lindex $ag_id $g] and {within 5.0 of {resname HOH and {within 5.0 of {chain B and resid [lindex $b_res_id $k]}}}}} "]
set ag_around_water resid [$ag_around_water get resid]
set ag_around_water_resname [$ag_around_water get resname]
puts $outfile "$pid [lindex $b_res_id $k] [lindex [$b11 get resname] $k] $ag_around_water_resname A: $water_around_b_resname"
}
}
}
close $outfile
cd ..
Thank you
That message:
wrong # args: should be "set varName ?newValue?"
is a standard error thrown when a built-in command gets the wrong number of arguments to evaluate. In this case, it's coming from the set command, and indicates that you've either said set on its own, or given more than two further arguments to it.
If you examine the stack trace (usually printed with the error message when using standard tclsh, though it's changeable with user code) then you'll get told where the problem happened. However, in this case we can look through and see that this line near the bottom of the script:
set ag_around_water resid [$ag_around_water get resid]
has what appears to be a space instead of an underscore in the variable name. Now, spaces are legal in variable names, but then the variable name needs to be quoted, and that can get a bit annoying. It's usually best to avoid using them like that. Without quoting, Tcl doesn't know that that's meant to be one word; the generic parsing layer decides there's really four words there (set, ag_around_water, resid and the complex [$ag_around_water get resid]) and tells set to deal with that, which it doesn't like.
Remember, Tcl's generic syntactic parsing happens first, before command arguments are interpreted semantically. Always.
The line set ag_around_water resid [$ag_around_water get resid] needs to be changed. You probably want ag_around_water_resid instead.

Resources