Você está na página 1de 51

1 Introducción

1.1 ¿Qué es Octave?


Octave es un software para cálculo numérico, que permite ejecutar algoritmos
de manera muy práctica sin necesidad de declarar variables, manejar estructuras
de datos complejas, apuntadores, etc. Permite manipular datos y graficarlos.
En este curso usaremos Octave pues es muy sencillo de aprender y ejecutar,
es de naturaleza numérica, nos permite trabajar con matrices de manera nativa
y tiene licencia de uso libre (GNU).

1.2 Lo que debes aprender de Octave para este curso es:


1. Hacer operaciones con vectores y matrices
2. Procesar datos en un archivo de texto (lectura/escritura)
3. Graficación de datos y creación de figuras
4. Creación y uso de scripts y funciones
5. Escritura de programas sencillos

1.3 Acerca de estas notas:


Estas notas resumen conceptos básicos para empezar en Octave. Es necesario
que complementes la información con recursos en lı́nea (e.g., foros, páginas de
ayuda manuales) para lograr dominar el lenguaje y optimizar tu código poco a
poco.

2 Usando Octave
Octave se encuentra disponible para sistemas UNIX (Linux) y MS Windows.
También se conoce como Octave al lenguaje de alto nivel en el que se codifica.
Se trata de un lenguaje interpretado que posee muchas similitudes con Matlab,
con el fin de hacerlo compatible (*).
Cuando se inicia Octave, se tiene una leyenda descriptiva seguida de la lı́nea
de comandos (prompt).
$ octave
GNU Octave, version 3.2.4
Copyright (C) 2009 John W. Eaton and others.
This is free software; see the source code for copying conditions.
There is ABSOLUTELY NO WARRANTY; not even for MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. For details, type ‘warranty’.
Octave was configured for "x86_64-pc-linux-gnu".
Additional information about Octave is available at http://www.octave.org.
For more information, visit http://www.octave.org/help-wanted.html
Report bugs to <bug@octave.org> (but first, please read...

1
For information about changes from previous versions, type ‘news’.

octave:1>

2.1 Matrices
La estructura de datos básica en Octave es la matriz, de esta forma, los escalares
son vistos como matrices de tamaño 1x1.

octave:1> 2

ans = 2

octave:2> 235

ans = 235

Los vectores son matrices de tamaño nx1 o 1xn y se introducen de la siguiente


forma:

octave:3> a=[1 2 3 4 5 6 7 8 9]
a =
1 2 3 4 5 6 7 8 9

octave:4> b=[1;2;3;4;5;6;7;8;9]
b =
1
2
3
4
5
6
7
8
9

octave:5> d=[1 2 3;4 5 6]


d =
1 2 3
4 5 6

octave:38> a=[1 2 3]
a =
1 2 3

2
Se pueden efectuar las operaciones tı́picas sobre matrices, por ejemplo:

Si se quiere obtener la transpuesta de una matriz:


octave:6> d’
ans =

1 4
2 5
3 6

Asignar el contenido de una matriz a otra:


octave:7> c=d’
c =

1 4
2 5
3 6

Concatenación de matrices

octave:5> d=[1 2 3;4 5 6]


d =
1 2 3
4 5 6

octave:38> a=[1 2 3]
a =
1 2 3

octave:39> s=[d;a]
s =
1 2 3
4 5 6
1 2 3

Suma de matrices y multiplicación por un escalar.

octave:13> c=a+b’
c =

2 4 6 8 10 12 14 16 18

3
octave:14> c=2*c
c =

4 8 12 16 20 24 28 32 36

Existen casos en el que, sin embargo, las operaciones no son las usuales
entre matrices y es cuando una de las matrices es de orden 1x1, es decir, un
escalar. En el caso de la suma, cuando se suma una matriz a un escalar, a
cada elemento de la matriz se le suma dicho escalar, en la suma normal, las
dimensiones de la matriz deben de coincidir para poder realizar esta suma. En
el caso de multiplicación, cuando una variable es un escalar, entonces se realiza
la multiplicación usual entre un escalar y una matriz, es decir, el escalar por cada
entrada, ignorándose la convención de que el número de columnas de la primer
matriz debe de coincidir con el número de renglones de la segunda matriz. Es
posible hacer otras operaciones útiles como multiplicación entrada por entrada,
asegurándose desde luego que las matrices a operar sean de la misma dimensión
agregando ’.’ antes del operador de multiplicación ’*’.

octave:1> a = [1 2 3]

a =

1 2 3

octave:2> b = [4 5 6]

b =

4 5 6

octave:3> a.*b
ans =

4 10 18

El operador . es también compatible con los operadores de división / y ex-


ponenciación ^, la sintaxis es igual que en el caso de multiplicación. En el caso
de la exponenciación el exponente es un escalar y cada entrada de la matriz es
elevada a dicho exponente.

Para desplegar el valor de una variable, simplemente se teclea el nombre de


la variable, p.ej.

octave:15> c
c =

4
4 8 12 16 20 24 28 32 36

Si no se desea desplegar el valor de las expresiones que se teclean, se pone


un punto y coma al final:

octave:16> a=[1 2 3; 1 2 3; 1 2 3];


octave:17>

Existen operaciones especiales que nos permiten resolver sistemas de ecua-


ciones de forma eficiente.
Para resolver sistemas de ecuaciones de la forma

Tx = a

se utiliza el operador \ haciendo equivalente escribir


T \ x
1 1
con T a. (T indica la inversa de la matriz T )

octave:7> T = [4 5 6;1 8 9; 3 5 -1]


T =

4 5 6
1 8 9
3 5 -1
octave:9> a = [1;2;3]
a =

1
2
3

octave:10> T\a
ans =

-0.043011
0.569892
-0.279570

octave:11> inv(T)*a
ans =

-0.043011
0.569892
-0.279570

5
Sin embargo usar el operador diagonal es computacionalmente más eficiente
que calcular la inversa de T y multiplicar con a debido a que al usar el operador
diagonal se realiza eliminación gaussiana para resolver el sistema de ecuaciones,
con la consecuente mejora numérica, mientras que en la otra forma se calcula
la inversa y luego se realiza un producto de matrices.

Si el sistema lo escribimos en la forma

xt T = at

se puede usar el operador / para realizar la eliminación gaussiana.

octave:12> T = T’
T =

4 1 3
5 8 5
6 9 -1

octave:13> a=a’
a =

1 2 3

octave:14> a/T
ans =

-0.043011 0.569892 -0.279570

Obteniéndose el mismo resultado que en el caso anterior, salvo que ahora las
soluciones están en un vector renglón.

2.2 Acceso a elementos


NOTA: Los ı́ndices de vectores y matrices comienzan en 1, no en cero como en
otros lenguajes. La última posición de un arreglo utiliza el sı́mbolo especial end.

Para tener acceso a una o varias de las entradas de una matriz, se utilizan
ı́ndices y paréntesis. p.ej.

Para acceder a un elemento de la matriz.


octave:20> a
a =

5 8 6

6
1 7 3
8 2 4

octave:21> a(3,2)
ans = 2
octave:22> a(3,end)
ans = 4

Acceder a varios elementos, en este caso se obtiene una submatriz de la


matriz original, en el ejemplo se desea acceder a los elementos en los renglones
1 y 2 que están en la columna 3 en la matriz a.

octave:23> a([1,2],3)
ans =

6
3

En el siguiente ejemplo deseamos los elementos de los renglones 1 y 2 que


están en las columnas 2 y 3 de la matriz a.

octave:24> a([1,2],[2,3])
ans =

8 6
7 3

En un vector (matriz de 1xn o nx1) basta con indicar un solo ı́ndice, aunque
tampoco es incorrecto escribir ambos ı́ndices.
octave:1> v = [1 2 3]
v =

1 2 3

octave:2> v(1) = 5
v =

5 2 3

octave:3> v(1,end) = 200


v =

5 2 200

7
La expresión x1 : x2 devuelve un vector renglón (fila) de enteros entre x1 y
x2 .

octave:1> v = 3:6
v =

3 4 5 6

Esta forma es particularmente útil cuando se desea acceder a varios elemen-


tos consecutivos de una matriz o vector.

octave:6> v1 = [1 2 3 4 5 6]
v1 =

1 2 3 4 5 6

octave:7> v1(2:5) = 0.5


v1 =

1.00000 0.50000 0.50000 0.50000 0.50000 6.00000

Usando una sintaxis similar podemos crear vectores donde cada elemento
corresponde a una sucesión aritmética, por ejemplo:

octave:11> x = 0:0.2:1
x =

0.00000 0.20000 0.40000 0.60000 0.80000 1.00000

En el caso anterior se comienza con 0, y el siguiente elemento del vector es el


elemento anterior más 0.2, la sucesión termina cuando se ha rebasado el número
1. En este caso el lı́mite superior fue alcanzado pero podrı́a no darse el caso,
por ejemplo:

octave:12> x = 1:0.3:2
x =

1.0000 1.3000 1.6000 1.9000

También se pueden dar incrementos negativos.

octave:13> 0:-0.2:-1
ans =

8
0.00000 -0.20000 -0.40000 -0.60000 -0.80000 -1.00000

Sin embargo, si deseamos dividir el intervalo en un número conocido de


puntos igualmente espaciados usamos la función linspace(·, ·, ·) que toma 3
argumentos, el primero y segundo correspondientes al primer y último elemento
del vector, el último parámetro corresponde al número de elementos deseados
en el vector, por ejemplo:

octave:14> linspace(1,2,5)
ans =

1.0000 1.2500 1.5000 1.7500 2.0000

Ejercicio 1 Hacer que se muestren los elementos de la matriz x en orden in-


verso por renglón y por columna, es decir, en una sola orden queremos que tome
la matriz:
octave:32> x = [1 2 3;4 5 6;7 8 9]
x =

1 2 3
4 5 6
7 8 9

y nos devuelva como respuesta:


ans =

9 8 7
6 5 4
3 2 1

Otro operador útil es el operador : este operador es usado para indicar que
se desea acceder a todos los elementos de un renglón o columna de una matriz.

octave:17> a = [1 2 3;4 5 6;7 8 9]


a =

1 2 3
4 5 6
7 8 9

octave:18> a(1,:)

9
ans =

1 2 3

octave:19> a(:,2)
ans =

2
5
8
Algunas veces es deseable eliminar por alguna razón el contenido de un
renglón o columna de una matriz, o simplemente un elemento de un vector, esto
se puede hacer usando la siguiente sintaxis:

octave:20> a = [1 2 3;4 5 6;7 8 9]


a =

1 2 3
4 5 6
7 8 9

octave:21> a(2,:) = []
a =

1 2 3
7 8 9

octave:22> a(:,1) = []
a =

2 3
8 9

Cabe notar que a diferencia de los lenguajes de bajo nivel como C, en Octave
no es necesario reservar memoria declarando las variables o su tipo, Octave real-
iza todo el proceso de asignación y liberación de memoria, como en cada ejemplo
donde hemos creado o redefinido los tamaños de las matrices.

Hasta ahora se han creado variables de forma intuitiva, las reglas para nom-
brar las variables son como en casi cualquier lenguaje de programación:

1. Deben de comenzar con una letra.

10
2. Pueden contener números.
3. Hay sensibilidad a letras mayúsculas y minúsculas.
4. No es posible asignarle como nombre de variable una palabra reservada
por el sistema, por ejemplo Sin, Cos, sqrt, entre otras.

Existen algunas variables predefinidas por el sistema, por ejemplo:

ans Esta variable contiene el resultado de la última sentencia que no ha sido


asignada a una variable.
pi Es el valor del número ⇡, no es lo mismo que teclear PI
52
eps Representa la diferencia más pequeña entre dos números. Es igual a 2 ,
que es aproximadamente 2.2204x10 16 .
i Se define como la raı́z cuadrada de 1.
j Es equivalente a i.

NaN Es la abreviatura de Not a Number. Se utiliza cuando Octave no puede


encontrar un valor numérico de la expresión calculada, por ejemplo en la
operación 0/0.
inf Representa el infinito.

2.3 Matrices especiales


Algunas matrices son muy frecuentemente usadas, las más usadas son las sigu-
ientes 3: zeros(m,n) que nos crea una matriz de m renglones y n columnas con
elementos iguales a cero, ones(m,n) que nos crea una matriz de m renglones
y n columnas con elementos iguales a uno, y la función eye(n) que crea una
matriz identidad de nxn.

octave:135> A = zeros(3,2)
A =

0 0
0 0
0 0

octave:136> B = ones(4,5)
B =

1 1 1 1 1
1 1 1 1 1

11
1 1 1 1 1
1 1 1 1 1

octave:137> C = eye(3)
C =

Diagonal Matrix

1 0 0
0 1 0
0 0 1
Aunque existen otras matrices especiales, por ejemplo magic(n) que genera una
matriz cuyos elementos forman un cubo mágico de tamaño nxn, pascal(n) que
forma una matriz que vista desde la esquina superior izquierda y en dirección a
la esquina inferior derecha contiene los elementos del triángulo de Pascal, entre
otras. Aunque pareciera que son en cierta forma funciones inútiles, y lo cierto
es que rara vez se van a llegar a usar, un uso por ejemplo de la matriz de pascal
es en la generación de números aleatorios de Faure.

Si v es un vector, el comando diag(v) devuelve una matriz con los elementos


de v en la diagonal. Mientras que diag(M) devuelve un vector con los elementos
de la diagonal de M.
octave:35> v = [5 30 20]
v =

5 30 20

octave:41> M = diag(v)
M =

Diagonal Matrix

5 0 0
0 30 0
0 0 20

octave:42> M(3,1) = 40
M =

5 0 0
0 30 0
40 0 20

octave:43> M(1:2,1:2) = [1 2;3 4]


M =

12
1 2 0
3 4 0
40 0 20

octave:44> v = diag(M)
v =

1
4
20

2.4 Funciones predefinidas para trabajar con matrices y


vectores
Algunas veces no se tiene control sobre las caracterı́sticas de las variables usadas,
por ejemplo si estas fueron extraı́das de un archivo de texto plano (.txt por
ejemplo), hoja de cálculo, etc. Y sin embargo es necesario conocer algunos de
sus datos, por ejemplo tipo de dato, número de elementos. Para esto utilizamos
las funciones:
who Muestra una lista de todas las variables almacenadas en memoria
whos Muestra una lista de todas las variables en memoria y su tamaño junto
con su clase y longitud.

octave:114> x = [1 2 3 4];
octave:115> y=[1:5];
octave:116> z = [eye(3) ones(3,1) zeros(3,2)];
octave:117> whos
Variables in the current scope:

Attr Name Size Bytes Class


==== ==== ==== ===== =====
x 1x4 32 double
y 1x5 40 double
z 3x6 144 double

Total is 27 elements using 216 bytes

octave:118> who
Variables in the current scope:

x y z

13
Sin embargo, si solo se desea conocer información de una variable en especı́fico
se pueden utilizar los comandos:

1. length(A): Devuelve el número de elementos del vector A, en el caso de


una matriz, devuelve el máximo entre el número de renglones y el número
de columnas.
2. size(A): Devuelve un vector fila [m, n] que representa el número de ren-
glones y número de columnas de la matriz A respectivamente.

octave:127> x = [1 2 3 4];
octave:128> z = [eye(3) ones(3,1) zeros(3,2)];
octave:129> length(x)
ans = 4
octave:130> size(z)
ans =

3 6

Es importante tener en cuenta las dimensiones de las matrices en todo mo-


mento, ası́ como saber que se trata de una matriz o un vector. Para ello con-
sidérese el siguiente ejemplo:

octave:131> x = magic(4)
x =

16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1

octave:132> x(10) = 100


x =

16 2 3 13
5 11 100 8
9 7 6 12
4 14 15 1

Aunque se trata de una matriz y no se ha especificado apropiadamente el


elemento con el cual se trabajar, Octave no ha enviado un mensaje de error.
Cuando solo se envı́a un valor como entrada para localizar un elemento en una
matriz se hace una correspondencia entre el par ordenado que determina cada
elemento en la matriz con una enumeración de los elementos de la misma, dicha
enumeración comienza en el elemento x(1, 1) y se va moviendo primero en verti-
cal y luego en horizontal. De esta forma el elemento correspondiente al x(2) es

14
x(2, 1), y en particular el elemento x(10) para el ejemplo corresponde con el el-
emento x(2, 3). Usando esta correspondencia es que trabaja la siguiente función:

reshape(A,m,n): Convierte una matriz A de dimensiones rxs en una matriz


de dimensiones mxn, se debe de cumplir que el producto de r, s sea igual al
producto de m, n. Es decir, redimensiona la matriz por otra que contiene el
mismo número de elementos pero diferentes dimensiones.
octave:133> A = [5 1 6;8 0 2]
A =

5 1 6
8 0 2

octave:134> reshape(A,3,2)
ans =

5 0
8 6
1 2
En general Octave posee un gran número de funciones que trabajan con
arreglos y matrices y, de momento, solo se mostrarán algunas de ellas.

sum(A)

Si A es un vector, calcula la suma de todos sus elementos.

octave:2> A = 1:6
A =

1 2 3 4 5 6

octave:3> sum(A)
ans = 21
Si A es una matriz entonces devuelve la suma de los elementos por columna

octave:4> A = magic(5)
A =

17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3

15
11 18 25 2 9

octave:5> sum(A)
ans =

65 65 65 65 65

Si se necesita la suma de los elementos por renglón se puede usar la transpuesta


de la matriz y aplicar la función sum(·), pero la función sum(·) también puede
trabajar con un segundo parámetro para lograr el mismo resultado. La sintaxis
es la siguiente:

octave:6> sum(A,2)
ans =

65
65
65
65
65

sort(A)

La función sort(A) organiza los elementos de un vector en orden creciente


como opción por default
octave:10> x = randperm(8)
x =

4 3 6 5 7 2 1 8

octave:11> sort(x)
ans =

1 2 3 4 5 6 7 8
Pero si lo que se desea es obtener los elementos ordenados en forma decre-
ciente se puede usar la palabra ’descend’ como segundo argumento.

octave:12> sort(x,’descend’)
ans =

8 7 6 5 4 3 2 1

16
La función sort(A) puede devolver dos valores de salida, cuando se hace una
asignación a una variable(o a ninguna como en el caso de los ejemplos) solo se
devuelve un valor que es el vector ordenado, el segundo valor de salida de esta
función es una lista del orden en que se encontraba cada entrada en el vector
original. La sintaxis es:

octave:13> [y,indices] = sort(x)


y =

1 2 3 4 5 6 7 8

indices =

7 6 2 1 4 3 5 8

que indicarı́a que el 1 estaba en la posición 7 en el vector x, el 2 en la posición


6 y ası́ sucesivamente. Si la función sort(A) es aplicada a una matriz sucede un
comportamiento similar a la función sum(A) y realiza el ordenado por columna
o por renglón agregando 2 como segundo parámetro.
octave:14> A = magic(5)
A =

17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9

octave:15> sort(A)
ans =

4 5 1 2 3
10 6 7 8 9
11 12 13 14 15
17 18 19 20 16
23 24 25 21 22

octave:16> sort(A,2)
ans =

1 8 15 17 24
5 7 14 16 23
4 6 13 20 22
3 10 12 19 21
2 9 11 18 25

17
octave:17> [y,indice] = sort(A)
y =

4 5 1 2 3
10 6 7 8 9
11 12 13 14 15
17 18 19 20 16
23 24 25 21 22

indice =

3 2 1 5 4
4 3 2 1 5
5 4 3 2 1
1 5 4 3 2
2 1 5 4 3

Ejercicio 2 La matriz X contiene por renglón vectores en R2 y el vector Y las


evaluaciones de esos vectores en cierta función F : R2 :! R, deseamos ordenar
los renglones de X en orden decreciente con respecto a sus evaluaciones en la
función F . Es decir tomar:
X =

0.92398 0.90550
0.85098 0.44459
0.40337 0.51532
0.16965 0.63489
0.63003 0.63630

Y =

1.2199
1.5620
1.7899
1.7908
1.6123

y devolver:

X2 =

0.16965 0.63489
0.40337 0.51532

18
0.63003 0.63630
0.85098 0.44459
0.92398 0.90550

Y2 =

1.7908
1.7899
1.6123
1.5620
1.2199

Usando la función sort(A) y sus parámetros de salida. La solución está dada


en dos renglones.

mean(A) Calcula el promedio de los valores del vector A, si A es una matrı́z en-
tonces calculará el promedio por columna, obteniéndose un vector renglón con
cada promedio. Al igual que las funciones sort(A) acepta un 2 como segundo
parámetro con lo que calcula el promedio por renglón en vez de por columna.

octave:6> X = magic(5)
X =

17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9

octave:7> mean(X)
ans =

13 13 13 13 13

octave:8> mean(X,2)
ans =

13
13
13
13
13

19
octave:9> mean(X(1,:))
ans = 13

Ası́ como las anteriores existen muchas funciones, explicar cada una de ellas
serı́a algo tardado, Octave nos puede dar información detallada de las funciones
siempre que conozcamos el nombre de la misma, basta con teclear en la terminal
la palabra help seguida de un espacio y el nombre de la función de la cual
queremos información.
octave:2> help max
’max’ is a function from the file /usr/lib/i386-linux-gnu/octave/
3.6.4/oct/i686-pc-linux-gnu/max.oct

-- Loadable Function: max (X)


-- Loadable Function: max (X, Y)
-- Loadable Function: max (X, [], DIM)
-- Loadable Function: max (X, Y, DIM)
-- Loadable Function: [W, IW] = max (X)
For a vector argument, return the maximum value. For a
matrix argument, return the maximum value from each column,
as a row vector, or over the dimension DIM if defined, in
which case Y should be set to the empty matrix (it’s ignored
otherwise). For two matrices (or a matrix and scalar), return
the pair-wise maximum. Thus,

max (max (X))

returns the largest element of the matrix X, and

max (2:5, pi)


=> 3.1416 3.1416 4.0000 5.0000

compares each element of the range ’2:5’ with ’pi’, and returns
a row vector of the maximum values.

For complex arguments, the magnitude of the elements are used


for comparison.

If called with one input and two output arguments, ’max’ also
returns the first index of the maximum value(s). Thus,

[x, ix] = max ([1, 3, 5, 2, 5])


=> x = 5
ix = 3

See also: min, cummax, cummin

20
Additional help for built-in functions and operators is
available in the online version of the manual. Use the command
’doc <topic>’ to search the manual index.

Help and information about Octave is also available on the WWW


at http://www.octave.org and via the help@octave.org
mailing list.

Ejercicio 3 Una variable X U (a, b) (Uniforme en el intervalo (a, b)) puede


ser generada usando la siguiente formula: X = (b a) ⇤ U + a, donde U es
una variable aleatoria uniforme en el intervalo (0, 1). Búsquese usando help el
funcionamiento de la función rand y genérense un vector con 100000 valores
de esta variable aleatoria, use la función hist para graficar un histograma y
comprobar que se sigue una distribución uniforme.

Otras funciones que son de utilidad en el área de optimización y en simulación


son: min, det, rand, randn.

3 Archivos Script
El uso de Octave es muy similar al de una calculadora en donde damos orden
por orden lo que se debe realizar, esto puede ser muy tedioso si la cantidad de
instrucciones que hemos de ingresar es relativamente grande, además de que
si cometimos algún error al escribir alguna variable, entrada de matriz, orden,
etc. generalmente tendrı́amos que comenzar desde el principio, lo cual es poco
práctico.
Para evitar este problema se usan los Archivos script, que tratan de emular lo
que se hace en lenguajes de programación como C o Pascal en donde se tiene que
escribir el código, luego compilarlo y finalmente ejecutar el programa. Algunas
caracterı́sticas de los scripts son:

• Un script es una lista de comandos de Octave, también denominada pro-


grama.
• Cuando se ejecuta un archivo script Octave ejecuta los comandos en el
orden en que han sido escritos como si se teclearan directamente en la
terminal.
• Cuando un comando tiene una orden que produce una salida (por ejemplo
una asignación u operación), y esta no está terminada en punto y coma, se
visualizará el resultado de la misma forma que si se tecleará en la terminal.
• La utilización de Archivos es conveniente ya que pueden ser editados y
ejecutarse tantas veces como se desee.

21
• Los scripts pueden ser creados usando cualquier editor de texto plano
(gedit, block de notas, Emacs, Kate, etc.). Asimismo el texto puede ser
copiado y pegado en la terminal para ser ejecutado.
• Los Archivos script también se denominan Archivos M ya que la extensión
.m es la que se debe utilizar para ser reconocidos por Octave.

Como se puede ver, editar un script es muy sencillo, solo hace falta tener
un editor de texto y guardar el archivo con la extensión .m para ser ejecutado.
No se necesita de algún tipo de sintaxis adicional, en el script los comandos se
escriben tal y como se escrbirı́an en la terminal.

Para poder ejecutar un script se debe de asegurar primero que el script tiene ex-
tensión .m y segundo que nos encontramos en la carpeta que contiene el script.
para movernos a la carpeta que contiene al script solo hace falta conocer la
dirección de esta y movernos al directorio usando el comando cd.

octave:15> cd /home/sltkbcu/Documents
octave:16>

Variables
Las variables globales son variables que pueden ser reconocidas en cualquier
parte, incluidos los Archivos script. Su utilidad es apreciada principalmente en
el manejo de funciones (se hablará más adelante de ellas). Las variables glob-
ales, a diferencia de las variables comunes que hemos manejado, deben de ser
declaradas en el ambiente en el que van a ser utilizadas, y se debe de asegurarse
que estas ya tienen un valor cuando son utilizadas, para declarar variables glob-
ales se escribe global seguido de espacio y el nombre de cada variable global
separada por espacio.

octave:18> global x y z w

En el caso de un script, si las variables globales son declaradas o no carece de


importancia ya que estas instrucciones son ejecutadas como si fueran ejecutados
los comandos directamente sobre la terminal, sin embargo, en el uso de funciones
es necesario declararlas dentro y fuera de ella para poder ser manipuladas.

Cuando el script usará variables, se debe de asegurar que se les ha dado un


valor previamente y/o se les asignará un valor a medida que se ejecutan los
comandos, no es posible usarse una variable si esta no tiene asignado un valor.
Para ejecutarse un script solo hay que teclear su nombre en la lı́nea de comandos,
por ejemplo si el script tiene nombre ejemplo.m entonces el script se llamará
desde la lı́nea de comandos como:

22
octave:19> ejemplo
a =

1 2 3 4 5 6 7 8 9 10
Cuando se trabaja con un script grande o se resuelven varios problemas es
posible que se tenga guardada una cantidad relativamente grande de variables
en la memoria, es una práctica común en cualquier lenguaje de programación ir
desechando estas variables de tal forma que la memoria quede libre para poder
usarse en cualquier momento. No nos gustarı́a que una aplicación falle a medio
proceso por falta de memoria. Para realizar eso se usa el comando clear. Esto
borra todas las variables con las que se esté trabajando, si se desea eliminar
alguna variable en particular mientras que se sigue trabajando con el resto, se
usa el mismo comando, se deja un espacio y luego la/las variables a eliminar
seguidas de espacio.
octave:20> clear
octave:21> x = 1;
octave:22> y=4
y = 4
octave:23> z=[1,2,5]
z =

1 2 5

octave:24> clear x y
octave:25> x
error: ’x’ undefined near line 25 column 1
octave:25> z
z =

1 2 5

octave:26>

3.1 Guardar y cargar datos


Cuando se ejecuta un programa, se desea obtener uno o más resultados, serı́a
poco práctico escribir estos resultados a mano, en especial si se trata de una
matriz de 1000x1000 por dar un ejemplo. Octave permite guardar estos datos
en diversos formatos, ası́ como cargar desde un archivo de tal forma que no se
tengan que ingresar los datos manualmente.

Los comandos save y load permiten guardar y cargar datos en diversos for-
matos.
save El comando save sirve para guardar los valores de las variables con las que
se esté trabajando actualmente, usa la sintaxis save opciones archivo x1 x2

23
· · · . Se escribe primero la palabra save seguida de espacio, en seguida la o las
opciones que se van a utilizar, si se usa más de una opción entonces cada opción
se separará por un espacio, luego de un espacio se escribe entre comillas simples
el nombre del archivo en el que se guardarán las variables y finalmente la/las
variables que se guardarán, cada una de ellas separadas por un espacio.

octave:31> x = 2;
octave:32> y = [1,2,3];
octave:33> z = [1 2 ; 4 5];
octave:34> save -ascii ’archivo.txt’ x y z
Es necesario escribir save, las opciones pueden o no ser escritas, en caso de
no indicarse alguna opción la salida por default es un archivo de texto que con-
tiene información detallada sobre cada variable guardada, el nombre del archivo
debe de proveerse, si el archivo no existe lo crea y si existe lo reemplaza. Las
variables a guardarse pueden o no especificarse, si no se especifica alguna vari-
able entonces se guardan todas las variables con las que se esté trabajando.

Las opciones de la función save son:


Opción Descripción
-ascii Guarda los datos en formato de texto.
-binary Guarda los datos en formato binario.
-float-binary Guarda los datos en formato binario de precisión sen-
cilla. Se debe de usar este formato solo si se sabe
que los datos a guardar pueden ser guardados us-
ando esta precisión.
-mat-binary Guarda los datos en formato binario de MATLAB. Es
el formato por default en el que se guardan los datos
en MATLAB.
La función load sirve para cargar datos de un archivo de texto plano, la
sintaxis a utilizar es en este caso:

octave:14> y = load(’X.txt’)
y =

6.60100 13.02966 10.32290 13.79483 1.65054


2.28473 12.80102 9.98589 14.11730 8.75711
6.21307 9.02257 2.29923 3.47374 7.99365
12.75629 9.01940 10.45939 12.85129 12.75086
3.60502 6.85801 0.16206 9.78344 0.91882
9.39162 2.60399 7.36981 7.87528 9.53574
1.74349 12.97184 4.47034 12.15191 9.58456
7.70008 1.27695 11.98621 2.05689 5.45029

24
2.47802 0.57247 3.42081 12.68678 3.27684
12.01603 9.17642 12.15015 10.33811 4.43015

octave:15> load(’X.txt’)
octave:16> X
X =

6.60100 13.02966 10.32290 13.79483 1.65054


2.28473 12.80102 9.98589 14.11730 8.75711
6.21307 9.02257 2.29923 3.47374 7.99365
12.75629 9.01940 10.45939 12.85129 12.75086
3.60502 6.85801 0.16206 9.78344 0.91882
9.39162 2.60399 7.36981 7.87528 9.53574
1.74349 12.97184 4.47034 12.15191 9.58456
7.70008 1.27695 11.98621 2.05689 5.45029
2.47802 0.57247 3.42081 12.68678 3.27684
12.01603 9.17642 12.15015 10.33811 4.43015

Como se ve, existen dos formas de cargar el archivo, la primera es asignárselo


directamente a una variable (y en el caso del ejemplo). La segunda es solo usar
el comando load con lo que Octave creará una variable con el mismo nombre
del archivo (sin extensión) y guardará el archivo ahı́. Cuando se usa el co-
mando save para guardar varias variables, es conveniente guardar las variables
en archivos por separado, si las matrices son de tamaños distintos provocará un
error al usar load además de que solo se puede usar load para asignar valor a
una sola variable, en el caso de un archivo .txt. Por el contrario si se carga un
archivo guardado como .mat no hace falta asignarse a una variable en particu-
lar, por default se asigna cada variable en el archivo a una variable con el mismo
nombre que tenı́a al ser guardada, en este caso es posible recuperar más de una
variable desde un solo archivo. Ambos son formatos son útiles, si se guardan en
un archivo .txt se puede usar otro programa para usar estos datos, por ejemplo
gnuplot para graficarlos, si por el contrario solo se desea guardar los datos para
usarse en una sesión posterior entonces quizá sea más conveniente guardarlos
como .mat.

4 Programación en Octave
Hasta ahora se ha hablado sobre el ambiente de Octave, la naturaleza de las
variables y la utilidad de los scripts para organizar las instrucciones de una forma
clara y susceptible a cambios. Por si solo lo que se ha visto no es suficiente para
resolver un problema.

25
4.1 Operadores relacionales y lógicos
Un operador relacional es aquel que compara dos números y devuelve como re-
spuesta falso o verdadero. Si el resultado es falso se devuelve o y si es verdadero
se devuelve 1. Los operadores relacionales disponibles en Octave son:

< Menor a
> Mayor a
== Igual a
<= Menor o igual a
>= Mayor o igual a
⇠= Distinto a

Los operadores relacionales usualmente son aplicables solamente a escalares,


pero en Octave es posible aplicar el operador a vectores y matrices siempre que
coincida el tamaño. En este último caso se devolverá una matriz del mismo
tamaño que las matrices comparadas y que contendrá el resultado de la com-
paración entre cada par de elementos correspondientes

octave:27> 1<3
ans = 1
octave:28> 5>0
ans = 1
octave:29> x = rand(5,1)
x =

0.265078
0.730114
0.969672
0.212333
0.050660

octave:30> y = rand(5,1)
y =

0.36415
0.42134
0.24123
0.47921
0.85776

octave:31> x<=y
ans =

26
1
0
0
1
1

También es posible comparar una matriz con un escalar, en este caso se compara
cada elemento de la matriz con dicho escalar.

octave:32> M = rand(4)
M =

0.492392 0.671352 0.587814 0.400250


0.997428 0.880732 0.252315 0.638045
0.053192 0.755610 0.633398 0.196543
0.458146 0.403724 0.964102 0.215812

octave:33> M>0.5
ans =

0 1 1 0
1 1 0 1
0 1 1 0
0 0 1 0
octave:34> whos ans
Variables in the current scope:

Attr Name Size Bytes Class


==== ==== ==== ===== =====
ans 4x4 16 logical

Total is 16 elements using 16 bytes

Aunque el resultado es un vector/matriz lógico/a, es posible operar con estos


valores como si se trataran de números en punto flotante, de esta forma, si se
quiere calcular la suma de los elementos de la matriz ans en el ejemplo anterior
no habrı́a problema alguno:

octave:35> sum(sum(ans))
ans = 8

27
4.2 Operadores Lógicos
Los operadores lógicos son usados en la lógica proposicional para aceptar o
rechazar una sucesión de proposiciones relacionadas entre sı́. Los operadores
lógicos que son posible de usar en Octave son:

& Y Se utiliza para comprobar que dos sen-


tencias son afirmativas, si al menos al-
guna es falsa entonces se devuelve 0, y
1 en caso contrario.
| O Se utiliza para comprobar si de dos sen-
tencias al menos una es afirmativa, se
devuelve 1 si al menos una es afirma-
tiva y 0 si ambas son falsas.
⇠ negación Se utiliza para negar una sentencia, de-
vuelve 0 si la sentencia es verdadera y
1 si es falsa.

• Los operadores lógicos funcionan con números, cualquier número distinto


a 0 (falso) se considera 1 (verdadero).

• Los operadores lógicos como los operadores relacionales se pueden utilizar


en expresiones y operaciones matemáticas.

• Los operadores lógicos al igual que los relacionales se pueden ocupar con
vectores y matrices siempre que se haga la comparación entre matrices del
mismo tamaño o una matriz y un escalar.

octave:39> x1 = 1;
octave:40> x2 = 0;
octave:41> x1&x2
ans = 0
octave:42> x1|x2
ans = 1
octave:43> ~x2
ans = 1
octave:44> y = [0 1 0;1 2 3;-1,0,4]
y =

0 1 0
1 2 3
-1 0 4

28
octave:45> y&x1
ans =

0 1 0
1 1 1
1 0 1

octave:46> y|x2
ans =

0 1 0
1 1 1
1 0 1

octave:47> ~y
ans =

1 0 1
0 0 0
0 1 0

octave:48> y2 = [0 0 1;2 3 7;1 1 1]


y2 =

0 0 1
2 3 7
1 1 1

octave:49> y&y2
ans =

0 0 0
1 1 1
1 0 1

Ya que los operadores lógicos y relacionales se pueden emplear en operaciones


matemáticas, estos tienen precedencia con respecto a las operaciones usuales.
Los órdenes de precedencia son los siguientes:

29
Orden de Precedencia Operación
1(la mayor) Paréntesis, si hay paréntesis anidados el
más interno tiene mayor precedencia.
2 Exponenciación
3 Operación lógica de negación (⇠)
4 Multiplicación y división
5 Suma y resta
6 Operadores relacionales
7 Operación Lógica Y (&)
8(la menor) Operación lógica O ( | )
Si dos o más operadores tienen la misma precedencia entonces la operación
se efectuará de izquierda a derecha.

4.3 Sentencias condicionales


Una sentencia condicional en Octave es una instrucción que permite tomar de-
cisiones sobre si se ejecuta un grupo de comandos si se cumple una condición
o, por el contrario, omitirlos. En una sentencia condicional se evalúa una ex-
presión condicional y en caso de ser verdadera el grupo de comandos se ejecutará.

Estructura if-endif Esta estructura consta de 3 partes, la sentencia if que evalúa


una expresión condicional, una serie de instrucciones que serán ejecutadas si la
expresión condicional resulta verdadera, la sentencia endif que indica el fin de
los comandos afectados dentro de la sentencia if.
octave:56> x=0;
octave:57> y=1;
octave:58> z=4;
octave:59> if x==0
> y=2;
> z=0;
> x=1;
> endif
octave:60> x
x = 1
octave:61> y
y = 2
octave:62> z
z = 0
octave:63> if x==0
> x=100;
> y=0;
> endif
octave:64> x
x = 1
octave:65> y

30
y = 2
octave:66> z
z = 0
Un valor distinto de cero funciona como verdadero.

Estructura if-else-endif
Esta estructura es usada para ejecutar uno entre dos grupos de comandos
en función de su evaluación lógica. la sintaxis es como sigue:

octave:6> x=1;
octave:7> y=2;
octave:8> opcion=2;
octave:9> if opcion==1
> x=0;
> y=0;
> else
> x=10;
> y=10;
> endif
octave:10> x
x = 10
octave:11> y
y = 10
si se cumple la sentencia lógica entonces se ejecuta el primero grupo de
comandos y en caso contrario se ejecuta el segundo grupo. También es posi-
ble “anidar” de tal forma que se ejecute un grupo de comandos entre varios
disponibles, para eso se usa la sentencia elseif seguida de una expresión condi-
cional.

octave:14> x=0;
octave:15> y=1;
octave:16> opcion=3;
octave:17> if opcion==0
> x=10;
> elseif opcion==1
> y=10;
> elseif opcion==2
> x=x*y;
> elseif opcion==3
> y=x/y;
> else

31
> x=2;
> y=2;
> end
octave:18> x
x = 0
octave:19> y
y = 0
En este tipo de estructura, cuando se cumple una expresión condicional se ejecu-
tará el grupo de datos correspondiente y luego de eso no se seguirán evaluando
las demás expresiones condicionales, es decir son ignoradas.

Estructura switch-case
La función de la estructura switch-case es muy similar al de la estructura
if-elseif-else-end, también es utilizada para ejecutar un grupo de comandos
pero no se verifica una expresión condicional sino el valor de una variable(que
en algún sentido es evaluar una expresión condicional de manera indirecta), la
sintaxis es la siguiente:

octave:19> x = 2;
octave:20> opcion = mod(x,2)
opcion = 0
octave:21> switch(opcion)
> case 0
> fprintf(’x es un número par\n’)
> case 1
> fprintf(’x es un número impar\n’)
> otherwise
> fprintf(’Ocurrio un error\n’)
> end
x es un número par
La estructura switch-case tiene las siguientes reglas:

• Si hay más de una coincidencia solo se atenderá a la primera que aparezca.


• Si no se encuentran coincidencias entonces se ejecuta el grupo de comandos
que siguen a la palabra otherwise(esta es opcional y no es necesario
usarse).
• Si no hay coincidencias y la palabra otherwise no se encuentra entonces
no se ejecuta ningún grupo de comandos.
• Una sentencia case puede tener más de un valor con el cual establecer
coincidencias. Para declararlos solo es necesario ponerlos a continuación
entre llaves y separados por comas { valor1, valor2,...}.

32
Para los que estén familiarizados con C, la estructura switch-case funciona
de la misma forma salvo que en C es necesario terminar cada grupo de comandos
con la sentencia break; ya que de no hacer esto se siguen buscando coincidencias
de tal forma que se puede ejecutar más de un grupo de comandos.

4.4 Bucles
Los bucles o sentencias repetitivas nos sirven para realizar un mismo grupo de
comandos en forma consecutiva. Cada una de estas repeticiones se denomina
paso o iteración. Existen dos tipos de bucles que se pueden usar en Octave,
estos son los bucles tipo for-endfor y los bucles tipo while-endwhile.
Estructura for-endfor
La sintaxis para este tipo de bucle es la siguiente:

octave:1> for i=1:5


> x(i) = i;
> endfor
x

x =

1 2 3 4 5

octave:9> y = ones(1,10);
octave:10> for x = 1:2:10
> y(x) = 0;
> end
octave:11> y
y =

0 1 0 1 0 1 0 1 0 1

Se inicia con la palabra for seguida de espacio y un contador igualado a


un vector con los valores que tomará el contador en cada paso del bucle. En
seguida un conjunto de instrucciones que se realizará en cada paso y finalmente
la palabra endfor para indicar el fin del bucle. En los ejemplos anteriores
se muestra que los valores que debe de tomar el contador no deben de ser
necesariamente consecutivos, además, estos valores no tienen restricciones en
cuanto a que no hace falta que tomen valores enteros (como suele usarse en C),
ni siquiera deben de ser valores distintos.

octave:1> a = ones(1,5)
a =

33
1 1 1 1 1

octave:2> for i = a
> x(a) = a;
> end
octave:3> x
x = 1

octave:15> a = zeros(1,5);
octave:16> cont = 1
cont = 1
octave:17> for i = linspace(1,2,5)
> a(cont) = i;
> cont = cont + 1;
> end
octave:18> a
a =

1.0000 1.2500 1.5000 1.7500 2.0000

Si la variable contador tiene asignado la matriz nula [] entonces el ciclo no


se ejecutará.

Estructura while-endwhile
Estos bucles constan de las siguientes partes: la palabra while seguida de
espacio y una expresión condicional, una serie de instrucciones, y finalmente la
palabra endwhile para indicar el fin del bucle.

octave:24> x = 0;
octave:25> i = 1;
octave:26> while x<20
> x = x + i;
> i = i + 1;
> endwhile
octave:27> x
x = 21
Cuando se entra al bucle tipo while-endwhile se empieza por verificar la
expresión lógica, si esta es verdadera entonces se ejecutan las instrucciones den-
tro del bucle, si esta no se cumple entonces se ignora el bucle y se continua con
las siguientes instrucciones. En C existe el tipo de bucle do-while que asegura
que siempre se ejecuta al menos una vez el grupo de instrucciones, en Octave
este tipo de bucle no existe, hay que tener en cuenta este detalle.

Cuando se trabaja con bucles del tipo while hay que tener en cuenta que

34
este continuará ejecutándose hasta que la expresión lógica sea falsa, es algo
común cometer errores y que la expresión lógica siempre sea verdadera, en ese
caso se puede cancelar la ejecución del bucle mediante la combinación de teclas
control+C. Esto, sin embargo, detiene la ejecución de todo el código restante
por lo que se debe de ocupar en caso de que sepamos que se ha cometido un
error o no se desee continuar con el resto de cálculos por algún motivo.

Existen dos herramientas que nos ayuda al control de los bucles, la primera
es el comando break, este comando forza la terminación del bucle, en el caso
del bucle for-endfor ignora el resto de iteraciones y en el caso del bucle tipo
while-endwhile no se vuelve a evaluar la expresión lógica. La otra herramienta
es el comando continue al aparecer este comando se provoca que el grupo de
instrucciones en la iteración actual sea ignorada y se comienza con las instruc-
ciones de la siguiente iteración.

Ejercicio 4 Recordemos que una expresión lógica, en Octave, puede ser también
un vector.¿ Que sucede si en una expresión condicional se usa un vector?. Por
ejemplo, ¿Qué devuelve el siguiente código?

octave:47> x = [1 2 3 4];
octave:48> y = [4 3 2 1];
octave:49> a = 1;
octave:50> if x<y
> a = 0;
> endif

¿Y si el código es el siguiente?

octave:56> x = [0 0 0 0];
octave:57> y = [1 2 3 4];
octave:58> a = 1;
octave:59> if x<y
> a = 0;
> endif

5 Funciones
En la sección 1 se usaron algunas funciones que trabajan sobre matrices, que
devuelven la suma de sus elementos, que devuelven su tamaño, etc. Aunque
en Octave existen un sinnúmero de funciones predefinidas para hacer gran can-
tidad de tareas, siempre será necesario poder crear nuestras propias funciones
para realizar tareas personalizadas o rutinas que no se encuentran programadas
en Octave, las funciones sirven para esto.

35
Una función es un conjunto de instrucciones que, al igual que los scripts, son
guardadas en un archivo .m. Una función puede requerir de algunas variables
de entrada (argumentos) o no, y devuelven una o más variables de salida. Para
manejar una función, al igual que con los scripts, es necesario que la función
se encuentre guardada en el directorio donde se está trabajando actualmente.
Debe de tener la siguiente forma:

function y = paraboloide(x)
y = sum(x.^2);
endfunction
Se inicia con la palabra function seguida de espacio y el nombre de la vari-
able de salida, el operador de asignación y entre paréntesis los argumentos que
usará la función, la función podrı́a no necesitar de parámetro alguno, en ese
caso se deja vacı́o el interior de los paréntesis. Una función en Octave puede
no devolver valor alguno, una o más variables. Los siguientes son ejemplos de
funciones que no devuelven valores y que devuelven más de uno.

function [x,y] = funcion1(z)


x = z.^2;
y = z + x - 1;
endfunction

function funcion2()
fprintf(’Esta funcion no devuelve nada\n’)
endfunction
Ejecutar una función en Octave se realiza como en cualquier otro lenguaje,
tan solo se escribe el nombre de la función y entre paréntesis los valores de
entrada que requiere.
octave:79> z = 1:5;
octave:80> funcion1(z)
ans =

1 4 9 16 25

octave:81> funcion2
Esta funcion no devuelve nada
Como se puede observar en el ejemplo, la función funcion1 que queremos
que devuelva dos valores de salida solo devuelve uno, solo es posible visualizar
la segunda variable de salida si esta es asignada a una variable, por ejemplo,
para poder obtener los dos valores de salida de la función podrı́amos hacer algo
como:

36
octave:82> [x,y] = funcion1(z)
x =

1 4 9 16 25

y =

1 5 11 19 29
Mientras que si lo que deseamos es solo el segundo valor que devuelve la
función podemos hacer:
octave:83> [~,y] = funcion1(z)
y =

1 5 11 19 29
Usando el operador ⇠ no hace falta reservar memoria para una variable que
no vamos a ocupar. También es posible que una función haga un llamado a otra
función, como es el caso de la primer función que planteamos (paraboloide) que
usa la función sum, podemos usar una función siempre que ésta este definida en
el mismo directorio de trabajo, y se llamará de la forma usual. Algo que es muy
útil es que una función usada dentro de otra función sea una variable, por ejem-
plo, si deseamos calcular la derivada en un punto, nos gustarı́a que esta función
sirva para cualquier función, o lo que es lo mismo, que la funcion ”derivada”
acepte como argumento de entrada otra función. En C esto se hace mediante
un puntero a una función, en Octave esto se realiza mediante la expresión:

octave:84> A = @funcion2
A = @funcion2
octave:85> A
A = @funcion2
octave:86> A()
Esta funcion no devuelve nada
El operador @ nos permite asignar la función a una variable para poder
enviarla como argumento a una función. Volviendo al ejemplo de la derivada de
una función, la función tendrı́a una estructura como la siguiente:
function y = derivada(f,x)
....
....
....
endfunction
Donde f es la función de la cual queremos obtener la derivada, x el punto
en el que hay que evaluarse y y la variable de salida con el valor de f 0 (x)

37
Una cosa importante y que no ha sido mencionada es que para poder ejecutar
una función desde un archivo .m (podrı́a definirse la función en la terminal sin
necesidad de un archivo que la contenga) es necesario que el archivo .m tenga el
mismo nombre de la función, es decir, en nuestros ejemplos los archivos deberı́an
de llamarse paraboliode.m, funcion1.m, funcion2.m, derivada.m
En general las funciones tienen muchas similitudes con los scripts, por ejem-
plo, que son una serie de comandos y que estas pueden guardarse en un archivo
.m para poder ejecutarse después, sin embargo, las funciones tienen diferencias
con respecto a los scripts.
• Una función puede requerir o no de argumentos de entrada. Un script no
requiere de argumentos de entrada para poder ejecutarse.
• En una función todos los valores usados son eliminados (salvo por los
valores de salida y variables globales) una vez acabadas las instrucciones
de esta. En un script las variables usadas pueden seguirse usando y si
no se desea seguir usándolas requiere de eliminarse (usando clear por
ejemplo).
Cuando se ejecuta una función o script, al igual que con los bucles, se puede
detener la ejecución de estos usando la combinación de teclas control+C.
Para terminar esta sección se muestra a manera de ejemplo un programa
que permite calcular el gradiente de una función usando diferencias finitas:

function G = grad(F,X,h)
%F es el nombre de la función, X es el punto en el que se
%evaluará el gradiente, h es el tama~
no del incremento en cada
%variable
dim = length(X);%Aquı́ se calcula el número de variables de la
%función
%En I se guardan vectores que representan los incrementos en cada
%variable
I = h*eye(dim);
%G es la inicialización del vector que se devolverá(el gradiente de
%F en X)
G = zeros(1,dim);
%En el siguiente bucle se calcula el gradiente para cada variable
%i, i=1,..,dim
for i = 1:dim
G(i) = (F(X+I(i,:))-f(X-I(i,:)))/(2*h);
endfor
endfunction
Como nota del programa anterior, X debe ser un vector renglón para que
las dimensiones de las sumas de matrices sean compatibles.

38
Ejercicio 5 Usando como base el programa anterior, elabórese un programa que
permita calcular la hessiana de una función F en el punto X con un incremento
h.

6 Gráficas
Además de los resultados numéricos, mostrar gráficas que muestren dichos re-
sultados siempre es más ilustrativo. En Octave se pueden realizar graficas en
2D y 3D usando los comandos plot y plot3 respectivamente, en esta sección
se mostrará algunas de las caracterı́sticas de estas funciones.

6.1 El comando plot


El comando plot sirve para graficar en 2D, es una función que se comporta de
forma distinta dependiendo del número de parámetros y el tipo que sea ingre-
sado.

Si se ingresa un solo parámetro y este es un vector, entonces el vector lo tomará


como una serie y se graficará una correspondencia de esta con los números nat-
urales, por ejemplo el código:

octave:6> x = rand(1,100);
octave:7> plot(x)
octave:8> print(’-djpg’,’ej1.jpg’)

produce:

39
figuras/ej1.jpg

Figure 1: Gráfica de una serie

El comando usado luego del comando plot, print, se usa para guardar la
imagen graficada en un archivo, en el caso anterior se usó el argumento ’-djpg’
para guardar la imagen en el archivo ’ej1.jpg’, puede guardarse la imagen en
distintos tipos de archivo, por ejemplo .eps, PS, PNG, PDF, TIFF,.

Si el argumento es una matriz entonces cada columna la considerará como una


serie de tiempo distinta y las graficará todas ellas en la misma gráfica y en dis-
tinto color. Por ejemplo el código:

octave:14> x = rand(20,5);
octave:15> plot(x)
octave:16> print(’-djpg’,’ej2.jpg’)
muestra

40
figuras/ej2.jpg

Figure 2: Gráfica de varias series

En general plot la forma más común de usar plot es usando dos argumen-
tos, estos argumentos son vectores que contendrán las abscisas y las ordenadas
respectivamente, hay que tener en cuenta que deben de tener el mismo tamaño.
En el código siguiente se gráfica la función f (x) = cos(x) en el intervalo [1, 4]

octave:21> x = 1:0.01:4;
octave:22> y = cos(x);
octave:23> plot(x,y)
octave:24> print(’-djpg’,’ej3.jpg’)

41
figuras/ej3.jpg

Figure 3: Gráfica de f (x) = cos(x)

En realidad lo que hace Octave es hacer una correspondencia entre los val-
ores de x y los de y y graficar punto por punto, al no especificarse más acerca
de lo que se quiere, por default, Octave unirá esos puntos por una lı́nea, si solo
necesitáramos ver los puntos se necesita agregar más argumentos, por ejemplo:

octave:52> x = 1:0.5:4;
octave:53> y = x.^2;
octave:54> plot(x,y,’marker’,’*’,’color’,’b’,’markersize’,20,
’linestyle’,’none’)
octave:55> print(’-djpg’,’ej4.jpg’)
que muestra la siguiente figura:

42
figuras/ej4.jpg

Figure 4: Gráfica discreta

Las opciones que acepta plot son:

1. color. Esta opción cambia el color del gráfico, puede usarse con valores
predeterminados como b para azul, r para rojo, etc. O puede usarse un
vector con porcentajes de los colores primarios azul, rojo y verde, por
ejemplo [0, 4, 0.5, 0]
2. marker. Esta opción determina el tipo de marcador que usarán los pun-
tos en el gráfico, puede usar como valores . para usar un punto, ⇤ para
asterisco, o para circulo, s para cuadrado, d para diamante y muchos más.
3. linestyle. Determina el tipo de lı́nea con el que se unirán los puntos, como
valores puede tomar: para una lı́nea recta, lı́nea punteada, none
para no poner lı́nea etc.
4. linewidth Se usa para cambiar el grosor de la lı́nea dibujada entre puntos.
5. markersize. Determina el tamaño del marcador, su argumento es un
número real.
6. markeredgecolor. Indica el color del contorno de la figura usada como
marcador, puede usar los colores predeterminados por letras o un vector
de 3 componentes como la opción color.
7. markerfacecolor. Se usa para indicar el color del relleno de la figura usada
como marcador, usa las mismas opciones que color.

43
La sintaxis para un formato muy especı́fico puede ser muy larga, pero si
no hace falta especificar mucho se puede usar un formato más corto como el
siguiente:

octave:83> x = linspace(-1,3,10);
octave:84> y = x.^2;
octave:85> plot(x,y,’k.’)
octave:86> print(’-djpg’,’ej5.jpg’)
octave:87> plot(x,y,’m’)
octave:88> print(’-djpg’,’ej6.jpg’)

que produce las figuras:

figuras/ej5.jpg

Figure 5: Gráfica simple (solo puntos)

44
figuras/ej6.jpg

Figure 6: Gráfica simple (puntos unidos)

Antes pudimos graficar en una sola gráfica varias series de tiempo, también
es posible graficar varias gráficas en un mismo gráfico, para eso usamos los
comandos hold on y hold off. Para usarse solo se debe de colocar entre estos
las instrucciones plot.

octave:1> x = linspace(0,pi,100);
octave:2> hold on
octave:3> plot(x,cos(x),’ro’)
octave:4> plot(x,sin(x),’bp’)
octave:5> plot(x,x.^2,’mx’)
octave:6> plot(x,exp(x),’k^’)
octave:7> hold off
octave:8> print(’-djpg’,’ej7.jpg’)

El código anterior produce:

45
figuras/ej7.jpg

Figure 7: Gráficas usando hold on y hold o↵

Además de las figuras es posible agregar texto a las mismas, por ejemplo
incluir un tı́tulo a las gráficas o nombrar los ejes, etc.

Para darle un tı́tulo a la imagen se usa el comando title, para darle nom-
bre a los ejes se usa xlabel y ylabel, para poner una texto que asocie los
marcadores con alguna caracterı́stica se usa legend, todas estas funciones(salvo
legend) usan como parámetro una cadena te texto(hay que tener cuidado con
los acentos) que indica lo que debe de escribirse como etiqueta, el tamaño del
texto se puede ajustar con la opción fontsize y un tamaño de fuente, el valor
por defecto es 10.

octave:27> x = linspace(0,pi,100);
octave:28> hold on
octave:29> xlabel(’Abscisas’,’fontsize’,20)
octave:30> ylabel(’Ordenadas’,’fontsize’,20)
octave:31> title(’Ejemplo de texto en graficas’,’fontsize’,20)
octave:32> plot(x,cos(x),’ro’)
octave:33> plot(x,sin(x),’b.’)
octave:34> legend(’Grafica de cos(x)’,’Grafica de sen(x)’)
octave:35> hold off
octave:36> print(’-djpg’,’ej8.jpg’)

46
figuras/ej8.jpg

Figure 8: Gráficas con etiquetas

También es algo común que queramos graficar varias funciones o conjuntos


de datos en distintas gráficas pero vistas en la misma figura, para ello usamos
el comando subplot. El comando subplot(m,n,p) tiene 3 argumentos, los
dos primeros definen una partición de la figura, la parte en m renglones y n
columnas, p es la posición en la que se colocará el gráfico. Para comprender
mejor esto veamos el siguiente ejemplo:

octave:38> x = linspace(0,pi,100);
octave:39> subplot(2,2,1)
octave:40> plot(x,cos(x),’yo’)
octave:41> subplot(2,2,2)
octave:42> plot(x,sin(x),’cd’)
octave:43> subplot(2,2,3)
octave:44> plot(x,x.^2,’color’,rand(1,3),’marker’,’h’,’linestyle’,’none’)
octave:45> subplot(2,2,4)
octave:46> plot(x,exp(x),’bx’)
octave:47> print(’-djpg’,’ej9.jpg’)

47
figuras/ej9.jpg

Figure 9: Gráficas con etiquetas

También se debe de notar que cada subgráfica es independiente de las demás,


por lo que se pueden graficar más de una función en cada una de ellas, insertar
tı́tulos, legendas, y en general, todo lo que se ha visto hasta ahora.

7 Temas Avanzados
Cuando se programa se está interesado en que nuestro código nos devuelva el
resultado que deseamos, la mayorı́a de las veces esto es suficiente, sin embargo,
cuando los problemas aumentan en dificultad, resolver el problema ya no es sufi-
ciente, además de resolverlo necesitamos que lo haga lo más rápido posible. Esta
sección se centra en mencionar algunos detalles que están más bien relacionados
a la programación en general y cálculo numérico.

48
Aumentar la calidad del código escrito en Octave
El uso de scripts y funciones ayuda a tener ordenado lo que se desea progra-
mar, siempre es conveniente crear módulos sobre los cuales si ocurre un error
sea fácil identificar la sección de donde proviene dicho error. Es por esto que
un buen hábito es el de usar estas herramientas. En general, Octave es un
lenguaje interpretado, de alto nivel y por tanto difı́cilmente podrá compararse
en tiempo de ejecución a programas compilados en C, y sin embargo, existen
algunas técnicas de programación que pueden ayudarnos a que esta diferencia
no sea tan significativa.

Vectorizar, la clave para aumentar la velocidad


El usuario de Octave debe de acostumbrarse a que todo son matrices. Cuando
se crearon los ordenadores y empezaron a surgir los lenguajes de programación
casi todos los procesos eran escalares. Todo se realizaba mediante operaciones
lógicas que operaban en bloques pequeños de memoria. Cuando los equipos se
volvieron más potentes se pensó en formas más eficientes de realizar cálculos y
esto dio paso al concepto de vectorización.

Una operación escalar se realiza elemento a elemento. Cuando se quieren sumar


dos matrices o vectores se cada elemento con su correspondiente y se guarda en
un tercer vector. En una operación vectorial se hace esta operación pero para un
bloque grande de memoria, de tal forma que todas las sumas se realizan a la vez.

Octave es un software que está basado esta ideologı́a y está optimizado para
hacer las cosas en dicha forma, pero si se le pide hacer las cosas elemento a
elemento(por ejemplo en un bucle) también lo hará aunque no está optimizado
para trabajar de esta forma. Entonces, hay que pensar siempre en la forma en
que se hagan los cálculos por bloques de memoria en vez de elemento a elemento
usando por ejemplo submatrices.

El truco más importante de la programación en Octave


El truco más importante en Octave para que los scripts tengan una velocidad
aceptable es evitar los bucles contador. Esta es la estructura más lenta en
este lenguaje. A manera de ejemplo consideré el siguiente código en el que se
suman dos matrices usando dos métodos distintos(el ejemplo fue obtenido de
[?]). El primer método consiste en sumarlas elemento a elemento usando un
ciclo anidado en otro, en el segundo método simplemente se suman, para medir
la eficiencia de cada método usamos la pareja tic y toc para medir el tiempo de
ejecución de cada método.

a = rand(66); %matriz de 66 x 66
b = rand(66);
tic
for i = 1:66

49
for j = 1:66
c(i,j) = a(i,j)+b(i,j);
endfor
endfor
toc
Elapsed time is 0.05702 seconds.

tic
c = a+b;
toc
Elapsed time is 3.501e-05 seconds.

Como se observa que la diferencia es muy grande, usualmente del orden


de 100 veces más rápido(en el ejemplo 1628 veces para ser exactos). Cuando
pensamos en resolver una ecuación diferencial parcial, esta diferencia puede con-
vertir un proceso que tardarı́a un dı́a en uno que tardarı́a apenas unos minutos.
Podrı́amos decir que fue un ejemplo amañado ya que el segundo método(el más
rápido) es más intuitivo de hacer y en realidad no es algo que harı́amos de forma
premeditada. Supongamos ahora el siguiente ejemplo, tenemos un vector y una
matriz, supongamos que deseamos multiplicar cada renglón de la matriz por un
elemento del vector. Nuevamente se pensará en realizar por dos métodos difer-
entes, en el primero se formará un bucle y se tomará cada elemento del vector
y se multiplicará por cada renglón de la matriz y se guardará en otra matriz,
en el segundo método la secuencia de números del vector se convertirán en una
matriz para poder luego multiplicarla la matriz.

a = 1:66;
b = rand(66);
tic
for i = 1:66
c(i,:) = a(i)*b(i,:);
endfor
toc

Elapsed time is 0.002794 seconds.

a = 1:66;
b = rand(66);
tic
c = a’*ones(1,66).*b;
toc

Elapsed time is 0.000108 seconds.

Ahora podemos notar que el segundo método es aproximadamente 25 veces


más rápido que el primero. A diferencia de nuestro ejemplo anterior, aquı́ se
veı́a perfectamente justificado el uso del bucle, y sin embargo al darle la vuelta

50
al problema(aun cuando pareciera que estamos realizando más operaciones) el
tiempo resulta menor.

Lo que hace que estos bucles sean lentos no es exactamente el bucle en sı́,
tampoco la ausencia de vectorización, en los ejemplos anteriores el principal
problema fue en la asignación de memoria. Cuando se sumaron las matrices en
el primer ejemplo al final tenı́amos una matriz en donde se estaba guardando
la suma, recordemos que las variables no se declaran y se crean en el instante
en el que se les asigna un valor, cuando se inicia el bloque, esta matriz se está
igualando a un escalar(1x1), en los siguientes pasos del ciclo la matriz está
cambiando de tamaño hasta que al final terminamos con una matriz de 66x66,
precisamente porque no lo vemos es que pasa desapercibido, Octave realiza la
reserva de memoria para la variable, y cuando esta cambia de tamaño realiza
la reserva de memoria para una variable más grande, copia los valores de la
variable anterior en la nueva variable, asigna el nuevo valor calculado y libera
la memoria de la variable vieja. Es por lo que los ciclos se vuelven tan lentos.
En el segundo caso la reserva de memoria se realiza solo una vez. Además de
evitar los ciclos, una práctica común es reservar memoria para las variables, por
ejemplo creando una matriz de ceros del tamaño que necesitamos. Este com-
portamiento está ligado al funcionamiento de los arrays en C; un buen texto
para comprenderlo mejor es [?] donde encontraremos un capı́tulo inicial sobre
qué es verdaderamente un array y qué relación tiene con un puntero.

51

Você também pode gostar