(q, r)
return torch.stack((w, x, y, z), dim=1).view(original_shape)
Multiply quaternion(s) q with quaternion(s) r.
    Expects two equally-sized tensors of shape (*, 4), where * denotes any number of dimensions.
    Returns q*r as a tensor of shape (*, 4).
Multiply quaternion(s) q with quaternion(s) r.
    Expects two equally-sized tensors of shape (*, 4), where * denotes any number of dimensions.
    Returns q*r as a tensor of shape (*, 4).
Multiply quaternion ( s ) q with quaternion ( s ) r . Expects two equally - sized tensors of shape ( * 4 ) where * denotes any number of dimensions . Returns q * r as a tensor of shape ( * 4 ) .
def qmul(q, r):
    """
    Multiply quaternion(s) q with quaternion(s) r.
    Expects two equally-sized tensors of shape (*, 4), where * denotes any number of dimensions.
    Returns q*r as a tensor of shape (*, 4).
    """
    assert q.shape[-1] == 4
    assert r.shape[-1] == 4

    original_shape = q.shape

    # Compute outer product
    terms = torch.bmm(r.view(-1, 4, 1), q.view(-1, 1, 4))

    w = terms[:, 0, 0] - terms[:, 1, 1] - terms[:, 2, 2] - terms[:, 3, 3]
    x = terms[:, 0, 1] + terms[:, 1, 0] - terms[:, 2, 3] + terms[:, 3, 2]
    y = terms[:, 0, 2] + terms[:, 1, 3] + terms[:, 2, 0] - terms[:, 3, 1]
    z = terms[:, 0, 3] - terms[:, 1, 2] + terms[:, 2, 1] + terms[:, 3, 0]
    return torch.stack((w, x, y, z), dim=1).view(original_shape)
def qmul ( q , r ) : assert q . shape [ - 1 ] == 4 assert r . shape [ - 1 ] == 4 original_shape = q . shape # Compute outer product terms = torch . bmm ( r . view ( - 1 , 4 , 1 ) , q . view ( - 1 , 1 , 4 ) ) w = terms [ : , 0 , 0 ] - terms [ : , 1 , 1 ] - terms [ : , 2 , 2 ] - terms [ : , 3 , 3 ] x = terms [ : , 0 , 1 ] + terms [ : , 1 , 0 ] - terms [ : , 2 , 3 ] + terms [ : , 3 , 2 ] y = terms [ : , 0 , 2 ] + terms [ : , 1 , 3 ] + terms [ : , 2 , 0 ] - terms [ : , 3 , 1 ] z = terms [ : , 0 , 3 ] - terms [ : , 1 , 2 ] + terms [ : , 2 , 1 ] + terms [ : , 3 , 0 ] return torch . stack ( ( w , x , y , z ) , dim = 1 ) . view ( original_shape )