Acuerdo de Einstein y einsum

Sorprendentemente, en el segmento de idioma ruso de Internet, casi no hay material que explique el acuerdo de suma de Einstein en un lenguaje comprensible . No es menos sorprendente que haya incluso menos materiales para comprender cómo funciona la función einsum en Internet de habla rusa. En inglés hay una respuesta bastante detallada sobre el trabajo de einsum en el desbordamiento de la pila, y en ruso solo hay unos pocos sitios que proporcionan una traducción curva de esta misma respuesta. Quiero solucionar este problema con la falta de materiales e invitar a todos los que estén interesados ​​a leerlo.






Discutiendo el Acuerdo de Einstein

En primer lugar, me gustaría señalar que el acuerdo de Einstein se usa con mayor frecuencia en el análisis de tensores y sus aplicaciones, por lo tanto, más adelante en el artículo habrá varias referencias a los tensores.

Cuando recién comienza a trabajar con tensores, puede confundirse al saber que, además de los subíndices habituales, también se utilizan superíndices, que al principio generalmente se pueden tomar como exponenciación. Ejemplo:

"a con superíndice i" se escribirá como a ^ yo, y "a en un cuadrado con superíndice i" se escribirá (a ^ i) ^ 2. Puede resultar confuso e incómodo al principio, pero puede acostumbrarse con el tiempo.





Acuerdo: más adelante en el artículo, objetos del tipo a_ix_io a_ix ^ ilos llamaré términos .





¿De qué trata el acuerdo de Einstein?

El acuerdo de Einstein está diseñado para reducir el número de signos de suma en una expresión. Hay tres reglas simples que determinan qué tan correcta se escribe una expresión en la notación de Einstein.





Regla # 1: La suma se lleva a cabo sobre todos los índices que se repiten dos veces en un término.



Ejemplo: considere una expresión como esta:





\ sum_ {i = 1} ^ 3 a_ix_i = a_1x_1 + a_2x_2 + a_3x_3

Usando la convención de Einstein, esta expresión se puede reescribir así:





a_ix_i \ text {o} a_ix ^ i

Por lo tanto, nos deshacemos del signo de suma y solo escribimos un solo término. Nótese que en este término el índice i se repite dos veces, lo que significa que, de acuerdo con la primera regla, entendemos que la suma se realiza sobre el índice i, o mejor dicho, sobre todos los valores posibles que toma este índice.







: A \ in \ mathbb {R} ^ {m \ times n} v \ in \ mathbb {R} ^ {n}. b \ in \ mathbb {R} ^ {m}. :





b_i = \ sum \ limits_ {j = 1} ^ n A_ {ij} v_j, ~ i = 1, \ ldots, m

:





b_i = A_ {ij} v_ {j} = A_ {ij} v ^ {j}

, i , j , , j.





1. , , .





2. , .





, , ,





  1. .





  2. , .





, Python:





for i in range(M):
    for j in range(N):
        b[i] += A[i, j] * v[j]
      
      



, , . j , i – . . j .





№ 2. .





, a_ {ij} b_ {ij}, a_ {ii} b_ {ij} a_ {ij} b_ {jj}, , .

:





a_i ^ i– i , .. ;





a_i ^ {jj}– i , j – ;





a_ {ii} ^ {jj}– i, j ;





a_ {ij} ^ {ij}– i, j ;





a_ {ii} ^ {ij}– ( i );





, , , . :





a_ {ij} b_ {i} + a_ {ji} b_ {j}

, , . , , , i 3 , j, , , ( ), , .





№ 3. , .





:





b_i = A_ {ij} v_ {j}– , i , ;





a_i = A_ {ki} B_ {kj} x_ {j} + C_ {ik} u_ {k}– . : k j , , , i , , . k , i – , , k – , i – . i , , . : i , , 3 .





, :





x_i = A_ {ij}– i , i j;





x_j = A_ {ik} u_k– j, i. ;





x_i = A_ {ik} u_k + c_j– i, i, j;





:

A – . , :





A_ {i_1i_2i_3i_4i_5} = \ sum_ {j_4 = 1} ^ {R_4} \ sum_ {j_3 = 1} ^ {R_3} \ sum_ {j_2 = 1} ^ {R_2} \ sum_ {j_1 = 1} ^ {R_1} G ^ {(1)} _ {i_1j_1} G ^ {(2)} _ {j_1i_2j_2} G ^ {(3)} _ {j_2i_3j_3} G ^ {(4)} _ {j_3i_4j_4} G ^ {(5)} _ {j_4i_5}

, G ^ {(k)}, Rhode Island. – . , .

, i_1, i_2, i_3, i_4, i_5, , j_1, j_2, j_3, j_4. , , , , . , G ^ {(k)}, (k). , , . :





