# Euclidean neural networks

## What is `e3nn`

?

`e3nn`

is a python library based on pytorch to create equivariant neural networks for the group \(O(3)\).

## Where to start?

Guide to the

`e3nn.o3.Irreps`

: Irreducible representationsGuide to implement a Convolution

The simplest example to start with is Tetris Polynomial Example.

Guide to implement a Transformer

## Demonstration

All the functions to manipulate rotations (rotation matrices, Euler angles, quaternions, convertions, …) can be found here Parametrization of Rotations.
The irreducible representations of \(O(3)\) (more info at Irreps) are represented by the class `e3nn.o3.Irrep`

.
The direct sum of multiple irrep is described by an object `e3nn.o3.Irreps`

.

If two tensors \(x\) and \(y\) transforms as \(D_x = 2 \times 1_o\) (two vectors) and \(D_y = 0_e + 1_e\) (a scalar and a pseudovector) respectively, where the indices \(e\) and \(o\) stand for even and odd – the representation of parity,

```
import torch
from e3nn import o3
irreps_x = o3.Irreps('2x1o')
irreps_y = o3.Irreps('0e + 1e')
x = irreps_x.randn(-1)
y = irreps_y.randn(-1)
irreps_x.dim, irreps_y.dim
```

```
(6, 4)
```

their outer product is a \(6 \times 4\) matrix of two indices \(A_{ij} = x_i y_j\).

```
A = torch.einsum('i,j', x, y)
A
```

```
tensor([[-0.5546, -0.1096, -0.8499, -0.1005],
[-1.3905, -0.2748, -2.1309, -0.2520],
[ 0.3184, 0.0629, 0.4880, 0.0577],
[ 0.2849, 0.0563, 0.4365, 0.0516],
[-1.1635, -0.2299, -1.7831, -0.2109],
[-2.0086, -0.3969, -3.0782, -0.3640]])
```

If a rotation is applied to the system, this matrix will transform with the representation \(D_x \otimes D_y\) (the tensor product representation).

Which can be represented by

```
R = o3.rand_matrix()
D_x = irreps_x.D_from_matrix(R)
D_y = irreps_y.D_from_matrix(R)
plt.imshow(torch.kron(D_x, D_y), cmap='bwr', vmin=-1, vmax=1);
```

This representation is not irreducible (is reducible). It can be decomposed into irreps by a change of basis. The outerproduct followed by the change of basis is done by the class `e3nn.o3.FullTensorProduct`

.

```
tp = o3.FullTensorProduct(irreps_x, irreps_y)
print(tp)
tp(x, y)
```

```
FullTensorProduct(2x1o x 1x0e+1x1e -> 2x0o+4x1o+2x2o | 8 paths | 0 weights)
```

```
tensor([-1.2602, -1.2072, -0.5546, -1.3905, 0.3184, 0.2849, -1.1635, -2.0086,
-0.5232, 0.1156, -0.4067, 2.0275, -0.3172, 0.4713, -0.0266, -0.7953,
-1.7187, 0.1669, 0.1183, -0.2442, 0.1461, -1.3303, -2.3257, -0.2972])
```

As a sanity check, we can verify that the representation of the tensor prodcut is block diagonal and of the same dimension.

```
D = tp.irreps_out.D_from_matrix(R)
plt.imshow(D, cmap='bwr', vmin=-1, vmax=1);
```

`e3nn.o3.FullTensorProduct`

is a special case of `e3nn.o3.TensorProduct`

, other ones like `e3nn.o3.FullyConnectedTensorProduct`

can contained weights what can be learned, very useful to create neural networks.