Mostrando las entradas con la etiqueta macros tnt. Mostrar todas las entradas
Mostrando las entradas con la etiqueta macros tnt. Mostrar todas las entradas

viernes, octubre 23, 2009

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.
var:
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 /;
stop
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
var:
i
;

set i 0 ;
loop =non 0 1
/* varias instrucciones */
if ('i' == 1)
endloop ;
else
setloop 0 ;
end ;
stop
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!

Referencias
[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

lunes, julio 13, 2009

Macros de TNT: Variables (1)


En el post anterior olvide algo muy importante. Se trata de los comentarios.

El lenguaje de macros de TNT permite el uso de comentarios en la misma forma que el tradicional C, es decir entre un /* y un */. Los comentarios no tienen ningún efecto sobre el script, pero son muy útiles para documentar el código.

/* Este es un comentario */

Es muy importante colocar comentarios, no solo para que otras personas puedan entender el código, sino para que uno mismo pueda entenderlo más rápidamente cuando vuelve a el (en especial, si fue escrito hace tiempo!).

Los comentarios son validos, una vez se a iniciado el modo de macros (usando macro=)

Por tradición, coloco este macro simple

macro =;
/* Mi primer macro de TNT */

quote Hola mundo!;
p/;

Ahora entrando en materia con el tema de este post...


Las variables son los objetos que el programa manipula con un propósito especificado por el usuario. Las variables guardan valores, y estos valores pueden ser modificados o leídos. Muchas veces, es el valor contenido en una variable lo que nos interesa. En otras ocasiones, el contenido de una variable sirve para controlar el flujo del programa. También pueden usarse variables para guardar valores dados por el usuario.

Al arrancar un macro, TNT define por omisión un número de variables (1000). Estas se pueden acceder usando un número, que inicia desde 0. Es posible cambiar el numero de variables usando macro* N K; donde N es el número de loops, y K el número de variables.

Variables generales

Usar los números de las variables puede ser cómodo en ,macros pequeños, pero al incrementar la complejidad de los macros, se hace más difícil el mantenimiento del código, por lo que es una buena práctica usar nombres para las variables. Las variables se pueden nombrar en cualquier parte del programa. Pero es una buena práctica nombrarlas justo después de iniciar el archivo con el macro (después del macro=). Para su declaración se utiliza la palabra clave var.

Hay dos formas de nombrar las variables, una es una forma explicita, que sirve, más que todo, para mantener la compatibilidad con macros anteriores.

var =
0 variable1
1 variable2
5 variable3
;

En este formato, usando var= se tiene que nombrar cada variable con el número interno (de TNT) que la identifica. La declaración termina con un punto y coma. El principal problema con esta forma, es que invita al uso intercambiable de números y nombres en las variables. Eso puede tener un efecto nosivo a la hora de hacer mantenimiento al código (por ejemplo, querer agregar más variables).

Una forma mucho más cómoda, y más recomendable (evita el uso de variables sin nombre), es declarar directamente los nombres, usando dos punto (:) en vez de igual

var:
variable 1
variable 2
variable 3
;

De aquí en adelante, utilizo esta forma, que me parece, mejora la legibilidad del código escrito.

Las variables en TNT pueden ser simples, es decir, que contienen un solo valor, o pueden ser arreglos, series de valores consecutivos. Los arreglos de TNT son estáticos, es decir que no pueden redimensionarse en tiempo de ejecución. Por eso es bueno declararlos solo cuando ya sabemos el tamaño que puede tener. Por ejemplo, luego de leer los datos, ya sabemos cuantos nodos puede tener un árbol.

Declarar un arreglo es muy simple, es como una variable normal, pero con las dimensiones entre corchetes ([]), si es una matriz multidimensional, los valores se separan con comas (,) de forma similar a como se declaran los arreglos en pascal.

var:
arreglo [25]
matriz [3, 4]
;


Variables en ciclos

En TNT las variables de los ciclos son independientes de las variables generales. Estas variables son manejadas por TNT y no directamente por el usuario. Al igual que las variables tradicionales, pueden nombrarse, o usar los números que vienen por omisión que comienzan desde 1, y se incrementan al irse anidando los ciclos.

Yo en general utilizo los números. Quizá sea una mejor práctica utilizar nombres puesto que de esa manera se independiza de el anidamiento del ciclo, y además, es la única forma de acceder variables de ciclos desde otro archivo.

La forma de declarar una variable en un ciclo es anteponiendo un igual (=) antes del nombre:

loop =ciclo 1 10


Variables de linea de comando

Al llamar a un macro, es posible asignarle valores iniciales usando la línea de comandos asociada al llamado del macro. Estas variables se conocen como "argumentos" o "parámetros". Por ejemplo, uno podría tener un macro que se llame dojac, y que reciba como parámetros el número de replicas, y un número de iteraciones en cada replica, así

dojac 1000 20 ;

En este caso, se reciben 1000 replicas y cada replica tiene 20 iteraciones.

En general, cuando uno distribuye un macro, si no se da ningún parámetro, se ofrece una especie de salida de ayuda, donde explica el objetivo y las condiciones necesarias para utilizar el macro de forma correcta.

La función argnumber retorna el número de argumentos usados al invocar el macro.

No se olviden de revisar las novedades de TNT, y por supuesto, consultar la wiki de TNT ;), hay varios scripts y otra documentación muy útil :D

