Esempio n. 1
0
def safe_unsigned_div(a, b, eps=None, name='safe_unsigned_div'):
    """Calculates a/b with b >= 0 safely.

  If the tfg debug flag TFG_ADD_ASSERTS_TO_GRAPH defined in tfg_flags.py
  is set to True, this function adds assertions to the graph that check whether
  b + eps is greather than zero, and the division has no NaN or Inf values.

  Args:
    a: A `float` or a tensor of shape `[A1, ..., An]`, which is the nominator.
    b: A `float` or a tensor of shape `[A1, ..., An]`, which is the denominator.
    eps: A small `float`, to be added to the denominator. If left as `None`, its
      value is automatically selected using `b.dtype`.
    name: A name for this op. Defaults to 'safe_unsigned_div'.

  Raises:
     InvalidArgumentError: If tf-graphics debug flag is set and the division
       causes `NaN` or `Inf` values.

  Returns:
     A tensor of shape `[A1, ..., An]` containing the results of division.
  """
    with tf.name_scope(name):
        a = tf.convert_to_tensor(value=a)
        b = tf.convert_to_tensor(value=b)
        if eps is None:
            eps = asserts.select_eps_for_division(b.dtype)
        eps = tf.convert_to_tensor(value=eps, dtype=b.dtype)

        return asserts.assert_no_infs_or_nans(a / (b + eps))
Esempio n. 2
0
def safe_signed_div(a, b, eps=None, name='safe_signed_div'):
    """Calculates a/b safely.

  If the tf-graphics debug flag is set to `True`, this function adds assertions
  to the graph that check whether `abs(b + eps)` is greather than zero, and the
  division has no `NaN` or `Inf` values.

  Note:
    In the following, A1 to An are optional batch dimensions, which must be
    broadcast compatible.

  Args:
    a: A `float` or a tensor of shape `[A1, ..., An]`, which is the nominator.
    b: A `float` or a tensor of shape `[A1, ..., An]`, which is the denominator
      with non-negative values.
    eps: A small `float`, to be added to the denominator. If left `None`, its
      value is automatically selected using `b.dtype`.
    name: A name for this op. Defaults to 'safe_signed_div'.

  Raises:
     InvalidArgumentError: If tf-graphics debug flag is set and the division
       causes `NaN` or `Inf` values.

  Returns:
     A tensor of shape `[A1, ..., An]` containing the results of division.
  """
    with tf.name_scope(name):
        a = tf.convert_to_tensor(value=a)
        b = tf.convert_to_tensor(value=b)
        if eps is None:
            eps = asserts.select_eps_for_division(b.dtype)
        eps = tf.convert_to_tensor(value=eps, dtype=b.dtype)

        return asserts.assert_no_infs_or_nans(a / (b + nonzero_sign(b) * eps))
Esempio n. 3
0
  def test_select_eps_for_division(self, dtype):
    """Checks that select_eps_for_division does not cause Inf values."""
    a = tf.constant(1.0, dtype=dtype)
    eps = asserts.select_eps_for_division(dtype)

    self.assert_exception_is_not_raised(
        asserts.assert_no_infs_or_nans, shapes=[], tensor=a / eps)
Esempio n. 4
0
def generate_random_face_indices(
        num_samples: int,
        face_weights: type_alias.TensorLike,
        seed: Optional[type_alias.TensorLike] = None,
        stateless: bool = False,
        name: str = "generate_random_face_indices") -> type_alias.TensorLike:
    """Generate a sample of face ids given per face probability.

  Note:
    In the following, A1 to An are optional batch dimensions.

  Args:
    num_samples: An `int32` scalar denoting the number of samples to generate
      per mesh.
    face_weights: A `float` tensor of shape `[A1, ..., An, F]` where F is
      number of faces. All weights must be > 0.
    seed: Optional seed for the random number generator.
    stateless: Optional flag to use stateless random sampler. If stateless=True,
      then `seed` must be provided as shape `[2]` int tensor. Stateless random
      sampling is useful for testing to generate the same reproducible sequence
      across calls. If stateless=False, then a stateful random number generator
      is used (default behavior).
    name: Name for op. Defaults to "generate_random_face_indices".

  Returns:
    An `int32` tensor of shape `[A1, ..., An, num_samples]` denoting sampled
      face indices.
  """
    with tf.name_scope(name):
        num_samples = tf.convert_to_tensor(value=num_samples)
        face_weights = tf.convert_to_tensor(value=face_weights)
        shape.check_static(tensor=face_weights,
                           tensor_name="face_weights",
                           has_rank_greater_than=0)
        shape.check_static(tensor=num_samples,
                           tensor_name="num_samples",
                           has_rank=0)

        face_weights = asserts.assert_all_above(face_weights, minval=0.0)
        eps = asserts.select_eps_for_division(face_weights.dtype)
        face_weights = face_weights + eps
        sampled_face_indices = _random_categorical_sample(
            num_samples=num_samples,
            weights=face_weights,
            seed=seed,
            stateless=stateless)
        return sampled_face_indices
