import tensorflow as tf


def _double_factorial_loop_body(n, result, two):
  result = tf.where(tf.greater_equal(n, two), result * n, result)
  return n - two, result, two


def _double_factorial_loop_condition(n, result, two):
  return tf.cast(tf.math.count_nonzero(tf.greater_equal(n, two)), tf.bool)


def double_factorial(n: TensorLike) -> TensorLike:
  n = tf.convert_to_tensor(value=n)

  two = tf.ones_like(n) * 2
  result = tf.ones_like(n)
  _, result, _ = tf.while_loop(
      cond=_double_factorial_loop_condition,
      body=_double_factorial_loop_body,
      loop_vars=[n, result, two])
  return result


def factorial(n: TensorLike) -> TensorLike:
  n = tf.convert_to_tensor(value=n)

  return tf.exp(tf.math.lgamma(n + 1))


def generate_l_m_permutations(
    max_band: int,
