finding difference between list elements in Tcl - tcl

I am a beginner in using Tcl. I am using it as VMD (molecular visualization) software uses it as a scripting language.
I have a list of co-ordinates of atom positions for a protein like: {{1 2 3} {7 9 13}, ...} I have a separate list of the same length with different positions say: {{3 5 2} {7 3 8}, ...}.
VMD has an inbuilt vecsub function which can subtract {1 2 3} and {3 5 2} to give {-2 -3 1}. I have written a foreach loop to iterate on the entire list and calculate vecsub.
My code is as follows:\
set sel1 [atomselect 0 "protein"] # selecting protein1
set sel2 [atomselect 1 "protein"] # selecting protein2
# create a list of same length as protein to store values
# $sel1 get index returns length of protein
foreach i [$sel1 get index] {
lappend x 0
}
# veclength2 returns square of vector length
# $sel1 get {x y z} returns a position list as described earlier
foreach i [$sel1 get index] {
lset x $i [expr [veclength2 [vecsub [lindex [$sel1 get {x y z}] $i] [lindex [$sel2 get {x y z}] $i]]]]
}
Is there another way to do this in Tcl? Similar to python array subtraction perhaps?

I would try this, but it's just a guess
set x [lmap p1 [$sel1 get {x y z}] p2 [$sel2 get {x y z}] {
expr [veclength2 [vecsub $p1 $p2]]
}]
With this, there's no need to pre-declare $x

Related

Does TCL containg built in functions of type get_bits and set_bits?

The get_bits will return specific bits of a value and set_bits will set specific bits of a value to a specified value. Does TCL contain such functions built in or should they be written by the user?
The binary scan command does come close to the get_bits function but is not the same thing.
There's no specific function for getting or setting a particular bit. We can make them.
proc get_bit {value bit} {
expr {($value & (1 << $bit)) != 0}
}
proc set_bit {varName bit {value 1}} {
upvar 1 $varName var
if {$value} {
set var [expr {$var | (1 << $bit)}]
} else {
set var [expr {$var & ~(1 << $bit)}]
}
}
Those will work with integer values of any width; you're not restricted to 32 bits or 64 bits.
# Lots of bits!
set x 123456789012345678901234567890
# Fetch a particular bit
puts [get_bit $x 17]
# Set a bit to 1
set_bit x 78
puts "x = $x"
# Set a bit to 0
set_bit x 75 0
puts "x = $x"

Why does not work using while for looping process