miércoles, mayo 06, 2009

Macros de TNT: Intro


Una de las utilidades más poderosas de TNT es su lenguaje de macros. Este lenguaje permite acceder variables internas de TNT, manipular árboles y datos. Esto en conjunto con el poder de computo de TNT es una excelente combinación.

Infortunadamente, bien sea porque no hay un manual extenso, o porque aún son pocos los que han usado explicitamente macros en sus artículos, esta utilidad suele pasar más o menos desapercibida para los usuarios. En esta serie de posts quiero dar un poco de remedio a esta situación, y dar una especie de introducción a las muchas posibilidades que permite el uso de macros.

Parte de la idea nació a que una vez vi el libro de "R para filogenia" [1], y pues a que he estado en contacto con Santi Catalano, que ha estado trabajando en la wiki de TNT. Espero poder postear después parte de esto a la wiki de TNT, pero por ahora, como para ver como me siento escribiendolo, lo coloco primero en mi blog ;).

El estilo, es bien orientado a la programación--mi influencia más poderosa es Kernighan y Ritchie :)--pues la idea es que se le saque el máximo provecho al lenguaje!

Notación

El lenguaje de macros de TNT es un lenguaje interpretado, esto quiere decir que cada instrucción se ejecuta a medida que se va leyendo, por lo que es posible ir "escribiendo" el programa en tiempo real desde la linea de comando.

Esto puede ser muy útil, por ejemplo, para realizar cálculos matemáticos directamente en TNT.

Por ejemplo:
> macro = ;
Macro language is ON
> var: dest ;
> set dest 4 + 5 ;
> quote 'dest' ;
9
Al escribir esa secuencia uno puede tener una calculadora simple. Esto sirve para introducirnos a las cosas particulares del lenguaje.

Para activar los macros, se usa el comando macro = ; con macro - ; se desactivan los macros.

Al terminar cada instrucción se coloca un punto y coma (;). Aunque no es necesario, por claridad es aconsejable dejar un espacio antes del punto y coma.

La palabra clave var se utiliza para declarar las variables.

Con la palabra clave set se asigna un valor a una variable. En este ejemplo el valor de una suma. Set acepta las cuatro operaciones básicas, así como operaciones más complejas usando paréntesis.

El comando quote imprime en pantalla. En TNT, para acceder al valor guardado en las variables, se coloca el nombre de la variable entre comillas simples. Así en este ejemplo, se imprime lo que esta dentro de dest.

Es importante diferenciar entre el valor guardado en la variable y su nombre. Set asigna a una variable, por ello la variable no va dentro de comillas, pero si lo que es asignado es otra variable, entonces como es un valor, debe estar entre comillas:
set dest 'primero' * 'segundo' ;
Esta instrucción asigna a dest la multiplicación de los valores de primero y segundo.

Sin embargo, la aplicación más importante de los macros de TNT es que pueden guardarse en un archivo y ejecutarse como si se tratara de un comando del programa.

Si los macros se guardan con la extensión ".run", y son colocados en el mismo directorio de trabajo del programa (por ejemplo c:\bin\tnt) es posible llamarlo simplemente usando el nombre del archivo. Por ejemplo, en la instalación de TNT esta incluido stats.run, que calcula el indice de consistencia y retención de los árboles en memoria. Para ejecutarlo, simplemente se escribe
> stats ;
en la linea de comando, y el macro es ejecutado automáticamente.

Como todos los archivos de TNT se pueden acceder usando el comando proc, pero se pierde la lista de parámetros (si los hay) del macro. Por eso es mejor usar el commando run (o simplemente escribir el nombre). Como cualquier comando se puede acceder directamente en la lista de parámetros del programa.

Como ejercicios de esta introducción se puede probar las diferentes maneras de invocar los macros, así como acceder valores desde comandos. Por ejemplo scripts como este:
macro = ;
var:
numIts
numTrees
itTrees;

set numIts 100 ;
set itTrees 10 ;
set numTrees 'numIts' * 'itTrees' ;

rseed 0;
hold 'numTrees' ;
mult = replic 'numIts' hold 'itTrees' ;
nel * ;
p/ ;
Que no hacen nada que no se puede hacer directamente (y segura más fácil!), pero sirven para familiarizarse con el lenguaje ;).

Referencias
[1] Paradis, E. 2006. Analysis of phylogenetics and evolution with R. Springer