Skip to the content.

Contenido

Introducción a Python

En este taller utilizaremos el lenguaje de programación Python junto con algunas de sus bibliotecas especializadas, para expresar y manipular las matemáticas relacionadas con matrices y vectores de manera eficiente. El objetivo principal es introducir herramientas útiles para implementar métodos numéricos enfocados en la resolución de sistemas de ecuaciones diferenciales ordinarias.

Revisaremos una serie de comandos y funciones que demuestran cómo trabajar de forma práctica y estructurada con escalares, vectores y matrices.

Para interactuar con el contenido de esta introducción a Python, acceda al siguiente enlace de Google Colab.

Asignación de variables

a = 1
b = 2; c = 3 # puede usar ; para definir variables en la misma linea
suma = b + c

Puedes utilizar la función print() para visualizar el valor de un objeto, ya sea una variable, un vector, una matriz u otro tipo de dato.

print(suma)
5

El uso de vectores y matrices es esencial para este resultado de aprendizaje. Por ello, utilizaremos la biblioteca NumPy, diseñada específicamente para cálculos numéricos y análisis de datos, especialmente cuando se trabaja con grandes volúmenes de información.

import numpy as np # llamada a la librería numpy:

A continuación, utilizaremos algunas funciones básicas para generar rápidamente arrays (vectores y matrices).

x = np.linspace(0,3,4)
print('x=',x) # vector fila (array de 1 dimensión) que contiene 4 números reales equidistantes desde el 0 al 3.
x = np.linspace(0,1,100) # Aquí se redefine el vector x, ya no tendremos acceso al vector x = [0 1 2 3].
print('x=',x)
x= [0. 1. 2. 3.]
x= [0.         0.01010101 0.02020202 0.03030303 0.04040404 0.05050505
 0.06060606 0.07070707 0.08080808 0.09090909 0.1010101  0.11111111
 0.12121212 0.13131313 0.14141414 0.15151515 0.16161616 0.17171717
 0.18181818 0.19191919 0.2020202  0.21212121 0.22222222 0.23232323
 0.24242424 0.25252525 0.26262626 0.27272727 0.28282828 0.29292929
 0.3030303  0.31313131 0.32323232 0.33333333 0.34343434 0.35353535
 0.36363636 0.37373737 0.38383838 0.39393939 0.4040404  0.41414141
 0.42424242 0.43434343 0.44444444 0.45454545 0.46464646 0.47474747
 0.48484848 0.49494949 0.50505051 0.51515152 0.52525253 0.53535354
 0.54545455 0.55555556 0.56565657 0.57575758 0.58585859 0.5959596
 0.60606061 0.61616162 0.62626263 0.63636364 0.64646465 0.65656566
 0.66666667 0.67676768 0.68686869 0.6969697  0.70707071 0.71717172
 0.72727273 0.73737374 0.74747475 0.75757576 0.76767677 0.77777778
 0.78787879 0.7979798  0.80808081 0.81818182 0.82828283 0.83838384
 0.84848485 0.85858586 0.86868687 0.87878788 0.88888889 0.8989899
 0.90909091 0.91919192 0.92929293 0.93939394 0.94949495 0.95959596
 0.96969697 0.97979798 0.98989899 1.        ]
h = 0.1 # Salto
y = np.arange(0,1,h)
print(y) # vector cuyos elementos son números reales equidistantes entre 0 y 1-h cuyo salto es h.
[0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]

Para generar una partición del intervalo $[0,1]$ que comience en $0$ y termine en $1$ a paso $h$ fijo, puede usar:

y = np.arange(0,1+h,h)
print(y)
[0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]
A = np.empty((3,3)) # tupla dimensiones (a,b): a filas, b columnas.
print(A) # Matriz con 3 filas y 3 columnas (los elementos a_{ij} se definen automáticamente)
[[0.1 0.2 0.3]
 [0.4 0.5 0.6]
 [0.7 0.8 0.9]]
