# Path: moonlight/util/functional_ops.py
# def flat_map_fn(fn, elems, dtype=None):
#   def compute(i, results):
# 
# Path: moonlight/util/memoize.py
# class MemoizedFunction(object):
#   def __init__(self, function):
#   def __call__(self, *args):
# 
# Path: moonlight/util/segments.py
# class SegmentsMode(enum.Enum):
#   STARTS = 1
#   CENTERS = 2
# def true_segments_1d(segments,
#                      mode=SegmentsMode.CENTERS,
#                      max_gap=0,
#                      min_length=0,
#                      name=None):
# def _segments_1d(values, mode, name=None):
#     def do_segments(values):
#     def empty_segments():
# def peaks(values, minval=None, invalidate_distance=0, name=None):
#     def loop_condition(_, current_peaks):
#     def loop_body(accepted_peaks, current_peaks):
# 
# Path: moonlight/vision/images.py
# def translate(image, x, y):
# 
# Path: moonlight/vision/morphology.py
# def binary_erosion(image, n):
# def binary_dilation(image, n):
# def _repeated_morphological_op(float_image, binary_op, n):
#   def body(i, image):
# def _single_morphological_op(float_image, binary_op):


import numpy as np
import tensorflow as tf
from moonlight.util import functional_ops
from moonlight.util import memoize
from moonlight.util import segments
from moonlight.vision import images
from moonlight.vision import morphology
    self.filtered_image = morphology.binary_dilation(
        _horizontal_filter(thresholded_image,
                           staff_detector.staffline_thickness), 1)
    staffline_distance = tf.reduce_mean(staff_detector.staffline_distance)
    # Deterministically convert max_gap_staffline_distance to a list.
    # We use a frozenset so there is no risk of mutating the default argument.
    self.max_gap = tf.to_int32(
        tf.round(
            tf.to_float(staffline_distance) *
            sorted(max_gap_staffline_distance)))
    self.min_length = tf.to_int32(
        tf.round(
            tf.to_float(staffline_distance) * min_length_staffline_distance))

  @property
  @memoize.MemoizedFunction
  def lines(self):
    """The vertical lines.

    Returns:
      int32 tensor of shape (num_lines, 2, 2), storing lines as
          ((start_x, start_y), (end_x, end_y)).
    """
    columns = tf.range(tf.shape(self.image)[1])

    def map_max_gap(max_gap):
      """Process all columns with the given value for max_gap."""
      return functional_ops.flat_map_fn(
          lambda column: self._verticals_in_column(max_gap, column), columns)


# Path: moonlight/util/functional_ops.py
# def flat_map_fn(fn, elems, dtype=None):
#   def compute(i, results):
# 
# Path: moonlight/util/memoize.py
# class MemoizedFunction(object):
#   def __init__(self, function):
#   def __call__(self, *args):
# 
# Path: moonlight/util/segments.py
# class SegmentsMode(enum.Enum):
#   STARTS = 1
#   CENTERS = 2
# def true_segments_1d(segments,
#                      mode=SegmentsMode.CENTERS,
#                      max_gap=0,
#                      min_length=0,
#                      name=None):
# def _segments_1d(values, mode, name=None):
#     def do_segments(values):
#     def empty_segments():
# def peaks(values, minval=None, invalidate_distance=0, name=None):
#     def loop_condition(_, current_peaks):
#     def loop_body(accepted_peaks, current_peaks):
# 
# Path: moonlight/vision/images.py
# def translate(image, x, y):
# 
# Path: moonlight/vision/morphology.py
# def binary_erosion(image, n):
# def binary_dilation(image, n):
# def _repeated_morphological_op(float_image, binary_op, n):
#   def body(i, image):
# def _single_morphological_op(float_image, binary_op):


# Path: moonlight/structure/verticals.py
import numpy as np
import tensorflow as tf
from moonlight.util import functional_ops
from moonlight.util import memoize
from moonlight.util import segments
from moonlight.vision import images
from moonlight.vision import morphology

    self.filtered_image = morphology.binary_dilation(
        _horizontal_filter(thresholded_image,
                           staff_detector.staffline_thickness), 1)
    staffline_distance = tf.reduce_mean(staff_detector.staffline_distance)
    # Deterministically convert max_gap_staffline_distance to a list.
    # We use a frozenset so there is no risk of mutating the default argument.
    self.max_gap = tf.to_int32(
        tf.round(
            tf.to_float(staffline_distance) *
            sorted(max_gap_staffline_distance)))
    self.min_length = tf.to_int32(
        tf.round(
            tf.to_float(staffline_distance) * min_length_staffline_distance))

  @property
  @memoize.MemoizedFunction
  def lines(self):
    """The vertical lines.

    Returns:
      int32 tensor of shape (num_lines, 2, 2), storing lines as
          ((start_x, start_y), (end_x, end_y)).
    """
    columns = tf.range(tf.shape(self.image)[1])

    def map_max_gap(max_gap):
      """Process all columns with the given value for max_gap."""
      return functional_ops.flat_map_fn(
          lambda column: self._verticals_in_column(max_gap, column), columns)


    return functional_ops.flat_map_fn(map_max_gap, self.max_gap)