def _compute_rolled_dates_table_without_cache(self, convention):
        is_bus_day = self._compute_is_bus_day_table()
        cumul_bus_days = self._compute_cumul_bus_days_table()
        bus_day_ordinals = self._compute_bus_day_ordinals_table()

        if convention == constants.BusinessDayConvention.FOLLOWING:
            return tf.gather(bus_day_ordinals, cumul_bus_days)

        if convention == constants.BusinessDayConvention.PRECEDING:
            return tf.gather(bus_day_ordinals,
                             cumul_bus_days - (1 - is_bus_day))

        following = self._compute_rolled_dates_table(
            constants.BusinessDayConvention.FOLLOWING)
        preceding = self._compute_rolled_dates_table(
            constants.BusinessDayConvention.PRECEDING)
        dates_following = dt.from_ordinals(following)
        dates_preceding = dt.from_ordinals(preceding)
        original_dates = dt.from_ordinals(
            tf.range(self._ordinal_offset - 1,
                     self._ordinal_offset + self._calendar_size + 1))

        if convention == constants.BusinessDayConvention.MODIFIED_FOLLOWING:
            return tf.where(
                tf.equal(dates_following.month(), original_dates.month()),
                following, preceding)

        if convention == constants.BusinessDayConvention.MODIFIED_PRECEDING:
            return tf.where(
                tf.equal(dates_preceding.month(), original_dates.month()),
                preceding, following)

        raise ValueError("Unrecognized convention: {}".format(convention))
Esempio n. 2
0
def pad_date_tensors(date_tensors, name=None):
  """Pads the innermost dimension of `DateTensor`s to a common shape.

  Given a list of `DateTensor`s of shapes `batch_shape_i + [n_i]`, pads the
  innermost dimension of each corresponding ordinal tensor to
  `batch_shape_i + [max(n_i)]`. For each ordinal tensor `t`, the padding is done
  with values `t[..., -1]`.

  ### Example
  ```python
  x = [(2020, 1, 1), (2021, 2, 2)]
  y = [(2019, 5, 5), (2028, 10, 21), (2028, 11, 10)]
  pad_date_tensors([x, y])
  # Expected: [DateTensor: [(2020, 1, 1), (2021, 2, 2), (2021, 2, 2)],
  #            DateTensor: [(2019, 5, 5), (2028, 10, 21), (2028, 11, 10)]]
  ```

  Args:
    date_tensors: a list of tensors of shapes `batch_shape_i + [n_i]`.
    name: Python string. The name to give to the ops created by this class.
      Default value: `None` which maps to the default name `pad_date_tensors`.
  Returns:
    A list of `DateTensor`s of shape `batch_shape_i + [max(n_i)]`.
  """
  name = name or "pad_date_tensors"
  with tf.name_scope(name):
    ordinals = [date_tensor.convert_to_date_tensor(t).ordinal()
                for t in date_tensors]
    padded_tensors = pad_tensors(ordinals)
    return [date_tensor.from_ordinals(p) for p in padded_tensors]
    def add_business_days(
            self,
            date_tensor,
            num_days,
            roll_convention=constants.BusinessDayConvention.NONE):
        """Adds given number of business days to given dates.

    Note that this is different from calling `add_period_and_roll` with
    PeriodType.DAY. For example, adding 5 business days to Monday gives the next
    Monday (unless there are holidays on this week or next Monday). Adding 5
    days and rolling means landing on Saturday and then rolling either to next
    Monday or to Friday of the same week, depending on the roll convention.

    If any of the dates in `date_tensor` are not business days, they will be
    rolled to business days before doing the addition. If `roll_convention` is
    `NONE`, and any dates are not business days, an exception is raised.

    Args:
      date_tensor: DateTensor of dates to advance from.
      num_days: Tensor of int32 type broadcastable to `date_tensor`.
      roll_convention: BusinessDayConvention. Determines how to roll a date that
        falls on a holiday.

    Returns:
      The resulting DateTensor.
    """
        control_deps = []
        if roll_convention == constants.BusinessDayConvention.NONE:
            message = ("Some dates in date_tensor are not business days. "
                       "Please specify the roll_convention argument.")
            is_bus_day = self.is_business_day(date_tensor)
            control_deps.append(
                tf.debugging.assert_equal(is_bus_day, True, message=message))
        else:
            date_tensor = self.roll_to_business_day(date_tensor,
                                                    roll_convention)

        with tf.control_dependencies(control_deps):
            cumul_bus_days_table = self._compute_cumul_bus_days_table()
            cumul_bus_days = self._gather(
                cumul_bus_days_table,
                date_tensor.ordinal() - self._ordinal_offset + 1)
            target_cumul_bus_days = cumul_bus_days + num_days

            bus_day_ordinals_table = self._compute_bus_day_ordinals_table()
            ordinals = self._gather(bus_day_ordinals_table,
                                    target_cumul_bus_days)
            with tf.control_dependencies(
                    self._assert_ordinals_in_bounds(ordinals)):
                return dt.from_ordinals(ordinals, validate=False)
