miércoles, noviembre 24, 2021

Usando índices de matrices en Octave

 Los elementos que conforma a una matriz, en Octave, tiene una posición determinada por renglón y por columna. Por ejemplo, para acceder a un elemento específico de un vector u, se usa un número entero:

>> u(5)

Por ejemplo, si el vector u está conformado por los elementos [6 7 8 9 10], al ejecutar lo anterior, se obtiene:

>> u=[6.1 7.2 8.3 9.4 10.5];
>> u(5)
ans =  10.5

También se puede usar un vector de enteros que se puede usar como índices para recuperar los valores de otro vector. Por ejemplo:

>> u=[6.1 7.2 8.3 9.4 10.5];
>> in = [1 2 3];
>> u(in)
ans =
   6.1000   7.2000   8.3000

Otra forma de recuperar un subconjunto continuo de elementos de un vector es usando el caracter ":" seguido de los números enteros que indican los índices donde comienza y termina el segmento a recuperar. Por ejemplo, para el mismo vector u:

>> u(1:3)
ans =
   6.1000   7.2000   8.3000

También se puede usar una variable como conjunto de índices. Por ejemplo, para el mismo vector u:

>> i=1:3
i =
   1   2   3
>> u(i)
ans =
   6.1000   7.2000   8.3000

Para una matriz de dos dimensiones, las reglas son equivalentes, con el agregado que es necesario usar índices para renglones y columnas.

Dada la siguiente matriz M:

>> M = [1.5 2.5 3.5; 4.5 5.5 6.5; 7.5 8.5 9.5]
M =
   1.5000   2.5000   3.5000
   4.5000   5.5000   6.5000
   7.5000   8.5000   9.5000

Para poder recuperar un elemento particular se especifica un par de números enteros que representan la posición por renglón y por columna. Por ejemplo, para recuperar el elemento del segundo renglón y tercer columna:

>> M(2,3)

ans =  6.5000

Y para recuperar una submatriz de M:

>> i=[1 2]
i =
   1   2
>> M(i,i)
ans =
   1.5000   2.5000
   4.5000   5.5000

Es muy importante notar que el primer elemento está en el índice 1, y que al usar los índices, éstos no deben referir a una posición que no forme parte de la matriz; por ejemplo, para la matriz M, una posición inválida por estar fuera de la matriz es M(4,4).


Etiquetas:

domingo, septiembre 12, 2021

Algunos generadores de matrices en Octave y Python

Existen algunas matrices básicas que resultan útiles al momento de comenzar a trabajar, ya sea por que permiten inicializar variables matriz o por que será útil en cálculos posteriores.

     Es posible recurrir a funciones en lenguaje M que nos permiten crear esas matrices y que están disponibles en Octave.

    Algunas de estás funciones son:

Función Resultado
zeros Una matriz de ceros
ones Una matriz de unos
rand Una matriz con elementos aleatorios de distribuición uniforme
randn Una matriz con elementos aleatorios de distribución normal
eye Una matriz identidad

    Para crear un vector renglón de ceros:

>> x = zeros(1,3)
x =

   0   0   0

y un vector columna de ceros:

>> y = zeros(3,1)
y =

   0
   0
   0

    Una matriz de ceros de 3x3:

>> M = zeros(3)
M =

   0   0   0
   0   0   0
   0   0   0

y una matriz rectangular de 3x2:

>> N = zeros(3,2)
N =

   0   0
   0   0
   0   0

    La misma forma de invocacion se puede emplear para la función ones. Así por ejemplo, para crear una matriz llena de 0.5 de dimensión 4x3, se puede usar la función ones y dividir entre 2:

>> M1 = ones(4,3)/2
M1 =

   0.50000   0.50000   0.50000
   0.50000   0.50000   0.50000
   0.50000   0.50000   0.50000
   0.50000   0.50000   0.50000

    O crear una matriz rectangular de 3x4 llena de unos:

>> M2 = ones(3,4)
M2 =

   1   1   1   1
   1   1   1   1
   1   1   1   1

    Y la forma de invocar es extensible al resto de las funciones.

    Por ejemplo, para crear un vector de elementos pseudoaleatorios:

>> u = rand(1,6)
u =

   0.82166   0.74930   0.79187   0.73530   0.73373   0.84726

    Una matriz de 2x2:

>> Mr = rand(2,2)
Mr =

   0.16396   0.75682
   0.77751   0.28670

    O crear una matriz identidad de 4x4:

>> I=eye(4)
I =

