sábado, 10 de junio de 2023

Superficie en forma de silla de montar representada con GNU MAXIMA

Representemos la función de dos variables reales: $f(x,y)=-x^2+y^2$ para comprobar que tiene la forma anunciada en el título de la entrada:

(%i19)	
    plot3d(-x^2 + y^2, [x, -3, 3], [y,-2,2],[legend, false]);

$\diamond$

-oOo-

Utilidades:

  [1] GNU MAXIMA

jueves, 8 de junio de 2023

Algoritmo de multiplicación de dos matrices cuadradas de orden 3. Implementación en lenguaje Python

ENUNCIADO. Sean dos matrices cuadradas de orden $3$: $A=(a_{ij})_{3 \times 3}$ y $B=(b_{ij})_{3 \times 3}$. Sabemos que el producto $A\,B$, viene dado por $\displaystyle A\,B=(c_{ij})_{3 \times 3}=\sum_{k=1}^{3} a_{ik}\cdot b_{kj}$ para $i=1,2,3$ y $j=1,2,3$. Escríbase un programa en Python para multiplicar dos de esas matrices, elegidas libremente.

SOLUCIÓN

def multiplicar_matrices(A, B):
    C = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
    
    for i in range(3):
        for j in range(3):
            for k in range(3):
                C[i][j] += A[i][k] * B[k][j]
    
    return C

# Ejemplo de matrices de orden 3
A = [[1, 0, -1],
           [2, 1, 3],
           [-2, 0, -1]]

B = [[4, 1, 0],
           [5, -5, 0],
           [3, 2, 1]]

# Llamada a la función para multiplicar las matrices
C = multiplicar_matrices(A, B)

# Imprimir el resultado C
for fila in C:
    print(fila)

Puesta en marcha del programa y resultado:

>>> %Run multiplicardosmatricesdeorden3.py
[1, -1, -1]
[22, 3, 3]
[-11, -4, -1]
$\diamond$

-oOo-

Utilidades:

  [1] El software básico para trabajar con Python: https://www.python.org/
  [2] Un entorno de trabajo: https://thonny.org/
  [3] Un compilador en línea: https://www.tutorialspoint.com/online_python_compiler.php

miércoles, 7 de junio de 2023

Cosas que pasan cuando se empieza a trabajar con una herramienta CAS

Un ejemplo con GNU MAXIMA:

(%i1)	/* Habiendo asignado un valor concreto a la variable
	x ...*/
	x:3$
	
(%i2)	/* Quiero calcular, a continuación, la derivada 
	de una función, de variable x, por ejemplo ... */
	diff(x^2+x+1,x);
    
	/* y me encuentro con el siguiente problema: 
    MAXIMA nos dice ... */
    
       diff: second argument 
       must be a variable; found 3
       -- an error. 
       To debug this try: debugmode(true);

(%i3)	/* Para solucionarlo (no hace falta entrar en el modo
        depuración de código), basta con borrar la asignación
	    de valor que, en un principio 
        había realizado a la variable */ 
    
	kill(x)$

(%i4)	/* Ahora sí podré obtener la derivada ...*/
	diff(x^2+x+1,x);

(%o4)	2*x+1

$\diamond$

-oOo-

Utilidades:

  [1] GNU MAXIMA

Toda matriz cuadrada puede expresarse de manera única como la suma de una matriz cuadrada simétrica y una matriz cuadrada hemisimétrica

Proposición

Pruébese que siendo $Q$ cualquier matriz cuadrada de orden $n$, no nula. Entonces, es posible escribir $Q=S+H$ de manera única, donde $S$ es una matriz (no nula) simétrica ($S=S^\top$); y $H$ es una matriz (no nula) hemisimétrica ($H=-H^\top$), ambas de orden $n$.

Demostración

Al ser $S$ una matriz simétrica, podemos escribirla de la forma $S=\dfrac{1}{2}\,(Q+Q^\top) \quad (1)$, donde $Q$ es una matriz cualquiera. En efecto, al trasponer $S$, se tiene que $S^\top= \dfrac{1}{2}\,(Q+Q^\top)=\dfrac{1}{2}\,(Q^\top+Q)=S$, como debe ser.

Y al ser $H$ una matriz hemisimétrica, podemos escribirla de la forma $H=\dfrac{1}{2}\,(Q-Q^\top) \quad (2)$, donde, igual que antes, $Q$ es una matriz cualquiera. En efecto, al trasponer $H$, se tiene que $H^\top= \dfrac{1}{2}\,(Q-Q^\top)=\dfrac{1}{2}\,(Q^\top-Q)=-\dfrac{1}{2}\,(Q-Q^\top)=-H$, como debe ser.

De lo arriba dicho se sigue que, sumando miembro a miembro, las igualdades (1) y (2), se tiene que $S+H=\dfrac{1}{2}\,(Q+Q^\top)+\dfrac{1}{2}\,(Q-Q^\top)=\dfrac{1}{2}\,(Q+Q+Q^\top-Q^\top)=\dfrac{1}{2}\cdot 2\,Q=Q$.

Veamos ahora que dicha descomposición $Q=S+H$ es única. Empecemos suponiendo lo contrario, entonces existe una matriz simétrica $S'\neq S$ y una matriz hemisimétrica $H'\neq H$ tales que $Q$ también puede expresarse como $Q=S'+H'$, entonces $Q=S+H=S'+H'$, y, por tanto, $(S+H)^\top=(S'+H')^\top$, esto es, $S^\top+H^\top=S'^\top+H'^\top$, y de ahí se sigue que $S-H=S'-H'$, luego $S-S'=H-H' \Leftrightarrow S-S'=H-H'=O$ (matriz nula), con lo cual $S=S'$ y $H=H'$, en contra de la hipótesis de partida.$\square$

Ejemplo

Cálculos efectuados con GNU Octave (la notación prima como instrucción indica la traspuesta de una matriz)
>> Q=[1,2,3;-1,0,2;2,1,1]
Q =

   1   2   3
  -1   0   2
   2   1   1

>> S=(Q+Q')/2
S =

   1.0000   0.5000   2.5000
   0.5000        0   1.5000
   2.5000   1.5000   1.0000

>> H=(Q-Q')/2
H =

        0   1.5000   0.5000
  -1.5000        0   0.5000
  -0.5000  -0.5000        0

>> S+H
ans =

   1   2   3
  -1   0   2
   2   1   1

$\diamond$

martes, 6 de junio de 2023

Otra manera de obtener los números primos mayores o iguales que $2$ y menores que $1000$. Algoritmo de Eratóstenes

Obtención de los números primos mayores o iguales que $2$ y menores que $1000$ implementado el algoritmo de la criba de Eratóstenes, escribiendo el programa correspondiente en lenguaje Python:

def criba_eratostenes(n):
    # Inicializar una lista de booleanos de tamaño n+1
    # donde cada elemento se considera inicialmente primo
    primes = [True] * (n + 1)
    primes[0] = primes[1] = False  # 0 y 1 no son primos

    p = 2
    while p * p <= n:
        # Si primes[p] es verdadero, entonces es primo
        if primes[p]:
            # Actualizamos todos los múltiplos de p como no primos
            for i in range(p * p, n + 1, p):
                primes[i] = False
        p += 1

    # Recopilamos todos los números primos en una lista
    prime_numbers = [num for num, is_prime in enumerate(primes) if is_prime]
    return prime_numbers

# Encontramos los números primos entre 2 y 1000
primes = criba_eratostenes(1000)

# Imprimimos los números primos encontrados
print("Números primos entre 2 y 1000:")
print(primes)


Ponemos en marcha el programa:
Resultado:
  >>> %Run cribadeeratostenes.py
Y se obtiene el resultado: Números primos entre 2 y 1000: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]

$\diamond$

Un ejercicio con matrices del tipo triangular inferior

ENUNCIADO. Sean $a,b,c,d$ números reales, la matriz triangular inferior $A=\begin{pmatrix}a&0\\ b&a\end{pmatrix}$ no nula y la matriz triangular inferior $B=\begin{pmatrix}c&0\\ d&c\end{pmatrix}$ no nula (nótese que los elementos de las diagonales principales son tales que $A_{11}=A_{22}=a$ y $B_{11}=B_{22}=c$). Compruébese que, así definidas, las matrices $A$ y $B$ conmutan.

SOLUCIÓN. Los cálculos simbólicos los he realizado con ayuda de la herramienta CAS, GNU MAXIMA [1]

(%i28)	A:matrix( [a,0],[b,a]   ); /* Defino una matriz genérica A */
(%o28)	matrix(
		[a,	0],
		[b,	a]
	)
(%i29)	B:matrix( [c,0],[d,c]   ); /* Defino una matriz genérica B */
(%o29)	matrix(
		[c,	0],
		[d,	c]
	)
(%i30)	is(A.B=B.A); /* Compruebo si conmutan. Nótese que en MAXIMA 
                      es necesario usar el punto bajo (.)
                      para la multiplicación de matrices 
                      en lugar del punto elevado (·), pues éste
                      multiplica elemento a elemnto; tal cosa
                      da lugar a muchas confusiones */
(%o30)	true /* en efecto, así es */


(%i31)	A.B; /* Observo el por qué */
(%o31)	matrix(
		[a*c,	0],
		[a*d+b*c,	a*c]
	)
(%i32)	B.A;
(%o32)	matrix(
		[a*c,	0],
		[a*d+b*c,	a*c]
	)
(%i33)	A.B-B.A;
(%o33)	matrix(
		[0,	0],
		[0,	0]
	)
$\diamond$

-oOo-

Utilidades:

  [1] GNU MAXIMA

¿Cómo saber si un número (el que primero se nos ocurra) es primo? ¿Cómo encontrar los números primos menores que un cierto número (pongamos que 1000)?

Aquí tenéis un algoritmo básico y el código del programa correspondiente en lenguaje Python [1]

def es_primo(numero):
    if numero < 2:
        return False
    for i in range(2, int(numero ** 0.5) + 1):
        if numero % i == 0:
            return False
    return True

# Ejemplo de uso:
numero = int(input("Ingrese un número: "))
if es_primo(numero):
    print(numero, "es un número primo.")
else:
    print(numero, "no es un número primo.")

-oOo-

Y para encontrar los números primos mayores o iguales que $2$ y menores que $1000$, podéis escribir y hacer funcionar el siguiente programa en vuestro intérprete de Python (los hay que podéis utilizar en línea, sin instalar software de desarrollo en vuestro ordenador como, por ejemplo, éste [3]: https://www.tutorialspoint.com/online_python_compiler.php):

  def es_primo(numero):
    if numero < 2:
        return False
    #la búsqueda acaba en la raíz cuadrada del número introducido más una unidad
    for i in range(2, int(numero ** 0.5) + 1):
        if numero % i == 0:
            return False
    return True

primos = []
for num in range(2, 1001):
    if es_primo(num):
        primos.append(num)

print("Números primos hasta 1000:")
print(primos)
  

Al poner en marcha el programa, a cuyo archivo le he dado el nombre de numerosprimos.py, >>> %Run numerosprimos.py
Nota: el símbolo >>> indica el prompt de la cónsola de vuestro entorno de desarrollo (fuera de línea, he utilizado el IDE Thonny [2] (habiendo instalado préviamente Python [1]), que es software libre, y es de fácil uso)
Podéis comprobar que se obtiene (rápidamente, en pocos segundos) ...
Números primos hasta 1000: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]
>>> $\diamond$

-oOo-

Utilidades:

  [1] El software básico para trabajar con Python: https://www.python.org/
  [2] Un entorno de trabajo: https://thonny.org/
  [3] Un compilador en línea: https://www.tutorialspoint.com/online_python_compiler.php