All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sisioh.baseunits.scala.intervals.IntervalSeq.scala Maven / Gradle / Ivy

There is a newer version: 0.1.22
Show newest version
/*
 * Copyright 2011 Sisioh Project and the Others.
 * lastModified : 2011/04/22
 *
 * This file is part of Tricreo.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.sisioh.baseunits.scala.intervals

import scala.collection._
import scala.collection.mutable.ArrayBuffer

/**
 * 区間同士の比較を行うための`Ordering`の実装(上側優先)
 *
 * 上側限界による比較を優先し、同じであったら下側限界による比較を採用する。
 *
 * @author j5ik2o
 * @param inverseLower 下限が逆順の場合は`true`
 * @param inverseUpper 上限が逆順の場合は`false`
 */
class UpperLowerOrdering[T <% Ordered[T]](private val inverseLower: Boolean, private val inverseUpper: Boolean)
    extends Ordering[Interval[T]] {

  private[this] val lowerFactor = if (inverseLower) -1 else 1
  private[this] val upperFactor = if (inverseUpper) -1 else 1

  def compare(e1: Interval[T], e2: Interval[T]): Int =
    if (e1.isEmpty && e2.isEmpty) {
      0
    } else if (e1.isEmpty) {
      -1
    } else if (e2.isEmpty) {
      1
    } else {
      val upperComparance = e1.upperLimitObject.compareTo(e2.upperLimitObject)
      val lowerComparance = e1.lowerLimitObject.compareTo(e2.lowerLimitObject)
      if (upperComparance != 0) (upperComparance * upperFactor)
      else (lowerComparance * lowerFactor)
    }
}

/**
 * `UpperLowerOrdering`コンパニオンオブジェクト。
 *
 * @author j5ik2o
 */
object UpperLowerOrdering {

  /**
   * インスタンスを生成する。
   *
   * @param inverseLower
   * @param inverseUpper
   * @return [[UpperLowerOrdering]]
   */
  def apply[T <% Ordered[T]](inverseLower: Boolean, inverseUpper: Boolean) =
    new UpperLowerOrdering[T](inverseLower, inverseUpper)

  /**
   * 抽出子メソッド。
   *
   * @param upperLowerOrdering [[UpperLowerOrdering]]
   * @return `Option[(Boolean, Boolean)]`
   */
  def unapply[T <% Ordered[T]](upperLowerOrdering: UpperLowerOrdering[T]) =
    Some(upperLowerOrdering.inverseLower, upperLowerOrdering.inverseUpper)

}

/**
 * 区間同士の比較を行うための`Ordering`の実装(下側優先)
 *
 * 下側限界による比較を優先し、同じであったら上側限界による比較を採用する。
 *
 * @author j5ik2o
 * @param inverseLower 下限が逆順の場合は`true`
 * @param inverseUpper 上限が逆順の場合は`false`
 */
class LowerUpperOrdering[T <% Ordered[T]](private val inverseLower: Boolean, private val inverseUpper: Boolean)
    extends Ordering[Interval[T]] {

  private[this] val lowerFactor = if (inverseLower) -1 else 1
  private[this] val upperFactor = if (inverseUpper) -1 else 1

  def compare(e1: Interval[T], e2: Interval[T]): Int =
    if (e1.isEmpty && e2.isEmpty) {
      0
    } else if (e1.isEmpty) {
      1
    } else if (e2.isEmpty) {
      -1
    } else {
      val upperComparance = e1.upperLimitObject.compareTo(e2.upperLimitObject)
      val lowerComparance = e1.lowerLimitObject.compareTo(e2.lowerLimitObject)
      if (lowerComparance != 0) (lowerComparance + lowerFactor)
      else (upperComparance * upperFactor)
    }
}

/**
 * `LowerUpperOrdering`コンパニオンオブジェクト。
 *
 * @author j5ik2o
 */
object LowerUpperOrdering {

  /**
   * インスタンスを生成する。
   *
   * @param inverseLower
   * @param inverseUpper
   * @return [[LowerUpperOrdering]]
   */
  def apply[T <% Ordered[T]](inverseLower: Boolean, inverseUpper: Boolean) =
    new LowerUpperOrdering[T](inverseLower, inverseUpper)

  /**
   * 抽出子メソッド。
   *
   * @param lowerUpperOrdering [[LowerUpperOrdering]]
   * @return `Option[(Boolean, Boolean)]`
   */

  def unapply[T <% Ordered[T]](lowerUpperOrdering: LowerUpperOrdering[T]) =
    Some(lowerUpperOrdering.inverseLower, lowerUpperOrdering.inverseUpper)
}

/**
 * 区間列(複数の [[Interval]] の列)を表すクラス。
 *
 * @author j5ik2o
 * @tparam T [[Interval]]の型
 * @param intervals [[Interval]]の列
 * @param ordering [[Ordering]]
 */