A = np.zeros((2,3)) # Matriz de dimensiones 2 x 3 (2 filas y 3 columnas) con todos los elementos a_{ij} = 0.
print(A)
[[0. 0. 0.]
 [0. 0. 0.]]

Matriz de dimensión 2x3 (2 fila y 3 columnas) con todos sus elementos iguales a 1.

A = np.ones((2,3))
print(A)
[[1. 1. 1.]
 [1. 1. 1.]]

Matriz de dimensión 1x3 (1 fila y 3 columnas) con todos sus elementos iguales a 1.

A = np.ones((1,3))
print(A)
[[1. 1. 1.]]

Vector fila (matriz de 1 fila y 3 columnas) con todos sus elementos iguales a 1.

A = np.ones(3)
print(A)
[1. 1. 1.]

Vector columna (matriz de 4 fila y 1 columnas) con todos sus elementos iguales a 1.

A = np.ones((4,1))
print(A)
[[1.]
 [1.]
 [1.]
 [1.]]
A = np.full((2,4),3.0) # Matriz cuyos elementos son todos iguales a 3.0
print(A)
[[3. 3. 3. 3.]
 [3. 3. 3. 3.]]
I = np.identity(5) # Matriz identidad de orden n=5.
print(I)
[[1. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0.]
 [0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 1.]]
A = np.random.random((3,2)) # Matriz de orden 3x2 con valores aleatorios entre 0 y 1 por defecto.
print('A=',A)
B = 10*A # Multiplicación de la matriz A por el escalar 10.
print('B=',B) # Matriz de orden 3x2 con valores aleatorios entre 0 y 10.
A= [[0.29944606 0.03828226]
 [0.92151849 0.39298975]
 [0.35294774 0.92536481]]
B= [[2.99446057 0.38282262]
 [9.21518494 3.9298975 ]
 [3.52947744 9.25364814]]
A = np.random.random((5,5)) # Matriz random de orden 5
d_A = np.diag(A,0) # son los elementos de la diagonal principal de la matriz A.
print(A)
print('v=',d_A)

B = np.diag(d_A) # Crea una matriz diagonal (solo elementos en la diagonal principal) con los elementos de d_A.
print(B)
[[0.19732352 0.25025703 0.25959884 0.48983972 0.14132041]
 [0.99847553 0.47422155 0.40698131 0.48891106 0.30007843]
 [0.29969325 0.55094652 0.70773012 0.56139925 0.41237901]
 [0.74852093 0.35024552 0.94323611 0.82278904 0.55021109]
 [0.75295973 0.25838071 0.74783274 0.61744358 0.15099475]]
v= [0.19732352 0.47422155 0.70773012 0.82278904 0.15099475]
[[0.19732352 0.         0.         0.         0.        ]
 [0.         0.47422155 0.         0.         0.        ]
 [0.         0.         0.70773012 0.         0.        ]
 [0.         0.         0.         0.82278904 0.        ]
 [0.         0.         0.         0.         0.15099475]]

Existen varios atributos y funciones que permiten describir las características de un array. A continuación, se presentan algunas de las más comunes:

A = 3.1*np.ones((3,5)) # Matriz de orden 3x5 (3 filas, 5 columnas). Todos sus elementos son iguales a 3.1
print(A)
print(A.size) # número de elementos que tiene la matriz
print(A.shape) # orden de la matriz (3 filas y 5 columnas)
B = np.random.random((5,3))
print(B)
[[3.1 3.1 3.1 3.1 3.1]
 [3.1 3.1 3.1 3.1 3.1]
 [3.1 3.1 3.1 3.1 3.1]]
15
(3, 5)
[[0.42394896 0.42837491 0.89547643]
 [0.12416299 0.27471687 0.21652912]
 [0.79961267 0.11090453 0.44186001]
 [0.65961756 0.50919244 0.27390606]
 [0.20697892 0.63413266 0.4020175 ]]
