<commit_before>package lv.addresses.indexer

trait SpatialIndexer { this: AddressFinder =>

  import scala.collection.mutable.SortedSet

  case class Node(code: Int, left: Node, right: Node)

  protected var _spatialIndex: Node = null

  class Search(val limit: Int) {
    private val realLimit = Math.min(limit, 20)
    private val nearest = SortedSet[(AddrObj, BigDecimal)]()(new Ordering[(AddrObj, BigDecimal)]  {
      def compare(a: (AddrObj, BigDecimal), b: (AddrObj, BigDecimal)) =
        if (a._2 < b._2) -1 else if (a._2 > b._2) 1 else 0
    })
    private def dist(px: BigDecimal, py: BigDecimal, ax: BigDecimal, ay: BigDecimal) =
      (px - ax).pow(2) + (py - ay).pow(2)

    def searchNearest(coordX: BigDecimal, coordY: BigDecimal) = {
      def search(node: Node, depth: Int = 0): AddrObj = if (node == null) null else {
        import node._
        val curr_addr = addressMap(code)
        def closest(addr: AddrObj, new_addr: AddrObj) = if (new_addr == null) {
          register_nearest(addr, null)
          addr
        } else {
          val nd = dist(coordX, coordY, new_addr.coordX, new_addr.coordY)
          val d = dist(coordX, coordY, addr.coordX, addr.coordY)
          val (ra, rd) = if (nd < d) (new_addr, nd) else (addr, d)
          register_nearest(ra, rd)
          ra
        }
        def register_nearest(addr: AddrObj, d: BigDecimal) = {
          nearest += (addr -> (if (d == null) dist(coordX, coordY, addr.coordX, addr.coordY) else d))
          if (nearest.size > realLimit) nearest.lastOption.foreach(nearest -= _)
        }
        def check_x_splitting_pane(addr: AddrObj) =
          dist(coordX, coordY, addr.coordX, addr.coordY) >= dist(coordX, 0, curr_addr.coordX, 0)
        def check_y_splitting_pane(addr: AddrObj) =
          dist(coordX, coordY, addr.coordX, addr.coordY) >= dist(0, coordY, 0, curr_addr.coordY)
        def traverse(left: Node, right: Node, check_splitting_pane_cross: AddrObj => Boolean,
            start_with_left: Boolean) = {
          val (first, second) = if (start_with_left) (left, right) else (right, left)
          val curr_best_addr = closest(curr_addr, search(first, depth + 1))
          if (check_splitting_pane_cross(curr_best_addr)) closest(curr_best_addr, search(second, depth + 1))
          else curr_best_addr
        }
        if (depth % 2 == 0) traverse(left, right, check_x_splitting_pane, coordX <= curr_addr.coordX) //x axis
        else traverse(left, right, check_y_splitting_pane, coordY <= curr_addr.coordY) //y axis
      }
      search(_spatialIndex)<commit_msg>multiple nearest search fix<commit_after>package lv.addresses.indexer

trait SpatialIndexer { this: AddressFinder =>

  import scala.collection.mutable.SortedSet

  case class Node(code: Int, left: Node, right: Node)

  protected var _spatialIndex: Node = null

  class Search(val limit: Int) {
    private val realLimit = Math.min(limit, 20)
    private val nearest = SortedSet[(AddrObj, BigDecimal)]()(new Ordering[(AddrObj, BigDecimal)]  {
      def compare(a: (AddrObj, BigDecimal), b: (AddrObj, BigDecimal)) =
        if (a._2 < b._2) -1 else if (a._2 > b._2) 1 else 0
    })
    private def dist(px: BigDecimal, py: BigDecimal, ax: BigDecimal, ay: BigDecimal) =
      (px - ax).pow(2) + (py - ay).pow(2)

    def searchNearest(coordX: BigDecimal, coordY: BigDecimal) = {
      def search(node: Node, depth: Int = 0): AddrObj = if (node == null) null else {
        import node._
        val curr_addr = addressMap(code)
        def closest(addr: AddrObj, new_addr: AddrObj) = if (new_addr == null) {
          register_nearest(addr, null)
          addr
        } else {
          val d = dist(coordX, coordY, addr.coordX, addr.coordY)
          val nd = dist(coordX, coordY, new_addr.coordX, new_addr.coordY)
          register_nearest(addr, d)
          register_nearest(new_addr, nd)
          if (nd < d) new_addr else addr
        }
        def register_nearest(addr: AddrObj, d: BigDecimal) = {
          nearest += (addr -> (if (d == null) dist(coordX, coordY, addr.coordX, addr.coordY) else d))
          if (nearest.size > realLimit) nearest.lastOption.foreach(nearest -= _)
        }
        def check_x_splitting_pane(addr: AddrObj) =
          dist(coordX, coordY, addr.coordX, addr.coordY) >= dist(coordX, 0, curr_addr.coordX, 0)
        def check_y_splitting_pane(addr: AddrObj) =
          dist(coordX, coordY, addr.coordX, addr.coordY) >= dist(0, coordY, 0, curr_addr.coordY)
        def traverse(left: Node, right: Node, check_splitting_pane_cross: AddrObj => Boolean,
            start_with_left: Boolean) = {
          val (first, second) = if (start_with_left) (left, right) else (right, left)
          val curr_best_addr = closest(curr_addr, search(first, depth + 1))
          if (check_splitting_pane_cross(curr_best_addr)) closest(curr_best_addr, search(second, depth + 1))
          else curr_best_addr
        }
        if (depth % 2 == 0) traverse(left, right, check_x_splitting_pane, coordX <= curr_addr.coordX) //x axis
        else traverse(left, right, check_y_splitting_pane, coordY <= curr_addr.coordY) //y axis
      }
      search(_spatialIndex)
{'fraction_non_alphanumeric': 0.12041884816753927, 'fraction_numerical': 0.0077564475470234635, 'mean_word_length': 2.910538286580743, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2356333', 'n_tokens_mistral': 1765, 'n_tokens_neox': 1735, 'n_words': 448}