Why my script does not work. I am using while for looping process.
Hope anyone could help me for my case. The script as below;
Set global
global xmin xmax ymin ymax xVer yVer x1 y1 Count
Set paramaters
set xmin 0
set xmax 51
set ymin 0
set ymax 51
set x1 2
set y1 2
set xVer 2
set yVer 2
set Count 1
set goToVer "n"
Do looping process
while {$x1 > $xmin && $x1 < $xmax && $y1 > $ymin && $y1 < $ymax} {
# For horizontal axis
while {$x1 > $xmin && $x1 < $xmax} {
set azi [expr (45+90)]
set dip 0
set length 2
set dist [expr (cos($dip) * $length)]
set x1 [expr ($x1 + (sin($azimuth) * $dist))]
set y1 [expr ($y1 + (cos($azimuth) * $dist))]
set goToVer "y"
incr Count
}
# For vertical axis
if {$goToVer == "y"} {
set azi 45
set dip 0
set length 5
set dist [expr (cos($dip) * $length)]
set x1 [expr ($xVer + (sin($azimuth) * $dist))]
set y1 [expr ($yVer + (cos($azimuth) * $dist))]
set xVer $x1
set yVer $y1
incr Count
}
}
Thanks in advance!
I don't know what the problem is, but there are some things that we can do to make everything better. First step: let's ry factoring out the coordinate conversion code itself into a little procedure (I've fixed the braces around the expressions too):
proc convert {x y length azimuth dip} {
set dist [expr {cos($dip) * $length}]
set x1 [expr {$x + sin($azimuth) * $dist}]
set y1 [expr {$y + cos($azimuth) * $dist}]
return [list $x1 $y1]
}
while {$x1 > $xmin && $x1 < $xmax && $y1 > $ymin && $y1 < $ymax} {
# For horizontal axis
while {$x1 > $xmin && $x1 < $xmax} {
set azi [expr (45+90)]
set dip 0
set length 2
lassign [convert $x1 $y1 $length $azi $dip] x1 y1
set goToVer "y"
incr Count
}
# For vertical axis
if {$goToVer == "y"} {
set azi 45
set dip 0
set length 5
lassign [convert $xVer $yVer $length $azi $dip] x1 y1
incr Count
}
}
Next, the value of azi in the inner loop is suspicious; it looks like it is in degrees but Tcl's trigonometry functions (like those in most other programming languages) take their argument in radians. Multiply it by π/180°.
Finally, the logic of the loops is weird. I'm not saying it is wrong… but I really find it hard to comprehend what you'd use looping like that for. To loop a pair of coordinates over some space using equal steps on the axes, you use for loops with integer iterator variables and then apply a conversion to get your floating point coordinates (this is best because it limits cumulative errors):
set azi [expr {(45 + 90) * 3.1415927/180}]
set dip 0
set length 2
for {set x $xmin} {$x <= $xmax} {incr x} {
for {set y $ymin} {$y <= $ymax} {incr y} {
set dist [expr {cos($dip) * $length}]
set x1 [expr {$x + sin($azimuth) * $dist}]
set y1 [expr {$y + cos($azimuth) * $dist}]
# I assume you want to do something with $x1,$y1 here…
}
}
Alternatively, you could use regular spacing in polar coordinates, or any other regular scheme; it's just that good code exploits regularity and you're strongly recommended to work that way if you can. But that might not be what you were trying to do at all. Your code is confusing in its intent.
Which brings me to your actual bugs, which appear to revolve around state management. The logic with the goToVer was confused, BTW, and that might've been the problem you were having. You were setting it in the inner loop, but from that point on it was always set. I recommend not doing things like that as it is quite difficult to debug (there are cases where it can make sense, but it doesn't look like you're doing them) and instead sticking to regular grids, but they can work. I'm guessing that you are missing a reset of the variable to 0 at some point in the outer loop, probably just before the inner loop starts.

Creating a list of first elements from a list of lists in tcl

Say I have a list like this: {{1 2 3} {4 5 6} {7 8 9}} and I'd like to create a new list made of the first element of each of the nested list: {1 4 7}. I Know how to do that in a couple of lines using 'foreach', but is that a more elegant way or, better yet, a built-in function that does that?
If you're using Tcl 8.6 then there's lmap command which does mapping of a list and can be used for your task:
%set a {{1 2 3} {4 5 6} {7 8 9}}
{1 2 3} {4 5 6} {7 8 9}
%lmap x $a {lindex $x 0}
1 4 7
The lmap command iterates through the list $a, assigns the currently processing list item to a given variable (x in the example) and calls a command (lindex $x 0 in te example).
As you know that you want to search the first element , so that is optimum solution for you to use foreach. The Complexity will be in your case O(1). As you just need to access the first value on index which is fixed.
As an alternative to using [lmap]/[lindex], re-formulate the problem to one on a flattened, but regular list. That is, accessing the nth (1st, 2nd, ...) element after having flattened the input list of lists:
set a {{1 2 3} {4 5 6} {7 8 9}}
set A [concat {*}$a]; # flattened list: {1 2 3 4 5 6 7 8 9}
lmap {pick drop drop} $A {set pick}
Depending on the layout of the input list, however, the [lmap]/[lindex] tactic is likely to outrun the above.

combining the elements of several lists

I want to take an arbitrary number of lists and return list of combinations of elements, but only combining one element from each list. All I have is sudo code because I don't know where to start.
I did find the solution to this program in the question of Combining the elements of 2 lists but I don't understand that scala code. I'm writing my program in Tcl but if you're able to help me feel free to write your answer in anything like java or python or pseudo code or whatever. Can anyone help me bring the following pseudo code to life?
for example:
# example: {a b} {c} {d e}
# returns: {a c d} {a c e} {b c d} {b c e}
# how?
# example: {a b} {c} {d e}
# iters: 0 0 0
# 0 0 1
# 1 0 0
# 1 0 1
#
#
# set done false
#
# while {!done} {
#
# list append combination_of_list due to iteration counts
#
# foreach list $lists {
# increment the correct count (specifically {0->1} {0->0} {0->1}) }
# reset the approapraite counts to 0
# }
#
# if all the counts in all the lists are at or above their max {
# set done true
# }
# }
Various Tcl solutions are discussed on this page: Cartesian product of a list of lists
Donal Fellows presents this variation at the end of the page:
proc product args {
set xs {{}}
foreach ys $args {
set result {}
foreach x $xs {
foreach y $ys {
lappend result [list {*}$x $y]
}
}
set xs $result
}
return $xs
}
Running that like this gives you the result:
% product {a b} {c} {d e}
{a c d} {a c e} {b c d} {b c e}
Documentation:
foreach,
lappend,
list,
proc,
return,
set,
{*} (syntax)
Here is a pseudocode describing an algorithm that generates all the combinations:
list_of_lists = {{a b}{c}{d e}}
def copy(list):
copy = {}
for element in list:
copy.add(element)
return copy;
def combine(list1, list2):
combinations = {}
for item1 in list1:
for item2 in list2:
combination = copy(item1)
combination.add(item2)
combinations.add(combination)
return combinations
results = {{}}
while list_of_lists.length>0:
results = combine(results, list_of_lists[0])
list_of_lists.remove(0)
It starts by combining {{}} with {a b c}
which produces {{a} {b}} which will be combined with {c} to generate {{a c} {b c}} on the next iteration etc.
Update:
Javascript version:
var list_of_lists = [["a", "b"],["c"],["d", "e"]];
function copy(list) {
var copy = [];
for (element of list) {
copy.push(element);
}
return copy;
}
function combine(list1, list2) {
var combinations = [];
for (let item1 of list1) {
var combination = copy(item1);
for (let item2 of list2){
combination.push(item2);
combinations.push(combination);
}
}
return combinations;
}
results = [[]]
while (list_of_lists.length>0) {
results = combine(results, list_of_lists[0]);
list_of_lists.splice(0,1);
}
console.log(results);

tcl formatting floating point with fixed precision

# the unit of period is picosecond
set period 625000.0
set period_sec [format %3.6g [expr $period * 1e-12]]
puts $period_sec
result: 6.25e-07
Is there a way to force tcl to get results like 625e-09
Assuming that you want to format it to the nearest exponent, you could use a proc which formats it like this:
proc fix_sci {n} {
# Not a sci-fmt number with negative exponent
if {![string match "*e-*" $n]} {return $n}
# The set of exponents
set a 9
set b 12
# Grab the number (I called it 'front') and the exponent (called 'exp')
regexp -- {(-?[0-9.]+)e-0*([0-9]+)} $n - front exp
# Check which set of exponent is closer to the exponent of the number
if {[expr {abs($exp-$a)}] < [expr {abs($exp-$b)}]} {
# If it's the first, get the difference and adjust 'front'
set dif [expr {$exp-$a}]
set front [expr {$front/(10.0**$dif)}]
set exp $a
} else {
# If it's the first, get the difference and adjust 'front'
set dif [expr {$exp-$b}]
set front [expr {$front/(10.0**$dif)}]
set exp $b
}
# Return the formatted numbers, front in max 3 digits and exponent in 2 digits
return [format %3ge-%.2d $front $exp]
}
Note that your original code returns 6.25e-007 (3 digits in the exponent).
If you need to change the rule or rounding the exponent, you will have to change the if part (i.e. [expr {abs($exp-$a)}] < [expr {abs($exp-$b)}]). For example $exp >= $a could be used to format if the exponent is 9 or below.
ideone demo of above code for 'closest' exponent.
For Tcl versions before 8.5, use pow(10.0,$dif) instead of 10.0**$dif
I do not think there is anything in the format command that will help you directly. However, if you consider a slight variation on the format code, then it may be a lot easier to get what you want (with a bit of string manipulation):
format %#3.6g $number
gives a number like: 6.25000e-007
This can be parsed more easily:
Extract the exponent
Determine the number of positions to shift the decimal point
Shift it and replace the exponent
It is not entirely straightforward, I am afraid, but it should be doable. Wiki page http://wiki.tcl.tk/5000 may give you some inspiration.