Esempio n. 5
0
def safe_cospx_div_cosx(theta: type_alias.TensorLike,
                        factor: type_alias.TensorLike,
                        eps: Optional[type_alias.Float] = None,
                        name: str = 'safe_cospx_div_cosx') -> tf.Tensor:
    """Calculates cos(factor * theta)/cos(theta) safely.

  The term `cos(factor * theta)/cos(theta)` has periodic edge cases with
  division by zero problems, and also zero / zero, e.g. when factor is equal to
  1.0 and `theta` is `(n + 1/2)pi`. This function adds signed eps to the angles
  in both the nominator and the denominator to ensure safety, and returns the
  correct values in all edge cases.

  Note:
    In the following, A1 to An are optional batch dimensions, which must be
    broadcast compatible.

  Args:
    theta: A tensor of shape `[A1, ..., An]`, representing angles in radians.
    factor: A `float` or a tensor of shape `[A1, ..., An]`.
    eps: A `float`, used to perturb the angle. If left as `None`, its value is
      automatically determined from the `dtype` of `theta`.
    name: A name for this op. Defaults to 'safe_cospx_div_cosx'.

  Raises:
    InvalidArgumentError: If tf-graphics debug flag is set and division returns
      `NaN` or `Inf` values.

  Returns:
    A tensor of shape `[A1, ..., An]` containing the resulting values.
  """
    with tf.name_scope(name):
        theta = tf.convert_to_tensor(value=theta)
        factor = tf.convert_to_tensor(value=factor, dtype=theta.dtype)
        if eps is None:
            eps = asserts.select_eps_for_division(theta.dtype)
        eps = tf.convert_to_tensor(value=eps, dtype=theta.dtype)

        # eps will be multiplied with factor next, which can make it zero.
        # Therefore we multiply eps with min(1/factor, 1e10), which can handle
        # factors as small as 1e-10 correctly, while preventing a division by zero.
        eps *= tf.clip_by_value(1.0 / factor, 1.0, 1e10)
        sign = nonzero_sign(0.5 * np.pi - (theta - 0.5 * np.pi) % np.pi)
        theta += sign * eps
        div = tf.cos(factor * theta) / tf.cos(theta)
        return asserts.assert_no_infs_or_nans(div)
Esempio n. 6
0
def safe_sinpx_div_sinx(theta, factor, eps=None, name='safe_sinpx_div_sinx'):
    """Calculates sin(factor * theta)/sin(theta) safely.

  The term `sin(factor * theta)/sin(theta)` appears when calculating spherical
  interpolation weights, and it has periodic edge cases causing both zero / zero
  and division by zero problems. This function adds signed eps to the angles in
  both the nominator and the denominator to ensure safety, and returns the
  correct values estimated by l'Hopital rule in the case of zero / zero.

  Note:
    In the following, A1 to An are optional batch dimensions, which must be
    broadcast compatible.

  Args:
    theta: A tensor of shape `[A1, ..., An]` representing angles in radians.
    factor: A `float` or a tensor of shape `[A1, ..., An]`.
    eps: A `float`, used to perturb the angle. If left as `None`, its value is
      automatically determined from the `dtype` of `theta`.
    name: A name for this op. Defaults to 'safe_sinpx_div_sinx'.

  Raises:
    InvalidArgumentError: If tf-graphics debug flag is set and the division
      returns `NaN` or `Inf` values.

  Returns:
    A tensor of shape `[A1, ..., An]` containing the resulting values.
  """
    with tf.name_scope(name):
        theta = tf.convert_to_tensor(value=theta)
        factor = tf.convert_to_tensor(value=factor, dtype=theta.dtype)
        if eps is None:
            eps = asserts.select_eps_for_division(theta.dtype)
        eps = tf.convert_to_tensor(value=eps, dtype=theta.dtype)

        # eps will be multiplied with factor next, which can make it zero.
        # Therefore we multiply eps with min(1/factor, 1e10), which can handle
        # factors as small as 1e-10 correctly, while preventing a division by zero.
        eps *= tf.clip_by_value(1.0 / factor, 1.0, 1e10)
        sign = nonzero_sign(0.5 * np.pi - theta % np.pi)
        theta += sign * eps
        div = tf.sin(factor * theta) / tf.sin(theta)
        return asserts.assert_no_infs_or_nans(div)