print(B.T)
[[0.42394896 0.12416299 0.79961267 0.65961756 0.20697892]
 [0.42837491 0.27471687 0.11090453 0.50919244 0.63413266]
 [0.89547643 0.21652912 0.44186001 0.27390606 0.4020175 ]]

Acceso y modificación de los elementos

Para acceder a los elementos de un vector o una matriz, utilizamos la siguiente sintaxis.

Por ejemplo, si tenemos el vector:

v = [1, 3, 5, 2]

Es importante recordar que en Python los índices comienzan en 0, lo que significa que el primer elemento tiene índice 0, el segundo elemento tiene índice 1, y así sucesivamente.

v = np.random.random(4) # vector de 4 componentes generado aleatoriamente.
print(v)
[0.56554423 0.7158947  0.23732554 0.39578333]
print(v[0]) # primera componente del vector v.
0.5655442286233147
print(v[3]) # Cuarta componente del vector v.
0.3957833287291599

Podemos cambiar el valor de un elemento de un vector o matriz asignando un nuevo valor.

Por ejemplo, si tenemos el vector:

v = [1, 3, 5, 2]

Podemos modificar la tercera componente (índice 2) asignándole un nuevo valor:

v[2] = 10

Después de esta asignación, el vector v será:

v = [1, 3, 10, 2]
print(v) # vector original
[0.56554423 0.7158947  0.23732554 0.39578333]
v[2] = np.pi
print(v) # vector con la tercera componente igual a pi.
[0.56554423 0.7158947  3.14159265 0.39578333]

En forma análoga, podemos acceder a los elementos de una matriz utilizando la siguiente sintaxis:

A[i,j] (fila i, columna j).

Por ejemplo, si tenemos la matriz:

A = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

Recuerda que, al igual que con los vectores, los índices en Python comienzan en 0.

A = np.random.random((3,5))
print(A)
[[0.93974559 0.05350414 0.79262227 0.22552793 0.1799146 ]
 [0.00175417 0.44495108 0.19229064 0.05121848 0.49654071]
 [0.93650049 0.6865986  0.45940217 0.67444161 0.88872908]]
print(A[0,0]) # Elemento a_11 (fila 1 columna 1).
0.9397455885358104
print(A[2,3]) # Elemento de la fila 3 columna 4.
0.6744416056849745

Podemos cambiar un elemento de la matriz $A$ utilizando la siguiente sintaxis:

A[i,j] = b

Por ejemplo, si queremos cambiar el elemento de la segunda fila y tercera columna a 10, lo hacemos así:

A[1, 2] = 10

Además, también podemos extraer elementos de la matriz $A$ de la siguiente manera:

Por ejemplo, si tenemos:

A = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]
print(A)
[[0.93974559 0.05350414 0.79262227 0.22552793 0.1799146 ]
 [0.00175417 0.44495108 0.19229064 0.05121848 0.49654071]
 [0.93650049 0.6865986  0.45940217 0.67444161 0.88872908]]
A[2,3] = 0 # Cambié el elemento de la fila 3 columna 4 por un 0.
print(A)
[[0.93974559 0.05350414 0.79262227 0.22552793 0.1799146 ]
 [0.00175417 0.44495108 0.19229064 0.05121848 0.49654071]
 [0.93650049 0.6865986  0.45940217 0.         0.88872908]]
B = A[:,2] # Extraemos toda la información correspondiente a la columna 3 (todas las filas (:), columna 3).
print(B)
[0.79262227 0.19229064 0.45940217]
B = A[0:2,3] # Extraemos toda la información correspondiente a la fila 1 hasta la 2, columna 4.
print(B)
[0.22552793 0.05121848]
B = A[2,:] # Extraemos toda la información correspondiente a la fila 3.
print(B)
[0.93650049 0.6865986  0.45940217 0.         0.88872908]

Operaciones matemáticas con arrays a nivel de elemento a elemento

