Introducción a Mathematica - Departamento de Informática y Sistemas

Anuncio
Introducción a Mathematica
(en construcción...)
Alberto Ruiz <[email protected]>
Departamento de Informática y Sistemas
Universidad de Murcia, Spain
à Preliminares
Mathematica es un entorno de cálculo simbólico, compuesto por un lenguaje de programación de alto nivel, una
colección extensa de funciones matemáticas y de propósito general, y un sistema para editar interactivamente
documentos como éste que contienen texto normal, órdenes sencillas, programas más complejos, gráficos, etc.
Los documentos están organizados por "celdas" indicadas en azul a la derecha. Hay varios tipos de celdas: las más
importantes son las de texto normal, y las de entrada (input) y salida de información (output), como las siguientes:
In[1]:= 2 + 2
Out[1]= 4
El lenguaje de Mathematica es interpretado: no hace falta compilación. Está basado en reglas de transformación de
expresiones y aprovecha muchas construcciones de programación funcional.
Para ejecutar una orden o evaluar una expresión se edita en una celda tipo "input" y cuando esté terminada se pulsa
Shift−Enter (tecla de mayúsculas + tecla de nueva línea). A continuación aparecerá una celda con el resultado.
Mathematica se puede usar directamente como una calculadora:
In[2]:= 1.5 + 2.5
Out[2]= 4.
El espacio en blanco significa multiplicación (también se puede usar *):
In[3]:= 2 H5 + 5L
Out[3]= 20
La aritmética es exacta:
In[4]:= 1000  350
Out[4]=
20
€€€€€€€
7
y sin límite en el tamaño de los números:
In[5]:= 2 ^ 100
Out[5]= 1267650600228229401496703205376
In[6]:= 100 !
Out[6]= 93326215443944152681699238856266700490715968264381621468592963895217599993229„
9156089414639761565182862536979208272237582511852109168640000000000000000000„
00000
Pero si en las operaciones aparecen números aproximados, el resultado también lo será:
In[7]:= 1000.0  350
Out[7]= 2.85714
Siempre se puede convertir un valor exacto en un valor aproximado usando la función N (convertir en un número).
En Mathematica los argumentos se encierran entre corchetes:
In[8]:= N@1000  350D
Out[8]= 2.85714
In[9]:= Π
Out[9]= Π
In[10]:= N@ΠD
Out[10]= 3.14159
Como argumento opcional se puede especificar la precisión del número:
In[11]:= N@Π, 100D
Out[11]= 3.14159265358979323846264338327950288419716939937510582097494459230781640628„
6208998628034825342117068
Disponemos de todas las funciones matemáticas usuales :
In[12]:= [email protected]
Out[12]= 44.7012
In[13]:= [email protected]
Out[13]= 0.992809
In[14]:= Sin@30 DegreeD
Out[14]=
1
€€€€
2
Existen bibliotecas con constantes y unidades físicas.
à Principio Fundamental de Mathematica
Todo son expresiones que se evalú an mediante la aplicación de reglas de transformación estructural.
Ÿ Expresiones
Una expresión es o bien un átomo (número o símbolo) o bien una "cabeza" y "argumentos", que, a su vez, son
expresiones. Este tipo de estructura recursiva permite representar cualquier cosa: fórmulas matemáticas, programas, dibujos, etc. Este mismo documento es en realidad una expresión de ese tipo.
Las expresiones tienen una representación externa, visualmente conveniente, pero en realidad están constituidas
por este tipo de estructuras anidadas. Por ejemplo:
a+b
es en realidad
Plus@a, bD
(Los componentes de una expresión (o argumentos de una función) se escriben con corchetes.) Otro ejemplo:
a Sin@3 + b xD
se representa internamente mediante
Times@a, Sin@Plus@3, Times@b, xDDDD
La forma interna de cualquier expresión se obtiene mediante la orden FullForm:
In[15]:= FullFormAa SinA €€€€€€€€€€€€€€€€ EE
bx+3
!!!!!!
Πm
Out[15]//FullForm=
Times@a, Sin@Times@Power@Power@Pi, mD, Rational@-1, 2DD, Plus@3, Times@b, xDDDDD
Los "arrays" se representan mediante la estructura más general de lista, que es una colección de expresiones
encerradas entre llaves:
84, a + b, 17, 81, 2, 3<, 5<
aunque, por supuesto, internamente son expresiones con cabeza "Lista":
List@4, Plus@a, bD, 17, List@1, 2, 3D, 5D
Ÿ Evaluación
El funcionamiento de Mathematica consiste en leer una expresión (y pasarla a la forma interna), evaluarla, y
mostrar el resultado (en forma externa).
La evaluación consiste en la aplicación de ciertas "reglas" que modifican la estructura de la expresión. Estas reglas
son de varios tipos: a) reglas que se aplican automáticamente (manipulación matemática usual) b) transformaciones
y algoritmos de distinto tipo ya preprogramados, y c) algoritmos definidos por nosotros para manipular las expresiones de acuerdo con nuestros intereses.
En primer lugar veremos algunos ejemplos de transformaciones automáticas y de instrucciones que realizan
transformaciones útiles:
Simplificación:
In[16]:= 2 + 3 + 5 x + y + 10 x - 5
Out[16]= 15 x + y
Expansión de potencias:
In[17]:= Expand@H1 + xL10 H1 - yL5 D
Out[17]= 1 + 10 x + 45 x2 + 120 x3 + 210 x4 + 252 x5 + 210 x6 + 120 x7 + 45 x8 + 10 x9 + x10 - 5 y -
50 x y - 225 x2 y - 600 x3 y - 1050 x4 y - 1260 x5 y - 1050 x6 y - 600 x7 y - 225 x8 y 50 x9 y - 5 x10 y + 10 y2 + 100 x y2 + 450 x2 y2 + 1200 x3 y2 + 2100 x4 y2 + 2520 x5 y2 +
2100 x6 y2 + 1200 x7 y2 + 450 x8 y2 + 100 x9 y2 + 10 x10 y2 - 10 y3 - 100 x y3 450 x2 y3 - 1200 x3 y3 - 2100 x4 y3 - 2520 x5 y3 - 2100 x6 y3 - 1200 x7 y3 - 450 x8 y3 100 x9 y3 - 10 x10 y3 + 5 y4 + 50 x y4 + 225 x2 y4 + 600 x3 y4 + 1050 x4 y4 + 1260 x5 y4 +
1050 x6 y4 + 600 x7 y4 + 225 x8 y4 + 50 x9 y4 + 5 x10 y4 - y5 - 10 x y5 - 45 x2 y5 120 x3 y5 - 210 x4 y5 - 252 x5 y5 - 210 x6 y5 - 120 x7 y5 - 45 x8 y5 - 10 x9 y5 - x10 y5
Solución simbólica de sistemas de ecuaciones:
In[18]:= Solve@5 x - 8 a Š 4, xD
Out[18]= 99x ® €€€€ H1 + 2 aL==
4
5
Derivadas simbólicas:
In[19]:= D@Sin@Exp@Cos@xDDD, xD
Out[19]= -ãCos@xD Cos@ãCos@xD D Sin@xD
Integrales simbólicas:
In[20]:= à Sin@xD2 â x
Out[20]=
x
1
€€€€ - €€€€ Sin@2 xD
2
4
Desarrollos en serie:
In[21]:= Series@Exp@xD, 8x, 0, 5<D
x2
2
x3
6
x4
24
x5
120
Out[21]= 1 + x + €€€€€€€ + €€€€€€€ + €€€€€€€ + €€€€€€€€€€ + O@xD6
Límites:
i
k
1 y5 x
, x ® ¥E
2x{
In[22]:= LimitAj
z
j1 + €€€€€€€€ z
Out[22]= ã52
Representaciones gráficas 2D:
In[23]:= Plot@Sin@xD + Sin@10 xD, 8x, 0, 2 Π<D;
2
1
1
-1
-2
2
3
4
5
6
Y 3D:
In[24]:= Plot3D@[email protected] Hx x + y yLD, 8x, -3, 3<, 8y, -3, 3<, Mesh ® False, PlotPoints ® 50D ;
1
0.75
0.5
0.25
0
2
0
-2
0
-2
2
La aritmética es exacta:
In[25]:= Solve@5 x2 - 8 + 5 x3 Š 4, xD
1
1
!!!!!! 13 1 1
!!!!!! 13
19 M
+ €€€€ J €€€€ I157 + 36 19 MN =,
3
15
3 5
1
1
1
!!!!
!!!!!! 13 1
!!!!
!!!!!! 13
9x ® - €€€€ - €€€€€€€ I1 + ä 3 M I3925 - 900 19 M
- €€€€ I1 - ä 3 M J €€€€ I157 + 36 19 MN =,
3
30
6
5
1
1
1
!!!!
!!!!!! 13 1
!!!!
!!!!!! 13
9x ® - €€€€ - €€€€€€€ I1 - ä 3 M I3925 - 900 19 M
- €€€€ I1 + ä 3 M J €€€€ I157 + 36 19 MN ==
3
30
6
5
Out[25]= 99x ® - €€€€ + €€€€€€€ I3925 - 900
Pero siempre podemos obtener números aproximados.
In[26]:= Solve@5 x2 - 8 + 5 x3 Š 4, xD  N
Out[26]= 88x ® 1.07537<, 8x ® -1.03768 + 1.07471 ä<, 8x ® -1.03768 - 1.07471 ä<<
La notación x//f es equivalente a f[x] (se utiliza para ir encadenando o componiendo funciones cómodamente).
Se pueden resolver sistemas de ecuaciones polinomiales con varias incógnitas:
In[27]:= Solve@8x2 + x y Š y, x Š y2 <, 8x, y<D  N
Out[27]= 88x ® 0., y ® 0.<, 8x ® 0.56984, y ® 0.754878<,
8x ® 0.21508 - 1.30714 ä, y ® -0.877439 + 0.744862 ä<,
8x ® 0.21508 + 1.30714 ä, y ® -0.877439 - 0.744862 ä<<
La solución de ecuaciones no lineales debe hacerse numéricamente, indicando el punto de partida en la búsqueda:
In[28]:= FindRoot@Sin@Hx - .3L Cos@xDD, 8x, 89 Degree<D
Out[28]= 8x ® 1.5708<
Factorización de polinomios:
In[29]:= Factor@x99 + y99 D
Out[29]= Hx + yL Hx2 - x y + y2 L Hx6 - x3 y3 + y6 L
Hx10 - x9 y + x8 y2 - x7 y3 + x6 y4 - x5 y5 + x4 y6 - x3 y7 + x2 y8 - x y9 + y10 L
Hx20 + x19 y - x17 y3 - x16 y4 + x14 y6 + x13 y7 - x11 y9 x10 y10 - x9 y11 + x7 y13 + x6 y14 - x4 y16 - x3 y17 + x y19 + y20 L
60
Hx + x57 y3 - x51 y9 - x48 y12 + x42 y18 + x39 y21 - x33 y27 - x30 y30 x27 y33 + x21 y39 + x18 y42 - x12 y48 - x9 y51 + x3 y57 + y60 L
Y de números enteros:
In[30]:= FactorInteger@192492352D
Out[30]= 882, 6<, 813, 3<, 837, 2<<
In[31]:= 26 133 372
Out[31]= 192492352
Se pueden obtener sumas infinitas:
In[32]:= ⠀€€€€€€
¥
1
n=2
Out[32]=
n2
1
€€€€ H-6 + Π2 L
6
otro ejemplo:
In[33]:= ⠀€€€€€€€€€€€€€€
¥
1
n2
+5
!!!!
!!!!
!!!!
!!!!
!!!!
!!!!
5 M I2 ä + 5 M CschA 5 ΠE I-15 Π CoshA 5 ΠE + 8 5 SinhA 5 ΠEMM ‘
!!!!
!!!!
!!!!
I45 5 I-ä + 5 M Iä + 5 MM
n=2
Out[33]= -II-2 ä +
Aunque no siempre convergen:
In[34]:= ⠀€€€
¥
n=2
1
n
Sum::div : Sum does not converge.
Out[34]= ⠀€€€
¥
n=2
1
n
Las derivadas se pueden expresar explícitamente:
In[35]:= D@Sin@Exp@Cos@a xDDD, xD
Out[35]= -a ãCos@a xD Cos@ãCos@a xD D Sin@a xD
O con la notación abreviada:
In[36]:= Sin ’@xD
Out[36]= Cos@xD
In[37]:= Tan ’’@xD
Out[37]= 2 Sec@xD2 Tan@xD
Las integrales definidas se calculan simbólicamente, no numéricamente sumando áreas:
In[38]:= à
1
0
4
€€€€€€€€€€€€ â x
1+x
Out[38]= 4 Log@2D
In[39]:= à
1
0
4
€€€€€€€€€€€€€€€ â x
1 + x2
Out[39]= Π
Lo que nos permite que los extremos sean símbolos:
In[40]:= à
t
1
1
€€€€€€€€€€€€ â x
1+x
Out[40]= -Log@2D + Log@1 + tD
In[41]:= %  Simplify
Out[41]= LogA €€€€€€€€€€€€ E
1+t
2
(El símbolo % representa el resultado anterior)
Si deseamos integrales numéricas hacemos lo siguiente:
In[42]:= à
1
0
4
€€€€€€€€€€€€ â x  N
1+x
Out[42]= 2.77259
In[43]:= IntegrateA €€€€€€€€€€€€ , 8x, 0, v<E
4
1+x
Out[43]= 4 Log@1 + vD
Se pueden aplicar transformaciones trigonométricas:
In[44]:= Sin@34 xD
Out[44]= Sin@34 xD
In[45]:= %  TrigExpand
Out[45]= 34 Cos@xD33 Sin@xD - 5984 Cos@xD31 Sin@xD3 + 278256 Cos@xD29 Sin@xD5 -
5379616 Cos@xD27 Sin@xD7 + 52451256 Cos@xD25 Sin@xD9 286097760 Cos@xD23 Sin@xD11 + 927983760 Cos@xD21 Sin@xD13 1855967520 Cos@xD19 Sin@xD15 + 2333606220 Cos@xD17 Sin@xD17 1855967520 Cos@xD15 Sin@xD19 + 927983760 Cos@xD13 Sin@xD21 286097760 Cos@xD11 Sin@xD23 + 52451256 Cos@xD9 Sin@xD25 - 5379616 Cos@xD7 Sin@xD27 +
278256 Cos@xD5 Sin@xD29 - 5984 Cos@xD3 Sin@xD31 + 34 Cos@xD Sin@xD33
Las reglas de simplificación son muy potentes. Por ejemplo, pueden deshacer la anterior expansión:
In[46]:= %  Simplify
Out[46]= Sin@34 xD
La integración simbólica permite abordar la solución de ecuaciones diferenciales:
In[47]:= DSolve@f ’@xD Š k, f@xD, xD
Out[47]= 88f@xD ® k x + C@1D<<
In[48]:= DSolve@8f ’’@xD Š w2 f@xD, f@0D Š 1<, f@xD, xD
Out[48]= 88f@xD ® ã-w x H1 - C@2D + ã2 w x C@2DL<<
Mathematica dispone de todas las funciones necesarias para efectuar eficientemente cálculo matricial. Por ejemplo,
el producto matricial y matriz vector se representa mediante "." (Dot):
In[49]:= m1 = Table@i + j, 8i, 3<, 8j, 4<D
Out[49]= 882, 3, 4, 5<, 83, 4, 5, 6<, 84, 5, 6, 7<<
In[50]:= m1  MatrixForm
i2 3 4 5z
y
j
j
z
j
j
z
j3 4 5 6z
z
k4 5 6 7{
Out[50]//MatrixForm=
In[51]:= Hm2 = Table@i + j2 , 8i, 4<, 8j, 2<DL  MatrixForm
Hm1.m2L  MatrixForm
5y
z
z
6z
z
z
z
z
7z
z
z
8{
i2
j
j
j
3
j
j
j
j
j
j
j4
k5
Out[51]//MatrixForm=
54 96 y
i
j
z
j
z
j
j
z
j 68 122 z
z
k 82 148 {
Out[52]//MatrixForm=
Es posible automatizar que las matrices se muestren como tales y no como listas de listas...
In[53]:= MakeBoxes@x_ ? MatrixQ, StandardFormD := ToBoxesž MatrixForm ž x
Off@MatrixQ::argtD
In[55]:= m1
i2 3 4 5y
z
z
4 5 6z
z
z
j
k4 5 6 7{
j
j
Out[55]= j
j
j3
Al ser un entorno de cálculo simbólico, tiene la ventaja de que los elementos de las matrices pueden ser símbolos:
In[56]:= m = J
Out[56]= J
1 a
N
c 7
1 a
N
c 7
In[57]:= Transpose@mD
Out[57]= J
1 c
N
a 7
In[58]:= Inverse@mD
7
€€
i €€€€€€€€
7-a c
j
Out[58]= j
j
j
k - €€€€€€€€
7-a c€€
c
a
- €€€€€€€€
€€ z
7-a c y
z
z
z
1
€€€€€€€€
7-a c€€ {
No confundamos el producto elemento a elemento (*):
In[59]:= m * Inverse@mD
7
i €€€€€€€€
€€
j
7-a c
j
Out[59]= j
j
j
c2
€€
k - €€€€€€€€
7-a c
a
- €€€€€€€€
€€ y
7-a c z
z
z
z
z
7
€€€€€€€€
€
€
7-a c {
2
Con el producto de matrices (.):
In[60]:= m.Inverse@mD
7
ac
i €€€€€€€€
7-a c€€ - €€€€€€€€
7-a c€€
j
Out[60]= j
j
j
k
0
In[61]:= %  Simplify
Out[61]= J
0
7
€€€€€€€€
€€
7-a c
-
ac
€€€€€€€€
€€
7-a c
y
z
z
z
z
{
1 0
N
0 1
Muchos más ejemplos pueden consultarse en la ayuda del sistema.
Ÿ Reglas de transformación estructural
La descripción de los algoritmos en Mathematica se hace mediante un estilo de programación diferente a C.
Aunque es posible usar construcciones de tipo for, while, etc., para controlar la asignación de valores a variables de
acuerdo con la lógica del algoritmo (estilo "imperativo"), Mathematica está orientado hacia un estilo de programación llamado "funcional" y, sobre todo, a la descripción de los algoritmos mediante lo que podemos llamar
transformación estructural basada en "pattern matching" (reconocimiento de patrones sintácticos, o "esquemas de
expresión").
El siguiente ejemplo muetra la aplicación de una regla de transformación muy simple. La notación "/." es un
convenio para indicar que la expresión de la izquierda se va a transformar de acuerdo con la regla de la derecha:
In[62]:= p + jp . p ® 3 y
Out[62]= j3 y + 3 y
Aquí solo transformamos el número 3:
In[63]:= p3 + jv+3 + 6 . 3 ® 4
Out[63]= 6 + j4+v + p4
Cuando combinamos la aplicación de reglas con pattern matching se obtiene un estilo de programación muy claro
y expresivo. Por ejemplo, para indicar que una función es lineal podemos hacer algo como:
In[64]:= f@a + g@cD + bD . f@x_ + y_D ® f@xD + f@yD
Out[64]= f@aD + f@b + g@cDD
Pero la regla se ha aplicado solo una vez. Es mejor:
In[65]:= f@a + g@cD + bD . f@x_ + y_D ® f@xD + f@yD
Out[65]= f@aD + f@bD + f@g@cDD
donde //. significa que la regla se aplica hasta que la expresión no cambie.
La parte izquierda de una regla es un patrón: un esquema de expresión donde algunas partes, indicadas con un
símbolo subrayado, representan variables o "comodines" que coinciden con cualquier expresión. La parte derecha
de la regla indica cómo se construye la expresión resultante recomponiendo trozos de la expresión original
(denotados por los símbolos anteriores, ya sin subrayar).
La parte izquierda de una regla es un patrón: un esquema de expresión donde algunas partes, indicadas con un
símbolo subrayado, representan variables o "comodines" que coinciden con cualquier expresión. La parte derecha
de la regla indica cómo se construye la expresión resultante recomponiendo trozos de la expresión original
(denotados por los símbolos anteriores, ya sin subrayar).
En lugar de aplicar reglas concretas en cada caso, en la práctica resulta más cómodo suministrar reglas que se
deberán aplicar siempre que sea posible, en forma de definiciones.
Ÿ Definiciones
En lenguajes de programación imperativos, del estilo de C, las variables son contenedores de números (o de
códigos de otros objetos), y las funciones se definen para que admitan unos parámetros y devuelvan resultados de
un cierto tipo. En Mathematica la filosofía es diferente: la programación consiste en asociar a cada símbolo un
conjunto de reglas que se deben aplicar siempre, automáticamente.
Cuando evaluamos una asignación del tipo
In[66]:= a = 2
Out[66]= 2
Lo que hacemos es crear la regla a ®2 que se aplicará siempre:
In[67]:= a + a
Out[67]= 4
Una nueva asignación como
In[68]:= a = 3 + b
Out[68]= 3 + b
sustituye la regla a®2 por a®3+b.
In[69]:= a2
Out[69]= H3 + bL2
Podemos interpretar lo anterior como que en Mathematica las variables no tienen un tipo predeterminado y fijo
(como en C, que deben ser int, double, etc.) sino que pueden tomar como valor cualquier expresión. En realidad lo
que hacemos es introducir una regla de transformación automática asociada a ese símbolo.
Este concepto se lleva a sus últimas consecuencias en lo que podríamos considerar como la definición de funciones. En este caso, lo que se hace es crear una serie de reglas automáticas para un símbolo, con patrones que hacen
referencia a posibles argumentos. Si evaluamos la siguiente asignación:
In[70]:= sincos@x_D := Sin@xD + Cos@xD
definimos la función sincos, pero lo que estamos haciendo en realidad es crear la regla
sincos@x_D ® Sin@xD + Cos@xD y solicitar que sea evaluada siempre que sea posible.
Observa el operador de asignación ":=" (dos puntos igual). Más adelante explicaremos la diferencia con "=". Por el
momento basta saber que en la mayoría de las situaciones en que definimos funciones usamos ":=",y cuando
asignamos variables usamos "=".
La función ya está disponible:
In[71]:= sincos@3D
Out[71]= Cos@3D + Sin@3D
In[72]:= sincos@2 ΠD
Out[72]= 1
In[73]:= [email protected]
Out[73]= -0.848872
In[74]:= Plot@sincos@xD, 8x, 0, 2 Π<D
1
0.5
1
2
3
4
5
6
-0.5
-1
Out[74]= … Graphics …
A veces la definción de una función debe tener en cuenta casos particulares:
In[75]:= sinc@0D = 1;
Sin@xD
sinc@x_D := €€€€€€€€€€€€€€€€€€
x
Observa que
In[77]:=
Sin@xD
€€€€€€€€€€€€€€€€€€ . x ® 0
x
General::dbyz : Division by zero.
1
Power::infy : Infinite expression €€€€€ encountered.
0
Out[77]= Indeterminate
Y que
Sin@xD
In[78]:= LimitA €€€€€€€€€€€€€€€€€€ , x ® 0E
x
Out[78]= 1
Las expresiones se evalúan hasta donde sea posible:
In[79]:= ? sinc
Global‘sinc
sinc@0D = 1
Sin@xD
sinc@x_D := €€€€€€€€
€€€€€€
x
In[80]:= sinc@2 + 3 + a + b * bD
Out[80]=
Sin@8 + b + b2 D
€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€
€€€€€
8 + b + b2
En general, las definiciones consisten de varias reglas, para considerar diferentes casos de interés:
In[81]:= fact@0D = 1;
fact@n_D := n fact@n - 1D
En C se utilizaba la construcción "if" para determinar la acción a tomar. En Mathematica también se utiliza, pero
muchas veces es más claro dar diferentes reglas para cada tipo de argumento.
Ÿ Diferencia entre = e :=
La diferencia entre los operadores ":=" y "=" es la siguiente:
"=" define una regla cuya parte derecha se evalúa en mismo momento de la definición.
":=" define una regla cuya parte derecha se evalúa en el momento de usar la regla.
In[83]:= a = 10100 ;
b := 10100
Lo que guardamos es:
In[85]:= ? a
Global‘a
a=
1000000000000000000000000000000000000000000000000000000000000000000000000000000000000
„
0000000000000000
In[86]:= ? b
Global‘b
b := 10100
El resultado de la evaluación es el mismo
In[87]:= a
Out[87]= 1000000000000000000000000000000000000000000000000000000000000000000000000000„
0000000000000000000000000
In[88]:= b
Out[88]= 1000000000000000000000000000000000000000000000000000000000000000000000000000„
0000000000000000000000000
Pero a ya lo tiene precalculado, y b lo tiene que calcular cada vez que se utilice.
En general usaremos := en la definición de funciones y = para definir símbolos como si fueran variables con un
valor
In[89]:= Remove@"Global‘*"D
Ÿ Patrones avanzados
En muchos casos es conveniente especificar en un patrón secuencias de argumentos, condiciones de los elementos
de una estructura, etc. Consideremos la anterior definción de fact:
In[90]:= fact@0D := 1
fact@n_D := n fact@n - 1D
El problema es que fracasa con números negativos o números no enteros:
In[92]:= [email protected]
$RecursionLimit::reclim : Recursion depth of 256 exceeded.
$RecursionLimit::reclim : Recursion depth of 1024 exceeded.
Out[92]= 3.4049139272933 ´ 10492 Hold@[email protected] - 1DD
Vamos a mejorarla un poco. Primero borramos todas las reglas asociadas a fact:
In[93]:= Clear@factD
Y damos la nueva definición:
In[94]:= fact@0D := 1
fact@n_Integer? PositiveD := n fact@n - 1D
La regla sólo "se dispara" en los casos permitidos:
In[96]:= [email protected]
Out[96]= [email protected]
In[97]:= fact@4D
Out[97]= 24
In[98]:= fact@-4D
Out[98]= fact@-4D
(Podríamos añadir una regla que recogiese el resto de los casos indicando un error.)
El símbolo ? indica que el elemento de un patrón tiene que cumplir una condición. Por ejemplo x_?OddQ hace
coincidencia con un número impar, al que se denota por x.
Por ejemplo, la función OddQ detecta números impares:
In[99]:= OddQ@5D
Out[99]= True
In[100]:= OddQ@6D
Out[100]= False
Esto nos permite definir una función con valores diferentes según sea el argumento par o impar:
g@n_ ? EvenQD := n  2
In[101]:= g@n_ ? OddQD := 3 n + 1
Funciona como deseamos:
In[103]:= g@3D
Out[103]= 10
In[104]:= g@4D
Out[104]= 2
Dado cualquier símbolo del sistema (no de los definidos por nosotros, al menos en principio) podemos obtener
ayuda sobre él pinchando encima y pulsando F1. P.ej. pruébalo con OddQ. También se puede pedir ayuda mediante la orden "Information" o símplemente con "?":
In[105]:= ? OddQ
OddQ@exprD gives True if expr is an odd integer, and False otherwise.
La interrogación también sirve para mostrar las reglas que hemos asocidado a un símbolo:
In[106]:= ? g
Global‘g
g@n_ ? OddQD := 3 n + 1
n
g@n_ ? EvenQD := €€€
€
2
(se usa el mismo símbolo para las condiciones de los patrones y para pedir información sobre un símbolo)
Continuamos con los patrones avanzados. Un símbolo detrás del subrayado indica el tipo de cabeza que tiene que
tener la expresión para que haya coincidencia.
La siguiente función f está definida para argumentos que sean listas o que sean q[.]
In[107]:= f@x_ListD := Reverse@xD
f@x_qD := 1 + x
Cuando el argumento es un número no hay definición para f:
In[109]:= f@3D
Out[109]= f@3D
Cuando es una lista se dispara primera regla:
In[110]:= f@81, 2, 3<D
Out[110]= 83, 2, 1<
Para lo siguiente tampoco tenemos una definición:
In[111]:= f@h@3DD
Out[111]= f@h@3DD
Pero sí para esto:
In[112]:= f@q@3DD
Out[112]= 1 + q@3D
La siguiente definición usa patrones con secuencias de argumentos:
Definimos una regla para s que se dispare cuando el argumento es una lista de 1 ó más elementos, todos ellos numeros.
In[113]:= s@a : 8__ ? NumberQ<D := Apply@Plus, aD
La función Apply sirve para cambiar la cabeza de una expresión por la que nosotros deseemos. Fíjate que al cambiar a una lista de cosas la cabeza
List por la cabeza Plus, fabricamos una expresión en la que se van a sumar los elementos de la lista.
In[114]:= s@810, 5, 18<D
Out[114]= 33
Observa el proceso de evaluación:
In[115]:= Trace@s@810, a, 18<DD  ColumnForm
8NumberQ@10D, True<
8NumberQ@aD, False<
s@810, a, 18<D
Out[115]= s@810, a, 18<D
Se comprueba si los argumentos de la lista son todos números, después se fabrica la expresión de suma y se evalúa.
Con otro tipo de argumentos el símbolo s se queda sin evaluar:
In[116]:= s@3D
Out[116]= s@3D
In[117]:= s@81, a, 3<D
Out[117]= s@81, a, 3<D
x_ se refiere a una sola expresión, x_ _ se refiere a una o más expresiones y x _ _ _ se refiere a cero o más expresiones. El resultado es una "secuencia desnuda", que automáticamente desaparece cuando va metida en cualquier
otra expresión:
In[118]:= r@x__D := Reverse@8x<D
In[119]:= r@a, b, cD
Out[119]= 8c, b, a<
In[120]:= q@x__D := x
In[121]:= q@a, b, cD
Out[121]= Sequence@a, b, cD
In[122]:= f@q@a, b, cDD
Out[122]= f@a, b, cD
Borramos:
In[123]:= Remove@"Global‘*"D
à Programación Funcional
El estilo de programación convencional, "imperativo", está basado en la modificación de los contenidos de ciertas
"variables" mediante construcciones de control de flujo. Las asignaciones no son "igualdades" en el sentido
matemático del término y, por tanto, el orden de las instrucciones es fundamental para la corrección del programa.
El análisis de un programa no es sencillo, dado que existe un "estado" de las variables, que va cambiando, y que
modifica el efecto que tendrá cada instrucción en distintos momentos de un programa.
El estilo de "programación funcional" trata de aproximarse a la práctica matemática usual, donde se utilizan
"definiciones" de objetos que luego podrían sustituirse en cualquier otro punto del programa sin afectar a su
funcionamiento (transparencia referencial). No existe el concepto de "variable" a la que podamos asignar un valor,
y la ejecución del programa consiste ú nicamente en la evaluación de funciones que con la misma entrada siempre
producirán la misma salida. Se han inventado muchos lenguajes funcionales. Uno particularmente atractivo es
Haskell, que posee evaluación "no estricta" y una forma restringida pero muy práctica de pattern matching. La
evaluación no estricta (perezosa) permite trabajar de forma muy elegante con estructuras potencialmente infinitas
de las que se calcularán sólo los términos necesarios. El pattern matching se usa para expresar las definiciones de
"definiciones" de objetos que luego podrían sustituirse en cualquier otro punto del programa sin afectar a su
funcionamiento (transparencia referencial). No existe el concepto de "variable" a la que podamos asignar un valor,
y la ejecución del programa consiste ú nicamente en la evaluación de funciones que con la misma entrada siempre
producirán la misma salida. Se han inventado muchos lenguajes funcionales. Uno particularmente atractivo es
Haskell, que posee evaluación "no estricta" y una forma restringida pero muy práctica de pattern matching. La
evaluación no estricta (perezosa) permite trabajar de forma muy elegante con estructuras potencialmente infinitas
de las que se calcularán sólo los términos necesarios. El pattern matching se usa para expresar las definiciones de
una función en diferentes tipos de entrada de manera mucho más clara que usando preguntas explícitas. Este
lenguaje y otros de su estilo son muy prácticos para el prototipado rápido de muchos problemas de programación
típicos, a veces sin demasiada pérdida de eficiencia. Sin embargo, por ahora no disponen del conjunto de bibliotecas matemáticas necesarias para el cálculo científico ni permiten manipular cómodamente expresiones matemáticas
arbitrarias.
Mathematica incluye muchas construcciones de programación funcional. En realidad,es el estilo de programación
recomendado y eficiente para este sistema (aunque la sintaxis no es siempre tan elegante y concisa como p.ej. la de
Haskell). La evaluación es estricta (más próxima a la programación convencional) por lo que las estructuras
siempre tienen un tamaño finito concreto y se evalú an completamente aunque sólo necesitemos una parte de ellas
(esto solo significa que tenemos que ser un poco más cuidadosos al programar). Por otro lado, el "motor" de
pattern matching es tremendamente potente y eficiente, permitiendo patrones de una gran complejidad y poder
expresivo, imprescindibles en un entorno de cálculo simbólico.
Veamos algunos ejemplos de programación funcional. En primer lugar vamos a definir funciones numéricas
sencillas. En todos los casos se sustituye la iteración y la asignación por recursión.
Potencias enteras:
In[124]:= pot@n_, 0D := 1
pot@n_, m_D := n pot@n, m - 1D
Máximo común divisor:
In[126]:= mcd@x_, 0D := x
mcd@x_, y_D := mcd@y, Mod@x, yDD
Cualquier función (no solo el ejemplo típico del factorial) se puede expresar de esta forma. Sin embargo, el enorme
poder expresivo de la programación funcional se manifiesta en la manipulación de expresiones estructuradas,
especialmente listas.
Cualquier operación de manipulación de listas se puede expresar en términos de las primitivas First, Rest, y
Prepend (históricamente, "cons").
First devuelve el primer elemento de la lista y Rest la lista sin el primer elemento. Prepend[a,l] añade como cabeza a l. Por cuestiones de
eficiencia,dependiendo de la implementación,muchas operaciones de listas se hacen directamente, sin recurrir a las primitivas básicas.
Longitud de una lista (por supuesto,disponemos de la primitiva Length):
In[128]:= lon@8<D := 0
lon@8a_, b___<D := 1 + lon@8b<D
Otra posiblidad:
In[130]:= lon2@8<D := 0
lon2@x_D := 1 + lon2@Rest@xDD
Suma de los elementos de una lista:
In[132]:= sumalist@8<D := 0
sumalist@x_D := First@xD + sumalist@Rest@xDD
Una construcción funcional muy importante es Map. Map[f,list] construye una lista que contiene el resultado de
aplicar una función f a cada elemento.
In[134]:= Map@Sqrt, 81, 4, 9, 100, 144<D
Out[134]= 81, 2, 3, 10, 12<
Como se usa mucho tiene la abreviatura /@ :
In[135]:= Sqrt ž 81, 4, 9, 100, 144<
Out[135]= 81, 2, 3, 10, 12<
¿Cómo definirías Map?
Apply es otro ejemplo de construcción funcional. Simplemente cambia la "cabeza" de una expresión. Sirve p.ej.
para pasar a una función una lista de argumentos que están en una lista. El símbolo @@ es una abreviatura de
Apply:
Cálculo de factorial mediante cambio de cabeza a la lista de números:
In[136]:= Times žž Range@5D
Out[136]= 120
Definimos una función que calcula la media de los elementos de una lista.
Plus žž x
In[137]:= med@x_ListD := €€€€€€€€€€€€€€€€
€€€€€€€€€€€
Length@xD
In[138]:= med@84, 8, 16, 32<D
Out[138]= 15
In[139]:= med@810, 20, c<D
Out[139]=
30 + c
€€€€€€€€€€€€€€€
3
Es posible definir funciones "puras", sin nombre (expresiones de "lambda" cálculo):
In[140]:= Function@algo, algo2 + 1D
Out[140]= Function@algo, algo2 + 1D
A esa función se le pasan argumentos entre corchetes, igual que a las demás:
In[141]:= Function@algo, algo2 + 1D@5D
Out[141]= 26
Se puede abreviar con la notación & (Function) y # (el argumento):
In[142]:= H#2 + 1 &L@5D
Out[142]= 26
Range construye una lista desde 1 hasta el valor deseado:
In[143]:= Range@5D
Out[143]= 81, 2, 3, 4, 5<
En el siguiente ejemplo aplicamos una función pura:
In[144]:= #2 + 1 & ž Range@10D
Out[144]= 82, 5, 10, 17, 26, 37, 50, 65, 82, 101<
(Curiosamente, podemos derivar funciones puras:)
In[145]:= Function@x, 2 x2 + 3 Cos@xDD ’
Out[145]= Function@x, 4 x - 3 Sin@xDD
In[146]:= Log@#D & ’’
1
#1
Out[146]= - €€€€€€€€€€
2 &
Otra construcción funcional importante es Select, que sirve para extraer de una lista los elementos que cumplan un
predicado:
In[147]:= Select@Range@100D, PrimeQD
Out[147]= 82, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97<
Una alternativa es usar Cases, que selecciona elementos teniendo en cuenta no un predicado sino un patrón, y
adema´s permite transormarlo en el resultado. Es muy función muy potente:
In[148]:= Cases@881, 2<, 3, 85, 7<, 8<, x_ListD
Out[148]= J
1 2
N
5 7
In[149]:= Cases@881, 2<, 3, 85, 7<, 8<, x_List ¦ Length@xDD
Out[149]= 82, 2<
Usamos la flecha ¦ (se teclea como :>) para que la parte derecha de la regla se evalúe al usar la regla (análogamente a :=) y no en el momento de
definirla.
In[150]:= Cases@881, 2<, 3, 83, 4, 5<, 85, 7<, 8<, 8a_, b_< ® b2 D
Out[150]= 84, 49<
Aunque como tal no se usa mucho en la práctica, la función Fold es una de las herramientas básicas de la programación funcional. La mejor manera de explicar su funcionamiento es pensar que Fold[f,x,list] cambia la "coma" de
separación de los elementos de la lista por la función f, y como primer valor usa x:
In[151]:= Fold@f, x, 8a, b, c<D
Out[151]= f@f@f@x, aD, bD, cD
In[152]:= Fold@Plus, 3, 8a, b, c<D
Out[152]= 3 + a + b + c
Existe el correspondiente FoldList, que devuelve en una lista todos los pasos:
In[153]:= FoldList@Plus, x, 8a, b, c<D
Out[153]= 8x, a + x, a + b + x, a + b + c + x<
Ejercicio: calcular la distribución empírica (acumulada) de un conjunto de observaciones aleatorias. (¿un "one−liner"?mejor no...).
Usando variantes de Fold podemos escribir muchísimos algoritmos y funciones típicas.
Nest sirve para "anidar" funciones:
In[154]:= Nest@h, x, 5D
Out[154]= h@h@h@h@h@xDDDDD
In[155]:= Nest@1  H1 + #L &, x, 20D
Out[155]=
1
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€
1
1 + €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€
1
1+ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€
1
1+ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€
1 €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
1+ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€
1
1+ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€
1
1+ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€
€€€€€€€€€€
1
1+ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€
1 €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
1+ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€
1
1+ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€
€€€€€€€€
€€€€
1
1+ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€
1
1+ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€
€€€€€€€€€
1
1+ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€
1 €€€€€€€€€€€€€€€€
1+ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€
€€€€€€€€€€€€€€€€€€€€€
1 €€€€€€€€€€€€€€€€
1+ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€€€
1 €€€€€€€€€€€€
1+ €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€
€€€€€€
1 €€€€€€€€€€€€
1+ €€€€€€€€€€€€€€€€
€€€€€€€€
€€€€€€€€
1
1+ €€€€€€€€€€€€€€€€
€€€€€€€€
€€€€€€
1
1+ €€€€€€€€€€€€€€€€
€€€€€
1
1+ €€€€
€€€€€€€
1+x
Los puntos fijos de funciones se calculan mediante FixedPoint:
In[156]:= FixedPoint@Sqrt, 0.5D
Out[156]= 1.
Se puede construir una lista de los valores por los que va pasando:
In[157]:= FixedPointList@Sqrt, 2.D
Out[157]= 82., 1.41421, 1.18921, 1.09051, 1.04427, 1.0219, 1.01089, 1.00543, 1.00271,
1.00135, 1.00068, 1.00034, 1.00017, 1.00008, 1.00004, 1.00002, 1.00001,
1.00001, 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.<
Podemos aprovechar para experimentar con la función g que definimos antes:
La volvemos a definir (por si acaso la habíamos borrado)
g@n_ ? EvenQD := n  2
In[158]:= g@n_ ? OddQD := 3 n + 1
Se cree que esta función aplicada repetidamente desde cualquier número siempre acaba por caer a 1. Vamos a
comprobarlo en algunos casos. Primero definimos una función que comprueba la conjetura con un cierto número.
NestWhileList sirve para hacer llamadas anidadas, guardando los resultados en una lista, mientras se cumpla una
condición:
In[160]:= conj@n_D := NestWhileList@g, n, # ¹ 1 &D
Probamos la conjetura con algunos valores. Por ejemplo con 11 se regresa pronto al 1:
In[161]:= conj@11D
Out[161]= 811, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1<
In[162]:= conj@11D  Length
Out[162]= 15
Con 27 tarda algo más en regresar, pero lo hace:
In[163]:= conj@27D
Out[163]= 827, 82, 41, 124, 62, 31, 94, 47, 142, 71, 214, 107, 322, 161, 484,
242, 121, 364, 182, 91, 274, 137, 412, 206, 103, 310, 155, 466, 233,
700, 350, 175, 526, 263, 790, 395, 1186, 593, 1780, 890, 445, 1336,
668, 334, 167, 502, 251, 754, 377, 1132, 566, 283, 850, 425, 1276, 638,
319, 958, 479, 1438, 719, 2158, 1079, 3238, 1619, 4858, 2429, 7288,
3644, 1822, 911, 2734, 1367, 4102, 2051, 6154, 3077, 9232, 4616, 2308,
1154, 577, 1732, 866, 433, 1300, 650, 325, 976, 488, 244, 122, 61,
184, 92, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1<
Vamos a representar gráficamente lo que tardan en regresar los 1000 primeros valores (tarda un poco en calcularlo). Primero construimos una lista con las longitudes:
In[164]:= lon = Table@Length@conj@jDD, 8j, 2, 3000<D;
Luego la representamos. ListPlot sirve para representar gráficamente los elementos de una lista.
In[165]:= ListPlot@lonD
200
150
100
50
500
1000 1500 2000 2500 3000
Out[165]= … Graphics …
Parece que hay cierta textura...
Podemos modificar la representación dando opciones de dibujo a la orden ListPlot. En este caso saco los primeros
100 elementos de la lista y los muestro con los puntos unidos por líneas. La opción PlotRange sirve para que
aparezcan en el dibujo todos los puntos, incluyendo los más extremos.
In[166]:= ListPlot@Take@lon, 100D, PlotJoined ® True, PlotRange ® AllD
120
100
80
60
40
20
20
40
60
80
100
Out[166]= … Graphics …
Borramos:
In[167]:= Remove@"Global‘*"D
Es conveniente estudiar en la ayuda todas las construcciónes funcionales.
Ejercicio: intentar la definición recursiva, funcional, de la transpuesta de una matriz.
Ÿ Construcciones de control de flujo de tipo imperativo
Por supuesto, disponemos de las construcciones de programación usuales (for, if, etc.):
In[168]:= For@i = 1, i £ 5, i ++, Print@2i DD
2
4
8
16
32
Cuando necesitamos definir variables locales usamos la construcción Module:
In[169]:= mcd@n_, m_D := Module@8a, b, r<,
If@n > m, a = n; b = m,
a = m; b = nD;
While@Hr = Mod@a, bDL ¹ 0,
a = b;
b = rD;
Return@bDD
In[170]:= mcd@100, 150D
Out[170]= 50
Sin embargo muchas veces es mejor usar otras construcciones más naturales del lenguaje.
Borramos:
In[171]:= Remove@"Global‘*"D
à Listas, matrices, dot
Los "arrays" (listas) se construyen mediante Table y se accede a sus elementos con doble corchete [[ ]]:
In[172]:= m = Table@2i , 8i, 0, 10<D
Out[172]= 81, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024<
Si las listas contienen únicamente enteros o reales, internamente se usa una representación muy eficiente.
In[173]:= m@@4DD
Out[173]= 8
Muchas operaciones se realizan sobre todos los elementos de una lista:
In[174]:= m + 10
Out[174]= 811, 12, 14, 18, 26, 42, 74, 138, 266, 522, 1034<
In[175]:= Attributes@PlusD
Out[175]= 8Flat, Listable, NumericFunction, OneIdentity, Orderless, Protected<
La suma es asociativa, se mete en las "listas", si acepta números dará números, Plus[1] = 1, conmutativa
In[176]:= 2m
Out[176]= 82, 4, 16, 256, 65536, 4294967296,
18446744073709551616, 340282366920938463463374607431768211456,
115792089237316195423570985008687907853269984665640564039457584007913129639„
936,
134078079299425970995740249982058461274793658205923933777235614437217640300„
73546976801874298166903427690031858186486050853753882811946569946433649006„
084096,
179769313486231590772930519078902473361797697894230657273430081157732675805„
50096313270847732240753602112011387987139335765878976881441662249284743063„
94741243777678934248654852763022196012460941194530829520850057688381506823„
42462881473913110540827237163350510684586298239947245938479716304835356329„
624224137216<
In[177]:= Log@2, 2m D
Out[177]= 81, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024<
El producto de matrices y el producto matriz vector se representa con un punto: (o la función Dot)
Creamos dos matrices:
In[178]:= m1 = Table@i * j, 8i, 2<, 8j, 3<D
Out[178]= J
1 2 3
N
2 4 6
La matriz es una lista de listas, pero también se puede representar como
In[179]:= m2 = Table@ij , 8i, 3<, 8j, 4<D
i1 1 1 1 z
y
z
4 8 16 z
z
z
j
k 3 9 27 81 {
j
j
Out[179]= j
j
j2
Calculamos su producto matricial:
In[180]:= m1.m2
Out[180]= J
14 36 98 276
N
28 72 196 552
El producto matriz vector también usa el punto:
In[181]:= m1.81, 2, 3<
Out[181]= 814, 28<
Importante:
a) No se distingue entre vectores fila o columna.
b) Dot funciona para "tensores" matrices multidimensionales de cualquier número de dimensiones...
Disponemos de operaciones matriciales usuales:
In[182]:= m3 = m2.Transpose@m2D
30
120 y
i 4
z
z
z
340
1554
z
j
z
120
1554
7380
k
{
j
j
Out[182]= j
j
j 30
In[183]:= Inverse@m3D
27
€
i €€€€€
j
8
j
j
j
5
j
Out[183]= j
€€€
€
j
j
j 4
j
5
k €€€€€
24€
5
- €€€
€
4
y
z
z
z
109 z
z
z
- €€€€€€€€€
€
1164 z
z
z
115 z
€€€€€€€€€
€
6984 {
5
€€€€€
€
24
105
€€€€€€€
€
194
109
- €€€€€€€€€
1164€
In[184]:= Inverse@m3D  N
-1.25
0.208333 y
i 3.375
z
z
0.541237
-0.0936426 z
z
z
j -1.25
k 0.208333 -0.0936426 0.0164662 {
j
j
Out[184]= j
j
j
Muchas operaciones matriciales funcionan también con matrices simbólicas:
In[185]:= InverseAJ
b
€
i €€€€€€€€€
-2+b
j
j
Out[185]= j
j
€
k - €€€€€€€€€
-2+b
1
1 2
NE
1 b
2
- €€€€€€€€€
€z
-2+b y
z
z
z
1
€€€€€€€€€
€
-2+b {
Ejemplo de una función Listable...
g@x_D := 8x, x<
In[186]:= SetAttributes@g, ListableD
In[188]:= g@4D
Out[188]= 84, 4<
Se "mete dentro" de un argumento de tipo lista:
In[189]:= g@8a, b, c<D
i a az
y
z
bz
z
z
j
c
c
k
{
j
j
Out[189]= j
j
jb
Esta función tiene la misma definición, pero al no tener el atributo listable no se distribuye dentro los argumentos de tipo lista:
In[190]:= h@x_D := 8x, x<
In[191]:= h@4D
Out[191]= 84, 4<
In[192]:= h@8a, b, c<D
Out[192]= J
a b c
N
a b c
Si lo deseamos, podemos trabajar con vectores fila y columna explícitos, usando matrices de una sola fila o
columna:
In[193]:= col = List ž 8a, b, c<
iay
j
z
z
j
Out[193]= j
j
z
jbz
z
kc{
In[194]:= fil = 88x, y, z<<
Out[194]= H x
y zL
In[195]:= fil.col
Out[195]= H a x + b y + c z L
El único problema es que no produce un escalar, sin una matrix 1x1.
In[196]:= col.fil
iax ay azy
z
z
by bzz
z
z
j
kcx cy cz{
j
j
Out[196]= j
j
jbx
Mejor Outer:
In[197]:= Outer@Times, 8a, b, c<, 8x, y, z<D
iax ay azy
z
z
by bzz
z
z
j
kcx cy cz{
j
j
Out[197]= j
j
jbx
In[198]:= Outer@h, 8a, b, c<, 8x, y, z<D  MatrixForm
h@a, xD h@a, yD h@a, zD y
i
j
z
j
j
z
j
h@b,
xD h@b, yD h@b, zD z
z
j
z
j
z
h@c,
xD
h@c,
yD
h@c,
zD
k
{
Out[198]//MatrixForm=
También tenemos Inner, una generalización de Dot:
In[199]:= Inner@f, 8a, b, c<, 8x, y, z<, gD
Out[199]= g@f@a, xD, f@b, yD, f@c, zDD
In[200]:= Inner@Times, 8a, b, c<, 8x, y, z<, PlusD
Out[200]= a x + b y + c z
Vamos a escribir un algoritmo conciso para generar una permutación aleatoria de números. La idea es
pegar a los números del 1 a 10 unos números aleatorios, emparejando las dos listas con Transpose.
Se ordenan y se cogen todos los segundos elementos:
In[201]:= Last ž HHTransposež 8Table@Random@D, 810<D, Range@10D<L  SortL
Out[201]= 82, 9, 8, 5, 4, 10, 1, 3, 7, 6<
Veamos el proceso paso a paso:
In[202]:= 8Table@Random@D, 810<D, Range@10D<
Out[202]= J
0.996618 0.318965 0.697993 0.0535312 0.983696 0.264338 0.268539 0.561153
1
2
3
4
5
6
7
8
In[203]:= Transpose@%D
0.996618 1 y
i
j
z
j
j
z
0.318965 2 z
j
z
j
z
j
z
j
z
j
z
0.697993
3
j
z
j
z
j
z
j
z
j
z
0.0535312
4
j
z
j
z
j
z
j
z
0.983696
5
j
z
j
z
j
z
Out[203]= j
z
j
z
0.264338
6
j
z
j
z
j
z
j
j
z
0.268539 7 z
j
z
j
z
j
z
j
z
j
z
0.561153
8
j
z
j
z
j
z
j
z
j
z
0.135592
9
j
z
j
z
k 0.765438 10 {
In[204]:= Sort@%D
i 0.0535312 4 z
y
j
j
j
z
0.135592 9 z
j
z
j
z
j
z
j
z
j
z
0.264338
6
j
z
j
z
j
z
j
z
j
z
0.268539
7
j
z
j
z
j
j
z
0.318965 2 z
j
z
j
z
z
Out[204]= j
j
j
z
0.561153 8 z
j
z
j
z
j
z
j
z
j
z
0.697993
3
j
z
j
z
j
z
j
z
j
z
0.765438
10
j
z
j
z
j
z
j
z
j
z
0.983696
5
j
z
j
z
0.996618
1
k
{
In[205]:= Last ž %
Out[205]= 84, 9, 6, 7, 2, 8, 3, 10, 5, 1<
(Por supuesto, en una biblioteca tenemos RandomPermutation)
Tenemos operaciones matriciales típicas de cálculo científico: valores y vectores propios, valores singulares, etc.
Borramos:
In[206]:= Remove@"Global‘*"D
à Ajuste de mínimo error cuadrático
En Mathematica podemos resolver cómodamente ajustes de mínimos cuadrados.
In[207]:= datos = Table@8x, x2 + Random@Real, 8-2, 2<D<, 8x, 0, 5, .1<D;
Mostramos los primeros:
In[208]:= Take@datos, 5D
0
i
j
j
j
0.1
j
j
j
j
Out[208]= j
0.2
j
j
j
j
j
j
j 0.3
k 0.4
-1.96865 y
z
z
-1.85859 z
z
z
z
z
0.206314 z
z
z
z
z
-1.61708 z
z
z
0.575433 {
In[209]:= g1 = ListPlot@datosD
25
20
15
10
5
1
2
3
Out[209]= … Graphics …
In[210]:= sol = Fit@datos, 81, x<, 8x<D
Out[210]= -4.63811 + 5.09923 x
4
5
In[211]:= g2 = Plot@sol, 8x, -2, 7<D
30
20
10
-2
2
4
6
-10
Out[211]= … Graphics …
Es muy cómodo unir los dos gráficos de manera consistente:
In[212]:= Show@g1, g2D
30
20
10
-2
2
4
6
-10
Out[212]= … Graphics …
El ajuste lineal es inadecuado. Vamos a probar con un polinomio de orden mayor:
In[213]:= sol2 = Fit@datos, 81, x, x2 , x3 , x4 <, 8x<D
Out[213]= -1.49295 + 3.65777 x - 2.03306 x2 + 0.905784 x3 - 0.0877753 x4
In[214]:= g3 = Plot@sol2, 8x, -2, 7<D
30
20
10
-2
2
-10
-20
Out[214]= … Graphics …
4
6
In[215]:= Show@g1, g3D
30
20
10
-2
2
4
6
-10
-20
Out[215]= … Graphics …
Por supuesto, en este caso el polinomio adecuado es de orden 2, pero esto puede no saberse en situaciones reales.
Podemos comparar las dos soluciones:
In[216]:= Show@g1, g2, g3D
30
20
10
-2
2
4
6
-10
-20
Out[216]= … Graphics …
El problema también puede resolverse fácilmente programando la solución en el lenguaje de Mathematica. Pero en este caso resulta mucho más
conveniente utilizar la función incorporada Fit.
Borramos:
In[217]:= Remove@"Global‘*"D
à Gráficos
Son expresiones como las demás, pero hay funciones que, como efecto colateral, las muestran.
Las expresiones gráficas combinan en listas anidadas primitivas gráficas (puntos, líneas, etc.) y directivas gráficas
(tamaños, colores, ancho, etc.):
In[218]:= dibu = 8
8RGBColor@1, 0.5, 0D, [email protected], Point@81, 4<D, Point@8-2, 2<D<,
8RGBColor@1, 0, 1D, AbsoluteThickness@2D,
Line@880, 0<, 81, 0<, 81, 1<, 80, 1<, 80, 0<<D<
<;
In[219]:= Graphics@dibuD  Show@#, AspectRatio ® Automatic, Frame ® TrueD &;
4
3
2
1
0
-2 -1.5 -1 -0.5
0
0.5
1
También hay primitivas 3D. (Y visores OpenGL gratuitos.)
Se pueden exportar los objetos gráficos a cualquier formato (jpeg, eps, etc.).
à Otras cosas
Se puede invocar una función de varias maneras:
In[220]:= Sqrt@4D
Out[220]= 2
In[221]:= Sqrt ž 4
Out[221]= 2
In[222]:= 4  Sqrt
Out[222]= 2
Los corchetes son los más seguros porque no hay problema de ambigüedad. Las dos barras sirven para tomar toda la expresión de la izquierda y
aplicar finalmente una función.
En una celda podemos poner varias expresiones que se evaluarán una detrás de otra. Si no deseamos mostrar el resultado de una expresión
ponemos punto y coma detrás.
In[223]:= 2 + 2
3 + 3;
4+4
Out[223]= 4
Out[225]= 8
Cuando estamos corrigiendo la definición de un símbolo que tenga varias reglas asociadas, conviene poner Clear al principio para que cada vez que
se evalúe el juego de definiciones, las reglas anteriores, erróneas, se borren. Si no se hace así puede ser que en las pruebas se obtengan
resultados incorrectos.
In[226]:= f@x_IntegerD := 3 x
In[227]:= f@3D
Out[227]= 9
Si ahora cambiamos la definición
In[228]:= f@x_D := 2 x
El resultado no cambia porque toma la regla anterior que es más específica:
In[229]:= f@3D
Out[229]= 9
Las dos reglas coexisten:
In[230]:= [email protected]
Out[230]= 6.
En estos casos conviene borrar al principio las definiciones del símbolo para que se quede sólo con las definiciones explícitamente evaluadas
después.
In[231]:= Clear@fD
f@x_D := 2 x
In[233]:= f@3D
Out[233]= 6
Por supuesto, en programas grandes conviene organizar un documento con secciones de definición, de ejemplos de uso, etc.
Borramos:
In[234]:= Remove@"Global‘*"D
Descargar