Diagonal Matrix

   1   0   0   0
   0   1   0   0
   0   0   1   0
   0   0   0   1

    En el caso particular de la función eye, si lo que se solicita es una matriz rectangular, coloca unos en la posición a(i,i), por ejemplo:

>> J=eye(2,4)
J =

Diagonal Matrix

   1   0   0   0
   0   1   0   0

    Existen funciones equivalente en Python con Numpy, que usa el mismo nombre y se comportan de forma similar.

    Para que estén disponibles es necesario importar el paquete y después invocarlas para obtener arreglos Numpy con contenido equivalente.

>>> import numpy as np

    Para crear un arreglo numpy de una dimensión de ceros en Python:

>>> x = np.zeros(3)

>>> print(x)

[0. 0. 0.]

    Para crear un arreglo numpy de ceros de 3x3:

>>> Mc = np.zeros([3,3])

>>> print(Mc)

[[0. 0. 0.]

 [0. 0. 0.]

 [0. 0. 0.]]

    Para crear una "matriz" rectangular de 4x2:

>>> Mc = np.zeros([4,2])

>>> print(Mc)

[[0. 0.]

 [0. 0.]

 [0. 0.]

 [0. 0.]]

    Existe también la función ones que se puede utilizar de igual forma que en Octave:

>>> M1 = np.ones([4,3])/2

>>> print(M1)

[[0.5 0.5 0.5]

 [0.5 0.5 0.5]

 [0.5 0.5 0.5]

 [0.5 0.5 0.5]]

    O una matriz rectangular inicializada con 1.5:

>>> M2 = np.ones([3,4])*1.5

>>> print(M2)

[[1.5 1.5 1.5 1.5]

 [1.5 1.5 1.5 1.5]

 [1.5 1.5 1.5 1.5]]

    La función rand en Python requiere un poco más de escritura, al usar la clase random. Por ejemplo, para crear una "matriz" de 2x2 de números pseudoaleatorios:

>>> u = np.random.rand(2,2)

>>> print(u)

[[0.05328813 0.79864914]

 [0.46865742 0.85856544]]

    O para crear una matriz de 2x4 con números pseudoaleatorios con una distribución normal:

>>> v = np.random.randn(2,4)

>>> print(v)

[[-1.45490502 -0.76736795  0.05142855  0.02027987]

 [-0.36772701  1.39209878 -0.58810718  1.22065564]]

    Y existen las funciones identity y eye para crear "matrices" identidad; en donde la función eye tiene un comportamiento semejante al de Octave, mientras que identity siempre devuelve una matriz cuadrada con unos en su diagonal principal.

    Por ejemplo para crear una "matriz" rectangular con unos en su elemento a(i,i):

>>> I1 = np.eye(4,3)

>>> print(I1)

[[1. 0. 0.]

 [0. 1. 0.]

 [0. 0. 1.]

 [0. 0. 0.]]


y para crear una "matriz" identidad de 3x3:

>>> I2 = np.identity(3)

>>> print(I2)

[[1. 0. 0.]

 [0. 1. 0.]

 [0. 0. 1.]]

    Finalmente es importante notar que los métodos zero y ones consumen una lista cuando se necesita crear un arreglo de dos o más dimensiones, mientras que random.rand, random.randn, identity y eye, se pasan escalares como argumentos para el tamaño en cada dimensión. 

Etiquetas: ,

sábado, septiembre 04, 2021

Un poco de matrices en Octave y Python

 Crear matrices en Octave es relativamente fácil, solo hay que delimitar los elementos que la conforman entre paréntesis cuadrados. Los elementos de un renglón se separan por espacios, y los renglones se separan utilizando punto y coma (;).

    Por ejemplo, para un vector de cinco elementos, en Octave se define de la siguiente manera:

x = [1.1 2.1 3.1 4.1 5.1]

    Y para una matriz de 3x4, se define:

A = [1.1 2.1 3.1 4.1; 5.1 6.1 7.1 8.1; 9.1 10.1 11.1 12.1]

mostrando lo siguiente:

A =

    1.1000    2.1000    3.1000    4.1000

    5.1000    6.1000    7.1000    8.1000

    9.1000   10.1000   11.1000   12.1000

    Se pueden concatenar vectores y matrices para crear matrices más grandes.

    Por ejemplo, dado el siguiente vector:

x = [1 2 3]

    Se puede construir la siguiente matriz a partir de concatenar x varias veces:

A = [x; x; x]

dando como resultado:

A =

   1   2   3

   1   2   3

   1   2   3

    Si definimos el vector "y" de la siguiente forma:

y = [1; 2; 3]

y se concatena el vector y varias veces para crear una matriz de la siguiente forma:

B = [y y y]

da como resultado:

B =

   1   1   1

   2   2   2

   3   3   3

 Podemos usar las matrices A y B para construir una matriz más grande.

C = [A 2*A; B [1 0 0; 0 1 0; 0 0 1]]

dando como resultado:

C =

   1   2   3   2   4   6

   1   2   3   2   4   6

   1   2   3   2   4   6

   1   1   1   1   0   0

   2   2   2   0   1   0

   3   3   3   0   0   1


    Para realizar la misma tarea en Python requiere más pasos, empezando por importar el paquete Numpy. 

import numpy as np

    Para definir el vector "x":

x = np.array([1.1, 2.1, 3.1, 4.1, 5.1])

    Y para definir la matriz ejemplo anterior en Python:

A = np.array([[1.1, 2.1, 3.1, 4.1], [5.1, 6.1, 7.1, 8.1], [9.1, 10.1, 11.1, 12.1]])

que devuelve:

array([[ 1.1,  2.1,  3.1,  4.1],

       [ 5.1,  6.1,  7.1,  8.1],

       [ 9.1, 10.1, 11.1, 12.1]])

    En Python para concatenar arreglos Numpy se usa el método concatenate, por lo que a partir del vector "x" definido de la siguiente forma:

x = np.array([[1, 2, 3]])

crear una matriz A de la siguiente forma:

A = np.concatenate((x, x, x))

da como resultado lo siguiente:

array([[1, 2, 3],

       [1, 2, 3],

       [1, 2, 3]])

    Para este ejemplo es importante notar que el vector x en realidad es una matriz Numpy de un único renglon y es importante porque en Python y Numpy no es lo mismo concatenar vectores que concatenar matrices.

Para el vector "y" utilizado previamente, definido de la siguiente forma:

y = np.array([[1],[2],[3]])

al concatenarlo de la siguiente forma:

B = np.concatenate((y,y,y), axis=1) 

se obtiene:

array([[1, 1, 1],

       [2, 2, 2],

       [3, 3, 3]])

En este ejemplo es importante notar que se usó el argumento axis, para indicar que se concatene a la derecha y no hacia abajo.

    Finalmente utilizando ambas matrices resultantes A y B al concatenarlas de la siguiente forma:

C1 = np.concatenate((A, 2*A), axis=1)

C2 = np.concatenate((B,[[1, 0, 0], [0, 1, 0], [0, 0, 1]]), axis = 1)

C = np.concatenate((C1, C2)) 

se obtiene:

 print(C)                                                               

[[1 2 3 2 4 6]

 [1 2 3 2 4 6]

 [1 2 3 2 4 6]

 [1 1 1 1 0 0]

 [2 2 2 0 1 0]

 [3 3 3 0 0 1]]

Obteniendo desde Python, resultados equivalentes a los vistos en Octave.

Etiquetas: ,

viernes, agosto 27, 2021

Creando gráficas básicas en Octave y su equivalente en Python

 En Octave es posible usar muchas de las sentencias disponibles en M, el lenguaje de script de Matlab.


Es por ello que para realizar una gráfica 2d en Octave, solo se requiere crear los vectores; de los términos independientes y dependientes.


Así, para crear la gráfica de la función seno en Octave:

>> x=0:0.1:2*pi;
>> y1=sin(x);
>> plot(x,y1);

 creando la siguiente gráfica:

Gráfica de la función seno en Octave


 Para crear la misma gráfica en Python su equivalente es:

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> x=np.arange(0,2*np.pi,0.1)
>>> y=np.sin(x)
>>> plt.plot(x,y)
[<matplotlib.lines.Line2D object at ...>]
>>> plt.show()

obteniendo la siguiente gráfica:

Gráfica de la función seno en Python3


Cómo se puede apreciar, en Octave es un poco más simple realizar la gráfica.

Para el caso de Python, es necesario tener objetos que se puedan tratar como arreglos, y es necesario un paquete adicional para realizar las gráficas. Por ello es necesario importar los paquete NumPy y Matplotlib.pyplot.


Numpy es el paquete que además, para este ejemplo, provee de la definición de pi, de la función seno y de una función que permite poblar el "vector" x; es decir np.pi, np.sin() y np.arange(inicio, fin, incremento).


Etiquetas: ,

miércoles, octubre 23, 2019

Tip. Depurando un script de Bash