Las operaciones a nivel de elemento se aplican a los elementos que ocupan la misma posición en dos arrays. Por lo tanto, es necesario que ambos arrays tengan las mismas dimensiones. El resultado será un array con las mismas dimensiones que los originales.

Los operadores matemáticos +, -, *, /, % y ** se utilizan para realizar las siguientes operaciones a nivel de elemento:

A = np.ones((2,3))
B = np.random.random((2,3))
print(A)
print(B)
[[1. 1. 1.]
 [1. 1. 1.]]
[[0.39344805 0.72132887 0.53187417]
 [0.76542712 0.76330354 0.65035085]]
print(A+B) # Suma elemento a elemento
[[1.39344805 1.72132887 1.53187417]
 [1.76542712 1.76330354 1.65035085]]

Es importante aclarar que la operación A * B no realiza el producto matemático tradicional de matrices. En su lugar, aplica el producto elemento a elemento entre los arrays A y B. Esto significa que cada elemento de A se multiplica por el elemento correspondiente de B en la misma posición.

De manera similar, si A y B son vectores, la operación A * B tampoco calcula el producto escalar o vectorial. En cambio, realiza una multiplicación elemento a elemento entre los dos vectores.

Por ejemplo, si tenemos:

A = [
    [1, 2],
    [3, 4]
]

B = [
    [5, 6],
    [7, 8]
]

C = A * B

El resultado será:

C = [
    [1*5, 2*6],
    [3*7, 4*8]
]

Esto dará como resultado:

C = [
    [5, 12],
    [21, 32]
]

Para realizar el producto matemático tradicional de matrices, es necesario usar la función np.dot(A, B) o el operador @ en Python.

print(A/B) # División elemento a elemento.
[[2.54163163 1.3863302  1.88014393]
 [1.3064601  1.3100948  1.53763158]]
print(B**2) # Esto no es B*B. Aquí cada elemento de B se eleva a 2.
[[0.15480136 0.52031534 0.28289014]
 [0.58587868 0.5826323  0.42295622]]

Tipos de Operadores en Python

En Python, los operadores se clasifican en varias categorías dependiendo de su propósito. A continuación se presentan los principales tipos:

Operadores Aritméticos

Se usan para realizar operaciones matemáticas básicas.

Operador Descripción Ejemplo Resultado
+ Suma 5 + 3 8
- Resta 5 - 3 2
* Multiplicación 5 * 3 15
/ División 5 / 3 1.6667
% Módulo (resto) 5 % 3 2
** Potenciación 5 ** 3 125
// División entera 5 // 3 1

Operadores Relacionales

Se usan para comparar valores y retornan un valor booleano (True o False).

Operador Descripción Ejemplo Resultado
< Menor que 5 < 3 False
<= Menor o igual que 5 <= 5 True
> Mayor que 5 > 3 True
>= Mayor o igual que 5 >= 6 False
== Igualdad 5 == 3 False
!= Diferente 5 != 3 True

Operadores Lógicos

Se usan para combinar condiciones lógicas.

Operador Descripción Ejemplo Resultado
and AND lógico (5 > 3) and (5 < 10) True
or OR lógico (5 > 3) or (5 > 10) True
not NOT lógico not(5 > 3) False

Para el trabajo con vectores (por ejemplo, arrays de numpy) usar:

Operador Nombre Uso Ejemplo Descripción
& AND lógico (cond1) & (cond2) (v > 0.1) & (v < 0.4) Retorna True si ambas condiciones son verdaderas.
\| OR lógico (cond1) \| (cond2) (v < 0.1) \| (v > 0.4) Retorna True si al menos una de las condiciones es verdadera.
~ NOT lógico ~(cond) ~(v < 0.4) Invierte el resultado lógico de la condición (TrueFalse).

Operadores de Asignación

Se usan para asignar valores a variables, con combinaciones de operaciones.

Operador Descripción Ejemplo Resultado
= Asignación simple x = 5 x = 5
+= Suma y asignación x += 3 x = x + 3
-= Resta y asignación x -= 2 x = x - 2
*= Multiplicación y asignación x *= 4 x = x * 4
/= División y asignación x /= 2 x = x / 2
//= División entera y asignación x //= 3 x = x // 3
%= Módulo y asignación x %= 2 x = x % 2
**= Potencia y asignación x **= 2 x = x ** 2
&= AND bit a bit y asignación x &= 2 x = x & 2
\|= OR bit a bit y asignación x |= 2 x = x | 2
^= XOR bit a bit y asignación x ^= 3 x = x ^ 3
<<= Desplazamiento izquierda y asignación x <<= 2 x = x << 2
>>= Desplazamiento derecha y asignación x >>= 1 x = x >> 1

Operadores de Identidad

Se usan para verificar si dos objetos son iguales (mismo objeto en memoria).

Operador Descripción Ejemplo Resultado
is Verifica identidad x is y True o False
is not Verifica no identidad x is not y True o False

Operadores de Pertenencia

Se usan para verificar si un valor está presente en una colección.

Operador Descripción Ejemplo Resultado
in Verifica pertenencia "a" in "abc" True
not in Verifica no pertenencia "x" not in "abc" True
print(2<3)
True
print(5!=1)
True
print(6==3)
False
v = np.random.random(4)
print(v)
print(v>0.4)
[0.81370763 0.59142879 0.46424298 0.66206272]
[ True  True  True  True]
# Uso con vectores y matrices

v = np.array([0.2, 0.05, 0.6, 0.9])

# AND lógico (&): Elementos entre 0.1 y 0.5
and_result = (v > 0.1) & (v < 0.5)
print("AND lógico: (v > 0.1) & (v < 0.5)")
print(and_result)  # Resultado: [ True False False False]

# OR lógico (|): Elementos menores a 0.1 o mayores a 0.5
or_result = (v < 0.1) | (v > 0.5)
print("\nOR lógico: (v < 0.1) | (v > 0.5)")
print(or_result)  # Resultado: [False  True  True  True]

# NOT lógico (~): Elementos que NO son menores a 0.4
not_result = ~(v < 0.4)
print("\nNOT lógico: ~(v < 0.4)")
print(not_result)  # Resultado: [ True False  True  True]
AND lógico: (v > 0.1) & (v < 0.5)
[ True False False False]

OR lógico: (v < 0.1) | (v > 0.5)
[False  True  True  True]

NOT lógico: ~(v < 0.4)
[False False  True  True]

Estructuras de control de flujo

Ciclo for en python

El ciclo for se utiliza para recorrer los elementos de un objeto iterable (lista, tupla, conjunto, diccionario, vectores, matrices) y ejecutar un bloque de código. En cada paso de la iteración se tiene en cuenta a un único elemento del objeto iterable, sobre el cuál se pueden aplicar una serie de operaciones.

Su sintaxis es la siguiente:

for <elem> in <iterable>:
  <Tu código>

Aquí, $elem$ es la variable que toma el valor del elemento dentro de $iterable$ en cada paso del bucle. Este finaliza su ejecución cuando se recorren todos los elementos.

nums = [4, 5, 3, 25]
for n in nums:
  print(n)
4
5
3
25
a = np.arange(0,5,1) # Vector de enteros. Estas serán las posiciones de los elementos del vector b
print(a)
b = np.zeros(a.size) # Defino el vector b del mismo tamaño que el vector a pero con elementos todos iguales a 0.

for i in a:
  b[i] = i**2 + 2 # Lleno componente a componente el vector b.
print(b)
[0 1 2 3 4]
[ 2.  3.  6. 11. 18.]

Sentencias if else

“Cuando la expresión if se evalúa como True, entonces ejecuta el código que le sigue. Pero si se evalúa como False, entonces ejecuta el código que sigue después de la sentencia else .”

Su sintaxis es la siguiente:

if condicion:
  ejecutar codigo si la condicion es True
else:
  ejecutar codigo si la condicion es False