Esempio n. 4
0
    def roll_to_business_day(self, date_tensor, roll_convention):
        """Rolls the given dates to business dates according to given convention.

    Args:
      date_tensor: `DateTensor` of dates to roll from.
      roll_convention: BusinessDayConvention. Determines how to roll a date that
        falls on a holiday.

    Returns:
      The resulting `DateTensor`.
    """
        if roll_convention == constants.BusinessDayConvention.NONE:
            return date_tensor
        ordinals = dt.convert_to_date_tensor(date_tensor).ordinal()
        biz_days, is_bizday = self._to_biz_space(ordinals)
        biz_days_rolled = self._apply_roll_biz_space(date_tensor, biz_days,
                                                     is_bizday,
                                                     roll_convention)
        return dt.from_ordinals(self._from_biz_space(biz_days_rolled))
Esempio n. 5
0
    def add_business_days(
            self,
            date_tensor,
            num_days,
            roll_convention=constants.BusinessDayConvention.NONE):
        """Adds given number of business days to given dates.

    Note that this is different from calling `add_period_and_roll` with
    PeriodType.DAY. For example, adding 5 business days to Monday gives the next
    Monday (unless there are holidays on this week or next Monday). Adding 5
    days and rolling means landing on Saturday and then rolling either to next
    Monday or to Friday of the same week, depending on the roll convention.

    If any of the dates in `date_tensor` are not business days, they will be
    rolled to business days before doing the addition. If `roll_convention` is
    `NONE`, and any dates are not business days, an exception is raised.

    Args:
      date_tensor: `DateTensor` of dates to advance from.
      num_days: Tensor of int32 type broadcastable to `date_tensor`.
      roll_convention: BusinessDayConvention. Determines how to roll a date that
        falls on a holiday.

    Returns:
      The resulting `DateTensor`.
    """
        control_deps = []
        biz_days, is_bizday = self._to_biz_space(
            dt.convert_to_date_tensor(date_tensor).ordinal())
        if roll_convention == constants.BusinessDayConvention.NONE:
            control_deps.append(
                tf.debugging.assert_equal(
                    is_bizday,
                    True,
                    message='Non business starting day with no roll convention.'
                ))

        with tf.compat.v1.control_dependencies(control_deps):
            biz_days_rolled = self._apply_roll_biz_space(
                date_tensor, biz_days, is_bizday, roll_convention)
            return dt.from_ordinals(
                self._from_biz_space(biz_days_rolled + num_days))
    def roll_to_business_day(self, date_tensor, roll_convention):
        """Rolls the given dates to business dates according to given convention.

    Args:
      date_tensor: DateTensor of dates to roll from.
      roll_convention: BusinessDayConvention. Determines how to roll a date that
        falls on a holiday.

    Returns:
      The resulting DateTensor.
    """
        if roll_convention == constants.BusinessDayConvention.NONE:
            return date_tensor
        rolled_ordinals_table = self._compute_rolled_dates_table(
            roll_convention)
        ordinals_with_offset = date_tensor.ordinal() - self._ordinal_offset + 1
        rolled_ordinals = self._gather(rolled_ordinals_table,
                                       ordinals_with_offset)
        with tf.control_dependencies(
                self._assert_ordinals_in_bounds(rolled_ordinals)):
            return dt.from_ordinals(rolled_ordinals, validate=False)