glsllinear-algebraquaternionshyperbolic-function

Quaternion division and hyperbolic tangent tanh


Quaternion multiplication is well-defined, and is known to me as "Hamilton product":

// hamilton product
vec4 qmul(in vec4 q1, in vec4 q2) {
    return vec4(
        q1.w * q2.xyz + q2.w * q1.xyz - cross(q1.xyz, q2.xyz),
        q1.w*q2.w - dot(q1.xyz, q2.xyz)
    );
}

However, for implementing qtanh() quaternionic function, we need division. So far I've found this, and it is working OK. Could you help me to undestand, where does this comes from?

// division
// https://www.boost.org/doc/libs/1_67_0/boost/math/quaternion.hpp
vec4 qdiv(in vec4 q1, in vec4 q2) {
float denominator = dot(q2,q2);
return vec4( 
    vec3(
        -q1.w*q2.x+q1.x*q2.w-q1.y*q2.z+q1.z*q2.y,
        -q1.w*q2.y+q1.x*q2.z+q1.y*q2.w-q1.z*q2.x,
        -q1.w*q2.z-q1.x*q2.y+q1.y*q2.x+q1.z*q2.w
    ),
    q1.w*q2.w + dot(q1.xyz, q2.xyz)
) / denominator;
}

Also, as far as I am trying to implement tanh().. are you aware of more computationally vat, than dividing sinh and cosh? For reals I've used to use following formula: tanh(x)=-1+2/(1+exp(-x)). And that involves only single exponential calculus, instead of two..


Solution

  • 1. Division

    Dividing a quaternion named p by a quaternion named q is nothing more than multiplying p by the reciprocal of q.

    This is equivalent to multiplying p by the conjugation of q (which by definition equals a – bi – cj – dk) and dividing the product by a scalar equalling q norm squared:

    From here it`s obvious where that denominator part comes from:

    Now let`s rearrange the terms in vec3 sums for better readability:

    vec3(
        -q1.w*q2.x + q1.x*q2.w - (q1.y*q2.z - q1.z*q2.y),
        -q1.w*q2.y + q1.y*q2.w - (q1.z*q2.x - q1.x*q2.z),
        -q1.w*q2.z + q1.z*q2.w - (q1.x*q2.y - q1.y*q2.x)
    )
    

    And now it suddenly gets clear what`s going on:

    vec3(
        -q1.w * q2.x    +  q1.x   * q2.w  -  (q1.y*q2.z - q1.z*q2.y),
        -q1.w * q2.y    +  q1.y   * q2.w  -  (q1.z*q2.x - q1.x*q2.z),
        -q1.w * q2.z    +  q1.z   * q2.w  -  (q1.x*q2.y - q1.y*q2.x)
    )
    
    ...
    
        -q1.w * q2.xyz  +  q1.xyz * q2.w  -  (cross(q1.xyz, q2.xyz))
    

    So yeah, quaternion division is just the regular run-of-the-mill multiplication, with the multiplicand being a reciprocal. That`s where the minuses come from, see the definition above.

    2. Hyperbolic tangent

    First, the definitions. For each q = a + bi + cj + dk = a + v̅:

    So, to get both eq and e–q you only need to compute the following values: ea, ||v̅||, sin(||v̅||), cos(||v̅||).

    To compute e–q you should take a reciprocal of ea and multiply it by the rest of the equation with signs inverted. That won`t take much time, for all the values it consists of have already been computed. One exp() call, as requested =)