class IntervalSeq[T <% Ordered[T]](val intervals: Seq[Interval[T]], val ordering: Ordering[Interval[T]])
    extends Seq[Interval[T]] with SeqLike[Interval[T], IntervalSeq[T]] {

  override protected def newBuilder: mutable.Builder[Interval[T], IntervalSeq[T]] =
    IntervalSeq.newBuilder[T](ordering)

  /**
   * インスタンスを生成する。
   *
   * `intervals`は空を利用し、`ordering`は`UpperLowerOrdering[T](true, false)`を利用する。
   */
  def this() = this(Seq.empty[Interval[T]], UpperLowerOrdering[T](true, false))

  /**
   * インスタンスを生成する。
   *
   * `ordering`は`UpperLowerOrdering[T](true, false)`を利用する。
   *
   * @param intervals [[Interval]]の列
   */
  def this(intervals: Seq[Interval[T]]) = this(intervals, UpperLowerOrdering[T](true, false))

  /**
   * 全ての要素区間を内包する、最小の区間を返す。
   *
   * @return 全ての要素区間を内包する、最小の区間
   * @throws IllegalStateException 要素が1つもない場合
   */
  lazy val extent: Interval[T] = {
    require(intervals.isEmpty == false)
    intervals.toList match {
      case List(e) => e
      case firstInterval :: _ =>
        val lower = intervals.map(_.lowerLimitObject).min
        val upper = intervals.map(_.upperLimitObject).max
        firstInterval.newOfSameType(lower.value, lower.closed, upper.value, upper.closed)
    }
  }

  /**
   * ソート済みの区間で、隣り合った区間同士に挟まれる区間を区間列として返す。
   *
   * 結果の区間列の `java.util.Comparator` は、この区間列の `java.util.Comparator` を流用する。
   *
   * 区間数が2つ未満の場合は、空の区間列を返す。また、区間同士が重なっていたり接していた場合は、
   * その区間は結果の要素に含まない。全てが重なっている場合は、空の区間列を返す。
   *
   * @return ギャップ区間列
   */
  lazy val gaps: IntervalSeq[T] = {
    if (intervals.size < 2) {
      IntervalSeq(Seq.empty[Interval[T]])
    } else {
      val seq = (1 until this.intervals.size).map {
        i =>
          val left = this.intervals(i - 1)
          val right = this.intervals(i)
          val gap = left.gap(right)
          if (gap.isEmpty) {
            None
          } else {
            Some(gap)
          }
      }.flatten
      IntervalSeq(seq)
    }
  }

  /**
   * ソート済みの区間で、隣り合った区間同士が重なっている区間を区間列として返す。
   *
   * 結果の区間列の [[java.util.Comparator]] は、この区間列の [[java.util.Comparator]] を流用する。
   *
   * 区間数が2つ未満の場合は、空の区間列を返す。また、区間同士が重ならなかったり接していた場合は、
   * その区間は結果の要素に含まない。全てが重ならない場合は、空の区間列を返す。
   *
   * @return 共通区間列
   */
  lazy val intersections: IntervalSeq[T] = {
    if (intervals.size < 2) {
      IntervalSeq[T]()
    } else {
      val seq = (1 until this.intervals.size).flatMap {
        i =>
          val left = this.intervals(i - 1)
          val right = this.intervals(i)
          val gap = left.intersect(right)
          if (gap.isEmpty) None
          else Some(gap)
      }
      IntervalSeq(seq)
    }
  }

  def iterator = this.intervals.iterator

  def length: Int = this.intervals.length

  def apply(idx: Int) = this.intervals(idx)

}

/**
 * [[org.sisioh.baseunits.scala.intervals.IntervalSeq]]のためのビルダー。
 *
 * @author j5ik2o
 */
class IntervalSeqBuilder[T <% Ordered[T]](val ord: Option[Ordering[Interval[T]]] = None)
    extends mutable.Builder[Interval[T], IntervalSeq[T]] {

  private lazy val builder = new ArrayBuffer[Interval[T]]

  def +=(elem: Interval[T]): this.type = {
    builder += elem
    this
  }

  def clear(): Unit = builder.clear

  def result: IntervalSeq[T] =
    ord match {
      case Some(ord) => IntervalSeq(builder.sorted(ord).result)
      case None      => IntervalSeq(builder.result)
    }

}

/**
 * `IntervalSeq`コンパニオンオブジェクト
 *
 * @author j5ik2o
 */
object IntervalSeq {

  import collection.generic.CanBuildFrom

  type From[T] = Seq[Interval[T]]
  type Elem[T] = Interval[T]
  type To[T] = IntervalSeq[T]

  implicit def canBuildFrom[T <% Ordered[T]]: CanBuildFrom[From[T], Elem[T], To[T]] =
    new CanBuildFrom[From[T], Elem[T], To[T]] {

      def apply(from: From[T]) = {
        from match {
          case intervalSeq: IntervalSeq[T] => new IntervalSeqBuilder[T](Some(intervalSeq.ordering))
          case _                           => throw new Error
        }
      }

      def apply() = new IntervalSeqBuilder[T]

    }

  /**
   * インスタンスを生成する。
   *
   * @tparam T 限界値の型
   * @param intervals
   * @return [[IntervalSeq]]
   */
  def apply[T <% Ordered[T]](intervals: From[T]): IntervalSeq[T] = new IntervalSeq(intervals)

  /**
   * インスタンスを生成する。
   *
   * @tparam T 限界値の型
   * @return [[IntervalSeq]]
   */
  def apply[T <% Ordered[T]](): To[T] = new IntervalSeq[T]()

  /**
   * 抽出子メソッド。
   *
   * @tparam T 限界値の型
   * @return 構成要素
   */
  def unapply[T <% Ordered[T]](intervalSeq: IntervalSeq[T]): Option[(Seq[Interval[T]], Ordering[Interval[T]])] =
    Some(intervalSeq.intervals, intervalSeq.ordering)

  /**
   * ビルダーを生成するメソッド。
   *
   * @tparam T 限界値の型
   * @return ビルダー
   */
  def newBuilder[T <% Ordered[T]](ordering: Ordering[Interval[T]]): mutable.Builder[Elem[T], To[T]] =
    new IntervalSeqBuilder[T](Some(ordering))

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy