def test_rotation_inversion(w):
    # Rotation followed by the inverse rotation should leave
    # everything the same (except that the frame data will be either a
    # 1 or a series of 1s)
    np.random.seed(hash("test_rotation_inversion") % 4294967294)  # Use mod to get in an acceptable range
    W_in = w()
    assert W_in.ensure_validity(alter=False)
    # We loop over (1) a single constant rotation, and (2) an array of random rotations
    for R_basis in [
        np.quaternion(*np.random.uniform(-1, 1, 4)).normalized(),
        np.array([np.quaternion(*np.random.uniform(-1, 1, 4)).normalized()] * W_in.n_times),
    ]:
        W_out = w()
        W_out.rotate_decomposition_basis(R_basis)
        W_out.rotate_decomposition_basis(~R_basis)
        assert W_out.ensure_validity(alter=False)
        assert np.array_equal(W_out.t, W_in.t)
        assert np.max(np.abs(W_out.frame - W_in.frame)) < 1e-15
        assert np.allclose(W_out.data, W_in.data, atol=W_in.ell_max ** 4 ** 4e-14, rtol=W_in.ell_max ** 4 * 4e-14)
        assert W_out.ell_min == W_in.ell_min
        assert W_out.ell_max == W_in.ell_max
        assert np.array_equal(W_out.LM, W_in.LM)
        for h_in, h_out in zip(W_in.history[:-3], W_out.history[:-5]):
            assert h_in == h_out.replace(
                f"{type(W_out).__name__}_{str(W_out.num)}", f"{type(W_in).__name__}_{str(W_in.num)}"
            ) or (h_in.startswith("# datetime") and h_out.startswith("# datetime"))
        assert W_out.frameType == W_in.frameType
        assert W_out.dataType == W_in.dataType
        assert W_out.r_is_scaled_out == W_in.r_is_scaled_out
        assert W_out.m_is_scaled_out == W_in.m_is_scaled_out
        assert W_out.num != W_in.num