a = np.pi
b = np.exp(1)
if a < b:
    print(" b es mayor que a")
else:
    print("a es mayor que b")
a es mayor que b
coleccion = [2, 4, 5, 7, 8, 9, 3, 4]
for e in coleccion: # Note el uso del operador de identidad `is`
    if e == 7:
        break  # Break permite salir del ciclo for.
    print(e)
2
4
5
coleccion = [2, 4, 5, 7, 8, 9, 3, 4]
for e in coleccion:
    if e <= 7:
        print('True')
    else:
      print('False')
True
True
True
True
False
False
True
True

Sentencia elif

La sintaxis básica es similar a la siguiente:

if primera_condicion:
  ejecutar sentencia
elif segunda_condicion:
  ejecutar sentencia
else:
  ejecutar sentencia alternativa si todas las condiciones previas son son evaluadas como False
x = 11
if x > 10:
    print(" x es mayor que 10!")
elif x < 10:
      print("x es menor que 10!")
elif x < 20 :
      print("x es menor que 20!")
else:
     print("x es igual a 10")
 x es mayor que 10!
x = 20
if x > 10 and x < 20:
    print(" 10 < x < 20")
elif x <= 10:
      print("x <= 10")
else:
     print("x >= 20")
x >= 20

Bucle while de Python

El bucle while de Python hace que se ejecute un bloque de código repetidamente mientras una condición sea verdadera. En Python, los bucles while se utilizan principalmente cuando el número de iteraciones necesarias no viene determinado de antemano.

i = 1
while i < 6:
  print(i)
  if i == 3:
    break
  i = i + 1
1
2
3

Funciones en Python

Las funciones son una herramienta fundamental en Python que te permiten estructurar y organizar tu código de forma más eficiente. Una de sus principales ventajas es que ayudan a reducir el número total de líneas de código en tu proyecto, mejorando su legibilidad y mantenimiento.

En Python, una definición de función tiene las siguientes características:

Sintaxis básica:

def nombre_funcion():
    # Aquí va el algoritmo
    # Más instrucciones
    return  # Retorno opcional
def multiplicacion(input1, input2):
  y = input1 * input2
  return y

result = multiplicacion(3,5)

print(result)
15
def area_circulo(radio):
    """
    Calcula el área de un círculo dado su radio.

    Parámetros:
        radio (float): El radio del círculo.

    Retorna:
        float: El área del círculo.
    """
    if radio < 0:
        raise ValueError("El radio no puede ser negativo.")
    return np.pi * radio**2  # Fórmula: π * r^2
area_c = area_circulo(2)
print(area_c)
12.566370614359172

Fibonacci con la Fórmula de Binet

Aquí calculamos el n-ésimo término en la secuencia de Fibonacci utilizando la famosa Fórmula de Binet.

Secuencia de Fibonacci

La secuencia de Fibonacci es una sucesión matemática en la que cada número es la suma de los dos anteriores. Se define como:

$ F(0) = 0, \quad F(1) = 1, \quad F(n) = F(n-1) + F(n-2) \; \text{para } n \geq 2 $

Fórmula de Binet

La fórmula de Binet permite calcular directamente el valor de ( F(n) ) sin necesidad de realizar un bucle. Está definida como:

$ F(n) = \frac{\phi^n - \psi^n}{\sqrt{5}} $

Donde:

def fibonacci_binet(n):
    """
    Calcula el n-ésimo término de Fibonacci usando la fórmula de Binet.

    Parámetros:
        n (int): El índice del número de Fibonacci a calcular (debe ser >= 0).

    Retorna:
        int: El n-ésimo número de Fibonacci.
    """
    if n < 0:
        raise ValueError("El índice n debe ser un número entero no negativo.")

    # Cálculo de Fibonacci usando la fórmula de Binet
    phi = (1 + np.sqrt(5)) / 2  # Número áureo (phi)
    psi = (1 - np.sqrt(5)) / 2  # Complemento
    fibonacci = (phi**n - psi**n) / np.sqrt(5)

    return round(fibonacci)  # Redondeamos al entero más cercano

