viernes, octubre 23, 2009

TNT macros: Variables (2)

In a previous entry I wrote about variable declaration under TNT macro language, in this post I show the most important aspect of variables: their access.

Variables can be accessed in two ways, for reading, in which the value stored on the variable is retrieved. The second access way is for writing, in which a value is assigned to a variable.

General variables

In TNT general variables (variables declared with var keyword) are accessed by its name inside single quotations (').
quote The number stored on variable is 'value' ;
hold 'number' ;
In this example, the number stored on value is printed and the number stored in number is used as the maximum tree hold. This is an important feature of the language: you can replace any command parameter by the value of variables. This gives an extraordinary flexibility to TNT's macros.

Sometimes, specially at linux version, it is necessary to use parenthesis to read successfully the variable:
hold ('numero') ;
To access arrays, the same format is used, with an index inside squared brackets ([]).
quote the value of the fourth element is  'vector [4]' ;
It can be a more complex (and useful) way for this example
quote the value of the 'i' element is 'vector ['i']' ;
Note that the variable i is also inside quotations. If you are somewhat familiar with some computer programming language, you note that quotations are a way to "dereference" of a variable.

This is an example for a multidimensional array
quote the value of the element 'i' , 'j' is 'mat ['i' , 'j']' ;
Using parenthesis (()) you can use math operations as index values. Here is an example with a two dimensional array, but that is exactly equal with any kind of array:
quote the value of the element 4, 'j' is 'mat [ (2 + 2 ) , 'j' ]' ;
Another option is the use of series
quote the value of the elements 3 to 8 is 'list [ 3 - 8 ]' ;
In this case, note that there are no parenthesis limiting the scope! If you put parenthesis, TNT interpret it as a mathematical operation.

To write values on general variables, the keword set is used with the name of the variable to assing, without quotations, and followed with the assigned value
set val 4 ;           /* Assigns 4 to val */
set res (3 + 4) ; /* Assigns a math operation */
set num 'val' ; /* Assigns the content of val to num */
Note that as is the value of the variable that is assigned to num, then val must be inside quotations. To assign arrays, it is possible to use the same format, just using one element at time.
set vec [4] 5 ;                 /* Assigns 5 to the 4th element of the array*/
set arreglo [ (2 + 3) ] 8 ; /* Assigns 8 to the 5th element of the array */
set arreglo ['i'] 10 ; /* Assigns 10 to the i-element of the array */
set arreglo [ ('j' + 'k') ] 7 ; /* Assigns 7 to the element j + k of the array */
Note that indexes must be dereferenced!

Many times, an operation to a variable is just a modification of its value, for example increase its value by one
set val 'val' + 1 ;
It is more clear and intuitive, modifying directly the variable without dereference it, this can be done using a C-like sintaxys
set val ++ ;              /* increase by 1 */
set arr [3] -- ; /* decrease the content of element 3 in 1 */
set mat [2, 4] += 'val' ; /* adds the value of val to the element 2, 4 of mat */
set num *= (3 + 'j') ; /* multiplies the content of num by (3 plus j)-times */
set arr [2] /= 3 ; /* divides the content of element 2 of arr by 3 */
set val -= 4 ; /* decreases the content of val in 4 */
In some cases, you want to store all array elements at the same time. This can be done with the keyword setarray. It is important that array dimensions coincide with the dimensions used in the declaration. The format of setarray is the name of the array followed by the name of the array an the elements.
lista [5, 4]
setarray 5, 4 lista 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 2 2 2 2 ;
In this example, the following matrix is assigned to a 5x4 array
0 1 1 1
1 0 1 1
1 1 1 0
2 2 2 2
The order of the elements follows the dimensions from left to right, then the first four elements assigned to the array are the array elements [0, 0], [0, 1], [0, 2] and [0, 3].

Variables in loops

Usually, loop variables are control variables, so the best option is not modifying them. So in principle, write the code as if loop variables are read-only. If a loop variable needs to be modified TNT can do it, but that usually shows a design problem, and it is not a good practice to make that modifications.

Loop variables can be accessed using using names or number. Is a good practice to use names to identify loop variables.

To read a loop variable the number or name of the cicle must be preceded by number character (#). For example to save a simple search of several k values using implied weights [1]
loop =kval 1 10
keep 0 ;
piwe = #kval ;
mult ;
tsave* resu#kval.tre ; save; tsave /;
As #kval is the name of the first cicle, then is possible to use #1, then to save the tree it would be
tsave* resu#1..tre ;
Note the double point after #1, that is because a point is interpreted by TNT as a decimal fraction, and assumes that the point is part of the name. In any case, it is better to use names ;). The numbering of loops is assigned in relation with its nestedness, starting with #1.

To modify a loop variable the keyword setloop is used, that change the most nested loop (i.e. the loop in which the instruction is used). As changing the value of loops distorts their sequence, you must be aware of infinite-loops. This is the reason that makes the change of loop variables unsafe and unrecommended. But, some times it is necessary a non-stop loop that finish only when a specified condition is meet. In that case, using endloop coupled with setloop can be very useful

set i 0 ;
loop =non 0 1
/* several instructions */
if ('i' == 1)
endloop ;
setloop 0 ;
end ;
It is assumed that somewhere inside the loop, the value of i is changed to 1.

Command line variables

Variables from command line are read-only. Then, we only can access their value. To access a command line variable it is used the percent sign (%).
set j %1 ;
Assigns j to the first parameter from the command line (by the way, %0 is the name of the macro). Trying to read more parameters than parameters actually provided, is an error and stops the execution. When you write a macro, keep in mind that command line parameters is the only way to communicate with the user, so it is necessary to do a good choice of reading order and default values.

As always, do not forgive to keep your TNT copy updated. And check the TNT wiki or join the TNT google group to deal with any question!

[1] Goloboff, P.A. 1993. Estimating character weights during tree search. Cladistics 9: 83-91. DOI: 10.1111/j.1096-0031.1993.tb00209.x

Previous post on TNT's macros

Macros de TNT: Variables (2)

En la pasada entrega (hace como mil años :P) escribí sobre como declarar las variables en los macros de TNT, en el post de hoy, voy a mostrar lo verdaderamente importante de las variables: su acceso.

Las variables se pueden acceder de dos maneras, una es la lectura, en donde el valor guardado en la variable es leído de alguna manera. La segunda forma de acceso es la escritura, en donde se asigna un valor a una variable.

Variables generales

En TNT para leer a las variables generales (las declaradas con la palabra clave var) se utiliza el nombre de la variable entre comillas simples (').
quote El valor de la variable es 'valor' ;
hold 'numero' ;
En este ejemplo, se imprime el número contenido en la variable valor. Y se retienen solo la cantidad de árboles que indica numero. Esta cualidad es muy importante, porque podemos reemplazar los parámetros de cualquier comando de TNT por variables, lo que le da una flexibilidad enorme a los macros.

A veces, en especial en la versión de linux, es necesario usar un paréntesis para que se lea correctamente la variable:
hold ('numero') ;
Para acceder a los arreglos, se utiliza el mismo formato, con el indice entre paréntesis cuadrados ([])
quote valor del elemento 4 del arreglo es 'arreglo [4]' ;
Es posible ser un poco más complejo es este caso
quote valor del elemento 'i' del arreglo es 'arreglo ['i']' ;
En este caso, se muestra el valor del elemento i dentro del arreglo. Véase que i va dentro de comillas. Para los que estén familiarizados con los lenguajes de programación pueden ver que al acceder a el valor de una variables este se "dereferencia" con las comillas.

Este es el ejemplo con arreglos multidimencionales
quote valor del elemento 'i', 'j' es 'dosd ['i', 'j' ]' ;
El indice del arreglo puede ser una operación entre paréntesis típicos (()), el ejemplo va con un array de dos dimensiones, pero es igualmente valido para arreglos de cualquier dimensión.
quote valor del elemento 4, 'j' es 'dosd [ (2 + 2), 'j' ] ;
Otra posibilidad muy útil en arreglos es el uso se series
quote el valor de los elementos 3 al 8 son 'lista [ 3 - 8 ];
En este caso es importante ¡no colocar los valores entre paréntesis! De lo contrario TNT interpreta una operación matemática.

Para escribir variables en TNT se utiliza la palabra clave set, usando el nombre de la variable a asignar, sin comillas, y seguida del valor asignado.
set valor 4 ;                   /* Asigna 4 a valor */
set resultado (3 + 4) ; /* Asigna una operación */
set numero 'valor' ; /* Asigna el contenido de valor a numero */
Véase que cuando lo que se asigna es el valor dentro de una variable, esta debe ir entre comillas. Para asignar arreglos se puede utilizar el mismo formato, asignando un elemento a la vez
set arreglo [4] 5 ;             /* Asigna 5 al elemento 4 del arreglo */
set arreglo [ (2 + 3) ] 8 ; /* Asigna 8 al elemento 5 del arreglo */
set arreglo ['i'] 10 ; /* Asigna 10 al i-elemento de arreglo */
set arreglo [ ('j' + 'k') ] 7 ; /* Asigna 7 al elemento j + k del arreglo */
Es importante anotar que los indices del arreglo deben dereferenciarse!

Muchas veces, las operaciones sobre las variables consisten en modificar su valor, por ejemplo, incrementar su valor en 1.
set valor 'valor' + 1 ;
Es mucho más claro e intuitivo, modificar directamente la variable sin dereferenciarla, esto se logra mediante operadores que usan una sintaxis como la de C en esos casos.
set valor ++ ;                 /* incrementa valor en 1 */
set arreglo [3] -- ; /* disminuye el contenido del elemento 3 de arreglo en 1 */
set matriz [2, 4] += 'valor' ; /* adiciona el contenido de valor al elemento 2, 4 de matriz */
set numero *= (3 + 'j') ; /* multiplica el contenido de numero por 3 más j */
set arreglo [2] /= 3 ; /* divide el contenido de arreglo en 3 */
set valor -= 4 ; /* disminuye el contenido de valor en 4 */
Para los arreglos puede ser más útil asignar a la vez todos los elementos, para ello se utiliza setarray. Es muy importante que las dimensiones del arreglo coincidan con las de su declaración. El formato de set array es las dimensiones del arreglo, seguido por el nombre del arreglo, seguido por los elementos.
lista [5, 4]

setarray 5, 4 lista 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 2 2 2 2 ;
En este ejemplo se creo un array de 5 x 4 que tiene la siguiente matriz
0 1 1 1
1 0 1 1
1 1 0 1
1 1 1 0
2 2 2 2
El orden de los elementos es siguiendo el orden de las dimensiones de izquierda a derecha, así en el ejemplo los primeros 4 elementos son los elementos [0, 0], [0, 1], [0, 2], y [0, 3] del arreglo.

Variables en ciclos

En general, las variables de los ciclos son de control, y por ello, lo mejor es no modificarlas. Así en principio, las variables de los ciclos son de solo lectura. Si se necesita modificar el valor de la variable de un ciclo, TNT también puede hacerlo, aunque es importante recalcar que las modificaciones de las variables en un ciclo, suelen reflejar algún problema de diseño, y no es una buena practica recurrir a esas modificaciones.

Las variables de ciclos se pueden leer usando nombres o números. Es una buena practica el utilizar nombres para identificar las variables de los ciclos.

Para leer una variable de un ciclo se utiliza el número del ciclo antecedido por el carácter numeral (#). Por ejemplo, para recorrer varios valores de k usando pesos implicados [1]
loop =kval 1 10
keep 0 ;
piwe = #kval ;
mult ;
tsave* resu#kval.tre ; save; tsave /;
El #kval se refiere al primer ciclo, también podría utlizarse #1, en ese caso, para guardar el arbol debería usarse
tsave* resu#1..tre
Véase que al guardar el nombre del árbol se usa un doble punto despues del número. Eso es porque con un solo punto, TNT interpreta que forma parte del número (es decir, que se trata de un real con decimales). De todas formas, mejor utilizar el nombre ;). Los números de los ciclos se asignan de acuerdo a su anidamiento (empezando desde #1).

Para modificar el valor de una variable de un ciclo se utiliza la palabra clave setloop, que modifica el ciclo más anidado en el que se encuentra la instrucción. Dado que el cambiar el valor de los ciclos distorsiona la secuencia del ciclo, hay que tener cuidado con los ciclos infinitos. Es por eso que su uso no es recomendable. Sin embargo, a veces necesitamos de un ciclo que corra indefinidamente hasta que se cumpla alguna condición. En ese caso, utilizar setloop junto a endloop puede ser muy útil. Por ejemplo

set i 0 ;
loop =non 0 1
/* varias instrucciones */
if ('i' == 1)
endloop ;
setloop 0 ;
end ;
Aquí se asume que en alguna condición dentro del ciclo el valor de i se cambia a 1, lo que permite que el ciclo finalice.

Variables de linea de comando

Las variables que vienen desde la linea de comando son de solo lectura. Así solo podemos accesar su valor. Para acceder al valor de una variable de linea de comando se usa el signo (%)
set i %1 ;
asigna a i el valor del primer parámetro pasado por la linea de comando (por interés %0 es el nombre del macro). Tratar de leer más parámetros de los que se pasaron por linea de comando, es un error, y detiene la ejecución. A la hora de escribir un macro, hay que tener en cuenta que son estos parámetros de la línea de comando la única manera de comunicarse con el usuario, así que hay que hacer una buena elección de su orden, y de los valores por omisión.

Como siempre, no se olviden de chequear que su versión de TNT esta actualizada, así mismo no duden en consultar la wiki de TNT o suscribirse al grupo google de TNT!

[1] Goloboff, P.A. 1993. Estimating character weights during tree search. Cladistics 9: 83-91. DOI: 10.1111/j.1096-0031.1993.tb00209.x

Post anteriores en macros de TNT

lunes, octubre 19, 2009

The behemot! for free! / El behemot gratuito!

Santí noted that the "behemot"'s paper [1] is now available for free from Wiley/Blackwell web-page, this is the link:

Or you can jump directly to the paper abstract and download the pdf:

If you want to look the results, Pablo post a quick guide to manage the trees and extract info from them. If you want to check you favorite group, or just play for a moment, there are no excuses ;)!

And the best of it, as they are macros, you can use for your own trees! and don't forget to check out the TNT wiki!

Santí me hizo notar que el paper donde el "behemot" vio la luz [1] se encuentra disponible de manera gratuita en el sitio de blackwell. El enlace es este:

O pueden ir directamente a la pagina del artículo y descargar el pdf:

Para quienes quieran jugar con los resultados, Pablo publicó una guía rápida para manejar los árboles y poder extraer info de ellos. Así que si tienen curiosidad por ver como quedo el grupo que ustedes trabajan, o simplemente quieren pasar un rato, ya no hay excusas ;)

Y lo mejor de todo, como son macros, se pueden usar en sus propios resultados :D! No se olviden de consultar la wiki de TNT ;)

[1] Goloboff, P.A. et al. 2009. Phylogenetic analysis of 73 060 taxa corroborates major eukaryotic groups. Cladistics 25: 211-230. DOI: 10.1111/j.1096-0031.2009.00255.x