En todo proceso de programación, contar con un método que permita realizar la depuración del código fuente es siempre una herramienta fundamental.

También resulta útil cuando se está trabajando con scripts de Bash de otras personas y no se tiene del todo claro que es lo que hace.

Bash proporciona opciones que permiten depurar scripts.

Una forma es, al momento de correr nuestro script:

$ bash -x ./script.s

Otra alternativa es incluir set -x dentro de script para que se obtenga una salida.

Para tener un archivo de salida numerado con el seguimiento de una ejecución del script, hay que agregar las siguientes líneas.

exec 5> archivo_salida_depuracion.txt
BASH_XTRACEFD="5"
PS4='$LINENO: '  # Permite numerar las líneas de salida.
set -x    # Comienza el proceso de depuración.


sábado, octubre 05, 2019

Graficándo tiempos con gnuplot

Del experimento de la entrada anterior tengo un archivo con los tiempos de pared del programa de interés, cuyos renglones tienen una forma semejante a la siguiente:

real 75m20.477s
user 75m20.464s
sys 0m0.300s

del cual solo me interesan los renglones con la etiqueta "real".

Necesito recuperar solo esos renglones y enumerarlos para hacer la gráfica que me interesa. Para ello con grep, cut y nl tendré la tabla que me interesa graficar.

  grep real tiempos.lfs.8e3.txt | cut -c6-20 | nl > archivo.data.graf.txt

El archivo resultante tiene renglones semejantes a esto:

    10 75m20.477s

que de esta forma se puede usar en gnuplot.

Desde gnuplot es necesario indicar que formato usar para interpretar los datos, en este caso que entienda que la segunda columna son datos de tiempo.

Cómo solo me interesa ver los datos graficados, uso solo dos sentencias:

gnuplot> set timefmt "%mm%ss"
gnuplot> plot "./archivo.data.graf.txt" using 1:2 t "Tiempos de pared"

Quedando la agráfica siguiente:

Por qué necesito crear métricas

En un cierto caso, necesito generar métricas de comportamiento de un programa en particular. Y el comando time me es muy conveniente.

Pero como siempre olvido como hacerlo, dejo esto por acá como futura referencia.

Para fines del experimento, necesito repetir la ejecución de un programa n veces, pero medir el tiempo de cada una de esas ejecuciones y adicionalmente, para después hacer un poco de estadísitca básica, guardar los tiempos de pared de cada ejecución.

Así, la ejecución completa queda:

for i in {1..10}
do
 echo "Incia"
 (time ./programa) >> salida.programa.txt 2>> tiempos.programa.txt
 echo "Termina"
done

Etiquetas:

lunes, mayo 24, 2010

Más de programacion paralela: OpenMP

OpenMP es un estandar creado por un grupo de fabricantes de software y hardware, con la intención de crear herramientas que sean útiles y de fácil uso, para la programación de máquinas de varias unidades de procesamiento con memoria compartida.

Es decir, herramientas que permitan a cualquier programar supercomputadoras clásicas (como la Cray). Y la idea es que sea posible programar de manera secuencial, para que cualquiera pueda desarrollar sus algoritmos sin tantas complicaciones y que a su vez, la porción paralela se ejecute en hilos, pero la decisión de cuantos hilos y de como sincronizarlos se le deja al compilador y no al programador. Que como se puede intuir, ayuda al programador.

Esto se logra mediante pragmas, directivas, llamadas a funciones y variables, que le indican al compilador que debe paralelizar en hilos.

Pero si es para programar supercomputadoras ¿qué sentido tiene hablar de ello cuando muy pocos pueden acceder a una de esas máquinas? Lo interesante, Open MP es independiente de plataforma (portable), y es posible usar OpenMP si se cuenta con una computadora con al menos dos núcleos. Es decir, gracias al avance de los procesadores, hoy cuanquiera con al menos dos núcleos, puede aprovechar el uso de OpenMP.

Y lo mejor aún, el compilador de GNU gcc soporta el más reciente estándar OpenMP 3.0; por lo que si además se tiene instalado alguna distribución GNU/Linux, ya se puede comenzar a jugar con OpenMP.

La página oficial de OpenMP:

http://openmp.org/wp/

Y ahí mismo hay mucho material para comenzar a trabajar, en donde se puede encontrar un tutorial de intel, que me ha parecido bastante bueno para comenzar a entender que es y como funciona OpenMP.

http://software.intel.com/en-us/articles/getting-started-with-openmp/

Etiquetas: