code: def _gen_periodic_schedule(
      start_date,
      end_date,
      tenor,
      holiday_calendar=None,
      roll_convention=constants.BusinessDayConvention.NONE,
      backward=False,
      end_of_month=False,
  ):
      """Generates a periodic schedule, see PeriodicSchedule."""
  
      # Validate inputs.
      control_deps = [
          tf.debugging.assert_greater_equal(
              end_date.ordinal(),
              start_date.ordinal(),
              message="End date must be >= to start date.",
          ),
          tf.debugging.assert_positive(
              tenor.quantity(),
              message="Tenor quantity must be positive.",
          ),
      ]
  
      with tf.compat.v1.control_dependencies(control_deps):
          # Reshape the input Tensors.
          if backward:
              start_date = start_date.broadcast_to(
                  tf.shape(end_date.ordinal())
              )
              tenor = tenor.broadcast_to(tf.shape(end_date.ordinal()))
          else:
              end_date = end_date.broadcast_to(
                  tf.shape(start_date.ordinal())
              )
              tenor = tenor.broadcast_to(tf.shape(start_date.ordinal()))
          start_date = start_date.expand_dims(axis=-1)
          end_date = end_date.expand_dims(axis=-1)
          tenor = tenor.expand_dims(axis=-1)
  
          # Figure out the upper bound of the schedule length.
          min_days_in_period = _MIN_DAYS_IN_PERIOD[tenor.period_type()]
          days_between = end_date.ordinal() - start_date.ordinal() + 1
          schedule_len_upper_bound = tf.cast(
              tf.math.ceil(
                  tf.math.reduce_max(
                      days_between
                      / (tenor.quantity() * min_days_in_period)
                  )
              ),
              dtype=tf.int32,
          )
  
          # Add the periods.
          if backward:
              # Subtract tenor * n, where n = n_max, ..., 2, 1, 0.
              tenors_expanded = tenor * tf.range(
                  schedule_len_upper_bound - 1, -1, -1, dtype=tf.int32
              )
              schedules = end_date - tenors_expanded
              # Prepend start_date to ensure we always include it.
              schedules = date_tensor.DateTensor.concat(
                  (start_date, schedules), axis=-1
              )
              in_bounds = schedules.ordinal() >= start_date.ordinal()
  
              # Pad with start_date.
              schedules = date_tensor.DateTensor.where(
                  in_bounds, schedules, start_date
              )
  
              # Find how much we overestimated max schedule length and trim the extras.
              not_start_date = tf.math.not_equal(
                  schedules.ordinal(), start_date.ordinal()
              )
              max_schedule_len_error = (
                  tf.math.reduce_min(tf.where(not_start_date)[..., -1])
                  - 1
              )
              schedules = schedules[..., max_schedule_len_error:]
          else:
              # Add tenor * n, where n = 0, 1, 2, ..., n_max.
              tenors_expanded = tenor * tf.range(
                  schedule_len_upper_bound, dtype=tf.int32
              )
              schedules = start_date + tenors_expanded
              # Append end_date to ensure we always include it.
              schedules = date_tensor.DateTensor.concat(
                  (schedules, end_date), axis=-1
              )
  
              in_bounds = schedules.ordinal() <= end_date.ordinal()
  
              # Pad with end_date.
              schedules = date_tensor.DateTensor.where(
                  in_bounds, schedules, end_date
              )
  
              # Find the actual schedule length and trim the extras.
              not_end_date = tf.math.not_equal(
                  schedules.ordinal(), end_date.ordinal()
              )
              max_schedule_len = (
                  tf.math.reduce_max(tf.where(not_end_date)[..., -1])
                  + 2
              )
              schedules = schedules[..., :max_schedule_len]
  
          # Move to the end of month where necessary.
          if end_of_month:
              where_cond = (
                  end_date if backward else start_date
              ).is_end_of_month()
              schedules = date_tensor.DateTensor.where(
                  where_cond, schedules.to_end_of_month(), schedules
              )
  
          # Roll to business days.
          if holiday_calendar is not None:
              schedules = holiday_calendar.roll_to_business_day(
                  schedules, roll_convention
              )
  
          return schedules
  
imports: import tensorflow.compat.v2
  from tf_quant_finance.datetime import constants
  from tf_quant_finance.datetime import date_tensor
label_desc: Use image node_id 1 for calling a global function with example usage: _gen_periodic_schedule(start_date, end_date, tenor, holiday_calendar, roll_convention, backward, end_of_month) and returns: schedules