Álgebra lineal#
¡Bienvenido/a al segundo notebook del curso de Computación Científica! En esta sesión, nos adentraremos en el mundo del Álgebra Lineal Computacional utilizando NumPy, una de las bibliotecas más poderosas de Python para manejar operaciones numéricas, especialmente con matrices y vectores. Aprenderemos desde lo básico hasta descomposiciones de matrices aplicadas a la resolución de problemas.
#1. Introducción a NumPy NumPy es una biblioteca que facilita las operaciones matemáticas avanzadas y el manejo eficiente de grandes cantidades de datos numéricos en Python. Su componente central es el array (o arreglo), que es similar a las listas de Python, pero con características más potentes para realizar cálculos en múltiples dimensiones.
##1.1 Instalación y uso de NumPy Para utilizar NumPy en Google Colab o en tu entorno local, primero debes importar la biblioteca de la siguiente manera:
import numpy as np
A partir de ahora, cada vez que veas np, sabrás que estamos usando la funcionalidad de NumPy.
##1.2. Creación de arrays en NumPy Un array es la estructura fundamental de NumPy, y puede ser de una o más dimensiones.
# Esto tiene formato de código
###1.2.1. Crear arrays desde listas Puedes convertir listas normales de Python en arrays de NumPy de la siguiente forma:
Vector (1D array):
vector = np.array([1, 2, 3])
print("Vector:\n", vector)
Matriz (2D array):
matriz = np.array([[1, 2], [3, 4]])
print("Matriz:\n", matriz)
##1.3 Funciones útiles de NumPy NumPy nos proporciona varias funciones útiles para crear matrices y vectores. Vamos a ver algunas de ellas:
np.zeros()
: Crea una matriz o vector llena de ceros.
ceros = np.zeros((3, 3))
print("Matriz de ceros:\n", ceros)
np.ones()
: Crea una matriz o vector llena de unos.
unos = np.ones((2, 4))
print("Matriz de unos:\n", unos)
np.random.rand()
: Genera una matriz o vector con números aleatorios entre 0 y 1.
aleatorio = np.random.rand(3, 3)
print("Matriz aleatoria:\n", aleatorio)
Estas funciones son útiles para inicializar matrices con valores específicos, lo que puede ser útil en simulaciones o análisis numéricos.
#2. Operaciones básicas con matrices y vectores ##2.1. Suma y resta de vectores y matrices NumPy nos permite realizar operaciones básicas como la suma y resta de matrices y vectores de manera eficiente. Es importante recordar que para estas operaciones, las dimensiones de los arrays deben coincidir.
Suma de vectores:
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
suma_vectores = a + b
print("Suma de vectores:\n", suma_vectores)
Suma de matrices:
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
suma_matrices = A + B
print("Suma de matrices:\n", suma_matrices)
##2.2. Producto punto (dot product) El producto punto es una operación muy importante en álgebra lineal, que combina dos vectores en un solo número. También se aplica entre matrices.
Producto punto entre dos vectores:
Para dos vectores ( a ) y ( b ):
Ejemplo con los vectores ( a = [1, 2, 3] ) y ( b = [4, 5, 6] ):
En NumPy, podemos calcular esto fácilmente:
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
producto_punto = np.dot(a, b)
print("Producto punto entre vectores:\n", producto_punto)
Producto punto de matrices:
Para dos matrices ( A ) y ( B ):
El resultado es una nueva matriz calculada como la suma de los productos correspondientes de filas y columnas.
Calculando con NumPy:
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
producto_matrices = np.dot(A, B)
print("Producto punto entre matrices:\n", producto_matrices)
2.3. Multiplicación de Matrices#
Además del producto punto entre matrices, también es posible multiplicar matrices en su sentido general, donde el número de columnas de la primera matriz debe coincidir con el número de filas de la segunda. La multiplicación de matrices es fundamental en álgebra lineal y tiene múltiples aplicaciones en ciencias computacionales, análisis de datos, transformaciones geométricas, entre otros.
Regla de multiplicación de matrices:#
Dados dos matrices ( A ) de dimensión ( m \times n ) y ( B ) de dimensión ( n \times p ), el producto ( C = A \cdot B ) es una matriz de dimensión ( m \times p ). El elemento en la posición ( (i, j) ) de la matriz ( C ) se calcula como:
Esto significa que para cada elemento de la matriz resultante, tomamos el producto de la fila ( i ) de la matriz ( A ) con la columna ( j ) de la matriz ( B ) y sumamos los productos.
Ejemplo de multiplicación de matrices:#
Consideremos dos matrices ( A ) y ( B ):
El producto de estas matrices es:
En NumPy:#
Podemos calcular la multiplicación de matrices de forma sencilla con NumPy usando la función np.matmul()
o el operador @
.
# Definimos las matrices
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# Multiplicación de matrices
C = np.matmul(A, B)
print("Producto de matrices:\n", C)
# O usando el operador @
C_alt = A @ B
print("Producto de matrices (con @):\n", C_alt)
Resultado:#
La multiplicación de matrices ( A ) y ( B ) nos da:
Este concepto es ampliamente usado en aplicaciones como el análisis de datos, transformaciones geométricas y sistemas de ecuaciones lineales.
#3. Descomposición LU y su aplicación La Descomposición LU es una técnica utilizada en álgebra lineal para descomponer una matriz en dos matrices: una matriz triangular inferior (L) y una matriz triangular superior (U). Esto facilita la resolución de sistemas de ecuaciones lineales.
##3.1. Explicación matemática de la descomposición LU Dado un sistema de ecuaciones representado por la matriz ( A ):
La descomposición LU consiste en encontrar dos matrices ( L ) y ( U ) tales que:
Donde ( L ) es triangular inferior y ( U ) es triangular superior:
Resolvemos el sistema utilizando ( L ) y ( U ), lo que simplifica el proceso.
Ejemplo de Descomposición LU#
Vamos a ver un ejemplo sencillo de cómo se realiza la descomposición LU en una matriz.
Consideremos la siguiente matriz ( A ):
Queremos descomponerla en dos matrices ( L ) (triangular inferior) y ( U ) (triangular superior) tales que:
Paso 1: Definir ( L ) y ( U )#
Sabemos que ( L ) es una matriz triangular inferior y ( U ) es una matriz triangular superior, por lo tanto:
Paso 2: Igualar
\[ A = L \cdot U \]
#
Al hacer la multiplicación de las matrices ( L ) y ( U ), tenemos:
Al realizar la multiplicación de matrices:
Paso 3: Resolver el sistema#
Ahora, igualamos cada elemento de la matriz resultante con los elementos correspondientes de la matriz ( A ):
- \[ u_{11} = 4 \]
- \[ u_{12} = 3 \]
- \[ l_{21} \cdot u_{11} = 6 $$, lo que nos da $$ l_{21} = \frac{6}{4} = 1.5 \]
- \[ l_{21} \cdot u_{12} + u_{22} = 3 $$, sustituimos $$ l_{21} = 1.5 $$ y $$ u_{12} = 3 $$, lo que nos da $$ u_{22} = -1.5 \]
Por lo tanto, las matrices ( L ) y ( U ) son:
Así, hemos descompuesto ( A ) en las matrices ( L ) y ( U ).
##3.2. Introducción a módulos en Python Un módulo en Python es un archivo que contiene código (funciones, variables, clases, etc.) que podemos reutilizar en otros programas. En este caso, vamos a usar el módulo scipy para realizar la descomposición LU.
Primero, debemos importar las funciones necesarias del módulo scipy de la siguiente manera:
from scipy.linalg import lu
Aquí, lu es la función que nos permite realizar la descomposición LU.
##3.3. La matriz de permutación P En algunos casos, la matriz 𝐴 que queremos descomponer no es directamente triangular inferior o superior. Esto puede requerir una permutación de filas para poder realizar la descomposición. La matriz de permutación 𝑃 realiza intercambios de filas en 𝐴 para que la descomposición LU sea posible.
Dado un sistema de ecuaciones representado por la matriz ( 𝐴 ):
No es posible hacer una descomposición LU sin permutar las filas, porque la primera fila tiene un 0 en la primera columna. Por lo tanto, se introduce la matriz ( P ) para intercambiar las filas:
Aplicamos la permutación a ( A ):
Ahora, podemos hacer la descomposición LU de la matriz permutada ( P \cdot A ), tal que:
Ejemplo:
from scipy.linalg import lu
import numpy as np
# Definimos una matriz A que requiere una permutación para hacer la descomposición LU
A = np.array([[0, 2], [1, 3]])
# Realizamos la descomposición LU
P, L, U = lu(A)
# Mostramos los resultados
print("Matriz P (Matriz de Permutación):\n", P)
print("Matriz L (Triangular Inferior):\n", L)
print("Matriz U (Triangular Superior):\n", U)
##3.4. Resolución de sistemas con descomposición LU
Vamos a usar solve_triangular()
, que es una función de scipy para resolver sistemas triangulares. Esta función toma los siguientes argumentos:
La matriz triangular. El vector con las soluciones del sistema. El parámetro lower=True si la matriz es triangular inferior.
Ejemplo:
from scipy.linalg import solve_triangular
# Resolución de L * y = B
y = solve_triangular(L, B, lower=True)
# Resolución de U * x = y
x = solve_triangular(U, y)
print("Solución del sistema:\n", x)
#4. Autovalores y autovectores ¿Qué son?: Los autovalores y autovectores son fundamentales para entender cómo las transformaciones lineales afectan a los vectores en un espacio vectorial. Dada una matriz cuadrada 𝐴, un autovector 𝑣 y un autovalor 𝜆 cumplen la relación:
Esto significa que la acción de la matriz sobre el vector 𝑣 es simplemente escalarlo por 𝜆.
Aplicaciones:
Análisis de Componentes Principales (PCA), para reducir dimensionalidad en ciencia de datos.
Dinámica de sistemas, métodos numéricos, y física cuántica.
Estabilidad de sistemas en control.
Implementación:
import numpy as np
# Definimos una matriz cuadrada A
A = np.array([[4, 1], [2, 3]])
# Calculamos los autovalores y autovectores
valores, vectores = np.linalg.eig(A)
print("Autovalores:\n", valores)
print("Autovectores:\n", vectores)
#5. Ejemplo práctico: Optimización de recursos en una compañía Imagina que trabajas en una empresa que fabrica dos productos: Producto A y Producto B. Estos productos requieren diferentes cantidades de dos recursos limitados, Recurso 1 y Recurso 2. La empresa tiene una cantidad limitada de estos recursos, y queremos saber cuántas unidades de cada producto podemos fabricar sin exceder la disponibilidad de los recursos.
Datos del problema:
Para producir una unidad del Producto A, necesitamos:
2 unidades de Recurso 1.
1 unidad de Recurso 2.
Para producir una unidad del Producto B, necesitamos:
1 unidad de Recurso 1.
3 unidades de Recurso 2.
La empresa dispone de:
200 unidades del Recurso 1.
300 unidades del Recurso 2.
Queremos saber cuántas unidades de Producto A y Producto B podemos fabricar para utilizar exactamente los recursos disponibles.
Formulación del Problema como un Sistema de Ecuaciones
Podemos escribir este problema como un sistema de ecuaciones lineales, donde:
𝑥 es el número de unidades de Producto A que fabricamos.
𝑦 es el número de unidades de Producto B que fabricamos.
Las restricciones del problema son:
En forma matricial, esto puede representarse como:
Donde:
Resolviendo el Sistema con Python
Vamos a usar álgebra matricial en Python para resolver este sistema de ecuaciones:
import numpy as np
# Definimos la matriz A (coeficientes de los recursos por producto)
A = np.array([[2, 1], [1, 3]])
# Definimos el vector B (recursos disponibles)
B = np.array([200, 300])
# Usamos la función np.linalg.solve() para resolver el sistema de ecuaciones
X = np.linalg.solve(A, B)
# Mostramos el resultado
print(f"Unidades de Producto A: {X[0]}")
print(f"Unidades de Producto B: {X[1]}")
Matriz 𝐴: Representa los coeficientes de las ecuaciones, donde cada fila contiene las cantidades de recursos necesarios para producir una unidad de los productos.
Vector 𝐵: Representa la cantidad disponible de cada recurso (200 unidades de Recurso 1 y 300 unidades de Recurso 2).
Función np.linalg.solve()
: Esta función resuelve el sistema
𝐴⋅𝑋=𝐵, devolviendo el vector 𝑋, que contiene las soluciones
𝑥 y 𝑦, es decir, cuántas unidades de cada producto se pueden fabricar.
Al correr el código, se mostrará cuántas unidades de Producto A y Producto B debemos fabricar para optimizar el uso de los recursos.
#6. Ejercicios #6.1. Ejercicio 1: Aplicación de la descomposición LU Contexto: Supongamos que trabajas en el área de ingeniería civil y necesitas resolver un sistema de ecuaciones para calcular las fuerzas que actúan en una estructura. Estas fuerzas se modelan con un sistema de ecuaciones lineales representado por la matriz 𝐴, y utilizamos la descomposición LU para resolver el sistema.
El sistema de ecuaciones es:
Vamos a resolver este sistema de ecuaciones usando descomposición LU.
Rellena los espacios faltantes.
import numpy as __
from scipy.linalg import lu, solve_triangular
# Definimos la matriz A y el vector B
A = np.array([[2, 1], [3, 4]])
B = np.array([4, 10])
# Realizamos la descomposición LU
P, L, U = _________(A) # Función para descomposición LU
# Resolvemos el sistema paso a paso
# Resolución de L * y = B
y = solve_triangular(_____, B, lower=True) # Matriz triangular inferior (L)
# Resolución de U * x = y
x = solve_triangular(_____, y) # Matriz triangular superior (U)
print("Solución del sistema de ecuaciones: x =", _)
##6.2. Ejercicio 2: Aplicación de eigenvectores Contexto: En física cuántica, es común representar un sistema de partículas usando matrices, donde los autovalores (eigenvalores) y autovectores (eigenvectores) describen los posibles estados energéticos del sistema. Vamos a usar autovalores y autovectores para encontrar los posibles niveles de energía de una partícula en un sistema.
Dada la matriz 𝐴 que representa el operador hamiltoniano de un sistema, calcula los autovalores y autovectores.
La matriz del operador es:
import _____ as np
# Definimos la matriz A (operador hamiltoniano)
A = np.array([[5, 4], [4, 5]])
# Calculamos los autovalores y autovectores
valores, vectores = _______(A) # Función para autovalores y autovectores
print("Autovalores (Niveles de energía):", valores)
print("Autovectores (Estados cuánticos):", vectores)
##6.3. Ejercicio 3: Optimización Contexto: Imagina que estás trabajando para una empresa que produce tres productos distintos. Cada producto requiere una cierta cantidad de recursos para ser fabricado, y hay restricciones en la cantidad de recursos disponibles. Tu tarea es optimizar la producción para maximizar la cantidad de productos que puedes fabricar sin exceder los recursos.
Recursos disponibles:
Recurso 1: 500 unidades.
Recurso 2: 600 unidades.
Recurso 3: 300 unidades.
Productos:
Producto A: Requiere 2 unidades de Recurso 1, 3 de Recurso 2 y 1 de Recurso 3.
Producto B: Requiere 4 unidades de Recurso 1, 1 de Recurso 2 y 2 de Recurso 3.
Producto C: Requiere 3 unidades de Recurso 1, 2 de Recurso 2 y 1 de Recurso 3.
Debes maximizar la producción de estos tres productos, asegurando que no se excedan los recursos disponibles.
Pistas:
Define las variables 𝑥, 𝑦, 𝑧 que representen las cantidades de los productos A, B, y C respectivamente.
Escribe las restricciones como un sistema de ecuaciones lineales.
Usa álgebra matricial para resolver el sistema.
___ __ __ __#Importa la biblioteca
# Define la matriz A que representa los recursos necesarios para producir cada producto
_ _ ______ # Recurso 1
______ # Recurso 2
______ # Recurso 3
# Define el vector B que representa la disponibilidad de recursos
_ _ ______
# Resolver el sistema de ecuaciones para encontrar las cantidades óptimas de cada producto
_ _ ______
# Imprime las cantidades de productos A, B y C
_____
_____
_____
#Conclusión En este segundo notebook, hemos explorado los conceptos fundamentales del álgebra lineal aplicados a la computación científica. Usando Python y NumPy, aprendimos a manejar operaciones con matrices y vectores, así como a resolver sistemas de ecuaciones lineales mediante técnicas como la descomposición LU. Estas herramientas son cruciales en diversas áreas, desde la optimización de recursos en una empresa hasta la resolución de problemas físicos o financieros mediante autovalores y autovectores.
Con este conocimiento, puedes abordar problemas más complejos que impliquen la optimización de sistemas, análisis de datos, y otros campos donde el álgebra lineal juega un papel central. Además, los ejemplos prácticos te han mostrado cómo aplicar estos conceptos, donde las soluciones requieren tanto precisión matemática como implementación eficiente en código.
En los siguientes notebooks, seguiremos explorando otras áreas clave de la computación científica, ampliando nuestra caja de herramientas para enfrentar diversidad de problemas.