# Ejemplo de uso
n = 10
fibo_num = fibonacci_binet(n)
print(f"El {n}-ésimo término de Fibonacci es: {fibo_num}")

El 10-ésimo término de Fibonacci es: 55

Taller de Modelamiento matemático y fenómenos de evolución

  1. Construya una función en python que evalúe la función [3 pts.] $$f(x)= \begin{cases}2 \operatorname{sen}^{2}(2 x), & x \leq 0, \\ 1-\mathrm{e}^{-x}, & x>0.\end{cases}$$ Indicación: Dado un vector $x$, su función debe evaluar $f$ en cada elemento de $x$. La función debe retornar un vector $y$ del mismo tamaño con la evaluación de $f$ en cada $x_i$.
  2. Investigue la librería matplotlib y úsela para gráficar la función $f$ del problema 1. en el intervalo $[-5, 6]$. [3 pts.]
  3. Construya una función en Python, que evalúe la función: [4 pts.] $$f(x)=\begin{cases} x-1, & x \leq -2, \\ 1-x^2, & -2 < x < 0, \\ -\displaystyle\frac{1}{x+1}, & x \geq 0 \end{cases}$$ Grafique la función $f$ en $[-6,10]$.
  4. Construya una función que reciba como entrada $n$ y que genere una matriz de la forma [10 pts.] $$\boldsymbol{A}=\left(\begin{array}{cccc}2 & -1 & & 0 \\ -1 & \ddots & \ddots & \\ & \ddots & \ddots & -1 \\ 0 & & -1 & 2\end{array}\right) \in \mathbb{R}^{n \times n}.$$ Indicación: La matriz $A$ es una matriz tridiagonal, solo tiene información distinta de 0 en las tres diagonales. En el resto de posiciones los coeficientes son iguales a 0.
  5. Haga una función que reciba como entrada $n$, $varepsilon$ y $\alpha$, que genere una matriz de la forma [10 pts.] $$ A=\left(\begin{array}{cc} \alpha \mathbf{I} & \varepsilon \mathbf{1} \\ \varepsilon \mathbf{1} & \alpha \mathbf{I} \end{array}\right) \in \mathbb{R}^{2 n \times 2 n}, $$ donde $\mathbf{1}$ denota la matriz de elementos todos 1 . $\mathbf{I}$ denota a la matriz identidad de $\mathbb{R}^{n \times n}, \alpha, \varepsilon$ y $n$ deben ser parámetros de la función.
  6. Haga una función que reciba como entrada $n$ y que genere una matriz de la forma [10 pts.] $$ A=\left(\begin{array}{ccc} 2 n & & \mathbf{1}\\ & \ddots & \\ \mathbf{1} & & 2 n \end{array}\right) \in \mathbb{R}^{2 n \times 2 n} $$ donde $\mathbf{1}$ indica que los elementos fuera de la diagonal principal de la matriz $A$ son unos.
  7. Haga una función que genere una matriz de la forma
  8. a) Diseñe una función en Python que reciba como entrada el orden $n$ de una matriz simétrica cuyas entradas son definidas por: [5 pts.] \[ A_{ij} = \begin{cases} i + j, & \text{si } i \neq j, \\ 2i, & \text{si } i = j. \end{cases} \] b) Análogamente, construya una función en Python que dado $n$ entregue la matriz $E \in \mathbb{R}^{n \times n}$ donde cada entrada $E_{ij}$ se defina como: [5 pts.] \[ E_{ij} = i^2 - j^2. \]
  9. Usando la fórmula: [10 pts.]

    \[ \frac{\sin(x + h) - \sin(x)}{h}, \] aproxime la derivada de $\sin(x)$ (es decir, $\cos(x)$) en $x = 0.5$, usando $h = 10^{-p}$ para $p = 1, \ldots, 10$ y calcule el error al usar esta aproximación.