A_ {i_1i_2i_3i_4i_5} = \ left (G ^ {(1)} \ right) _ {i_1j_1} \ left (G ^ {(2)} \ right) _ {i_2j_2} ^ {j_1} \ left (G ^ {( 3)} \ derecha) _ {i_3j_3} ^ {j_2} \ izquierda (G ^ {(4)} \ derecha) _ {i_4j_4} ^ {j_3} \ izquierda (G ^ {(5)} \ derecha) _ { i_5} ^ {j_4}

, !





einsum

einsum , Python (NumPy, TensorFlow, PyTorch). , , ( , ), , einsum . NumPy. einsum . , , , , .





: A \ in \ mathbb {R} ^ {3 \ times5}, B \ in \ mathbb {R} ^ {5 \ times2} – , . M \ in \ mathbb {R} ^ {3 \ times2}, , :





M_ {ij} = \ sum_ {k = 1} ^ {5} A_ {ik} B_ {kj} = A_ {ik} B_ {kj}

. , :





M = np.zeros((3, 2))
for i in range(3):
    for j in range(2):
        for k in range(5):
            M[i, j] += A[i, k] * B[k, j]
      
      



, einsum :





M = np.einsum("ik,kj->ij", A, B)
      
      



, . einsum : , . :





"{, },{, }->{, }"





einsum :





  • ( ), ;





  • , ;





  • 3 ;





, einsum , , , . , , , , einsum . , einsum.





, einsum:





einsum,

1. :





vector = np.array([1, 2, 3, 4, 5])
result = np.einsum("i->", vector)
print(result)
      
      



Output

15





2. :





matrix = np.array([[1, 2], [3, 4], [5, 6]])
result = np.einsum("ij->", matrix)
print(result)
      
      



Output

21





3. :





matrix = np.array([[1, 2], [3, 4], [5, 6]])
result = np.einsum("ij->j", matrix)
print(result)
      
      



Output

[9, 12]





4. :





matrix = np.array([[1, 2], [3, 4], [5, 6]])
result = np.einsum("ij->i", matrix)
print(result)
      
      



Output

[3, 7, 11]





5. ( , , , ):





matrix = np.array([[1, 2], [3, 4], [5, 6]])
result = np.einsum("ij->ji", matrix)
print(result)
      
      



Output

[[1, 3, 5], [2, 4, 6]]





6. :





matrix = np.array([[1, 2], [3, 4], [5, 6]])
vector = np.array([[1, 2]])
result = np.einsum("ij,kj->ik", matrix, vector)
print(result)
      
      



, 1 \ por 2, , . einsum , , , .





Output

[[5], [11], [17]]





7. :





matrix1 = np.array([[1, 2], [3, 4], [5, 6]])
matrix2 = np.array([[1, 0], [0, 1]])
result = np.einsum("ik,kj->ij", matrix1, matrix2)
print(result)
      
      



Output

[[1, 2], [3, 4], [5, 6]]





8. :





vector1 = np.array([[1, 2, 3]])
vector2 = np.array([[1, 1, 1]])
result = np.einsum("ik,jk->", vector1, vector2)
print(result)
      
      



Output

6





9. :





matrix1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
result = np.einsum("ii->", matrix1)
print(result)
      
      



Output

15





10. () :





matrix1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
matrix2 = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
result = np.einsum("ij,ij->ij", matrix1, matrix2)
print(result)
      
      



, , : , einsum – :





result = np.zeros(matrix1.shape, dtype="int32")
for i in range(result.shape[0]):
    for j in range(result.shape[1]):
        result[i, j] += matrix1[i, j] * matrix2[i, j]
print(result)
      
      



Output

[[1, 0, 0], [0, 5, 0], [0, 0, 9]]





11. () :





vector1 = np.array([1, 2, 3])
vector2 = np.array([1, 0, 0])
result = np.einsum("i,j->ij", vector1, vector2)
print(result)
      
      



Output

[[1, 0, 0], [2, 0, 0], [3, 0, 0]]





12. :





A = np.array([[[0, 1], [1, 2], [2, 3]], [[1, 2], [2, 3], [3, 4]], [[2, 3], [3, 4], [4, 5]]])
result = np.einsum("ijk->jki", A)
print(result)
      
      



Output

[[[0, 1, 2], [1, 2, 3]], [[1, 2, 3], [2, 3, 4]], [[2, 3, 4], [3, 4, 5]]]





13. :





A = np.array([[[0, 1], [1, 2], [2, 3]], [[1, 2], [2, 3], [3, 4]], [[2, 3], [3, 4], [4, 5]]])
U = np.array([[1, 2], [2, 3]])
result = np.einsum("ijk,nk->ijn", A, U)
print(result)
      
      



Output

[[[2, 3], [5, 8], [8, 13]], [[5, 8], [8, 13], [11. 18]], [[8, 13], [11, 18], [14, 23]]]





, einsum . , (np.dot, np.outer, np.tensordot, np.transpose, np.cumsum ..), einsum. , , , , , .





einsum ( ).





Acuerdo de Einstein (base)





Acuerdo de Einstein (parte avanzada)








All Articles