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

com.rklaehn.interval.IntervalSeq.scala Maven / Gradle / Ivy

The newest version!
package com.rklaehn.interval

import java.util.Arrays

import spire.algebra.{Eq, Bool, Order}
import spire.math.{Rational, Interval}
import spire.math.interval._

import scala.annotation.tailrec
import scala.collection.{AbstractIterator, AbstractTraversable}
import scala.reflect.ClassTag

final class IntervalSeq[T] private[interval] (
    val belowAll: Boolean,
    private val values: Array[T],
    private val kinds: Array[Byte],
    private implicit val order: Order[T]) extends IntervalSet[T, IntervalSeq[T]] { lhs =>

  import IntervalSeq._

  private def binarySearch(key: T): Int = {
    var low = 0
    var high = values.length - 1
    while (low <= high) {
      val mid = (low + high) >>> 1
      val midVal = values(mid)
      val c = order.compare(midVal, key)
      if (c < 0) {
        low = mid + 1
      }
      else if (c > 0) {
        high = mid - 1
      }
      else {
        // scalastyle:off return
        return mid
        // scalastyle:on return
      }
    }
    -(low + 1)
  }

  private def belowIndex(index: Int): Boolean = {
    if (index == 0)
      belowAll
    else
      valueAbove(kinds(index - 1))
  }

  def at(value: T): Boolean = {
    val index = binarySearch(value)
    if (index >= 0)
      valueAt(kinds(index))
    else
      belowIndex(-index - 1)
  }

  def above(value: T): Boolean = {
    val index = binarySearch(value)
    if (index >= 0)
      valueAbove(kinds(index))
    else
      belowIndex(-index - 1)
  }

  def below(value: T): Boolean = {
    val index = binarySearch(value)
    if (index > 0)
      valueAbove(kinds(index - 1))
    else if (index == 0)
      belowAll
    else
      belowIndex(-index - 1)
  }

  def apply(value:T) = at(value)

  def aboveAll = if (values.isEmpty) belowAll else valueAbove(kinds.last)

  def unary_~ :IntervalSeq[T] = copy(belowAll = !belowAll, kinds = negateKinds(kinds))

  def |(rhs:IntervalSeq[T]) = new Or[T](lhs, rhs).result

  def &(rhs:IntervalSeq[T]) = new And[T](lhs, rhs).result

  def ^(rhs:IntervalSeq[T]) = new Xor[T](lhs, rhs).result

  def intersects(rhs: IntervalSeq[T]): Boolean = !new Disjoint[T](lhs, rhs).result

  def isSupersetOf(rhs: IntervalSeq[T]): Boolean = new IsSupersetOf[T](lhs, rhs).result

  def isProperSupersetOf(rhs: IntervalSeq[T]): Boolean = isSupersetOf(rhs) && (lhs != rhs)

  private def copy(belowAll:Boolean = belowAll, values:Array[T] = values, kinds:Array[Byte] = kinds) =
    new IntervalSeq[T](belowAll, values, kinds, order)

  override def toString = {
//    val vs = values.mkString("[",",","]")
//    val ks = kinds.map(kindToString).mkString("[",",","]")
//    s"SeqBasedIntervalSet($belowAll, $vs, $ks)"
    if(isEmpty)
      Interval.empty[T].toString()
    else
      intervals.mkString(";")
  }

  override def hashCode = {
    belowAll.## * 41 + Arrays.hashCode(kinds) * 23 + Arrays.hashCode(values.asInstanceOf[Array[AnyRef]])
  }

  override def equals(rhs:Any) = rhs match {
    case rhs:IntervalSeq[_] =>
      lhs.belowAll == rhs.belowAll &&
        Arrays.equals(lhs.kinds, rhs.kinds) &&
        Arrays.equals(values.asInstanceOf[Array[AnyRef]], rhs.values.asInstanceOf[Array[AnyRef]])
    case _ => false
  }

  def edges = values

  def isEmpty = !belowAll && values.isEmpty

  def isContiguous: Boolean =
    if(belowAll) {
      kinds match {
        case Array() => true
        case Array(kind) => kind != K01
        case _ => false
      }
    } else {
      kinds match {
        case Array() => true
        case Array(_) => true
        case Array(a,b) => a != K10 && b != K01
        case _ => false
      }
    }

  private[this] def lowerBound(i:Int) = kinds(i) match {
    case K01 => Open(values(i))
    case K11 => Closed(values(i))
    case K10 => Closed(values(i))
    case _ => wrong
  }

  private[this] def upperBound(i:Int) = kinds(i) match {
    case K10 => Closed(values(i))
    case K00 => Open(values(i))
    case _ => wrong
  }

  def hull: Interval[T] = {
    if(isEmpty) {
      Interval.empty[T]
    } else if (belowAll && aboveAll) {
      Interval.all[T]
    } else if (belowAll) {
      Interval.fromBounds(Unbound(), upperBound(kinds.length - 1))
    } else if (aboveAll) {
      Interval.fromBounds(lowerBound(0), Unbound())
    } else {
      Interval.fromBounds(lowerBound(0), upperBound(kinds.length - 1))
    }
  }

  def intervals = new AbstractTraversable[Interval[T]] {
    override def foreach[U](f: (Interval[T]) => U): Unit = foreachInterval(f)
  }

  def intervalIterator: Iterator[Interval[T]] = new IntervalIterator[T](lhs)

  private def foreachInterval[U](f:Interval[T] => U) : Unit = {
    var prev: Option[Bound[T]] = if(belowAll) Some(Unbound()) else None
    for(i<-values.indices) {
      val vi = values(i)
      val ki = kinds(i)
      prev = (ki, prev) match {
        case (K00, Some(prev)) =>
          f(Interval.fromBounds(prev, Open(vi)))
          None
        case (K01, Some(prev)) =>
          f(Interval.fromBounds(prev, Open(vi)))
          Some(Open(vi))
        case (K10, Some(prev)) =>
          f(Interval.fromBounds(prev, Closed(vi)))
          None
        case (K10, None) =>
          f(Interval.fromBounds(Closed(vi),Closed(vi)))
          None
        case (K11, None) =>
          Some(Closed(vi))
        case (K01, None) =>
          Some(Open(vi))
        // $COVERAGE-OFF$
        case _ => wrong
        // $COVERAGE-ON$
      }
    }
    for(prev <- prev)
      f(Interval.fromBounds(prev, Unbound()))
  }

  private[interval] def kindsAccessor = kinds
}

object IntervalSeq {

  implicit def algebra[T: Order] = new Bool[IntervalSeq[T]] with Eq[IntervalSeq[T]] {

    def eqv(x: IntervalSeq[T], y: IntervalSeq[T]) = x == y

    def zero = IntervalSeq.empty[T]

    def one = IntervalSeq.all[T]

    def complement(a: IntervalSeq[T]) = ~a

    def or(a: IntervalSeq[T], b: IntervalSeq[T]) = a | b

    def and(a: IntervalSeq[T], b: IntervalSeq[T]) = a & b

    override def xor(a: IntervalSeq[T], b: IntervalSeq[T]) = a ^ b
  }

  def atOrAbove[T: Order](value: T) = singleton(false, value, K11)

  def above[T: Order](value: T) = singleton(false, value, K01)

  def atOrBelow[T: Order](value: T) = singleton(true, value, K10)

  def below[T: Order](value: T) = singleton(true, value, K00)

  def point[T: Order](value: T) = singleton(false, value, K10)

  def hole[T: Order](value: T) = singleton(true, value, K01)

  def empty[T: Order]: IntervalSeq[T] = new IntervalSeq[T](false, Array()(classTag), Array(), implicitly[Order[T]])

  def all[T: Order]: IntervalSeq[T] = new IntervalSeq[T](true, Array()(classTag), Array(), implicitly[Order[T]])

  def constant[T: Order](value: Boolean) : IntervalSeq[T] = new IntervalSeq[T](value, Array()(classTag), Array(), implicitly[Order[T]])

  def apply[T: Order](interval: Interval[T]): IntervalSeq[T] = interval.fold {
    case (Closed(a),    Closed(b)) if a == b => point(a)
    case (Unbound(),    Open(x))      => below(x)
    case (Unbound(),    Closed(x))    => atOrBelow(x)
    case (Open(x),      Unbound())    => above(x)
    case (Closed(x),    Unbound())    => atOrAbove(x)
    case (Closed(a),    Closed(b))    => fromTo(a, K11, b, K10)
    case (Closed(a),    Open(b))      => fromTo(a, K11, b, K00)
    case (Open(a),      Closed(b))    => fromTo(a, K01, b, K10)
    case (Open(a),      Open(b))      => fromTo(a, K01, b, K00)
    case (Unbound(),    Unbound())    => all[T]
    case (EmptyBound(), EmptyBound()) => empty[T]
  }

  def apply(text:String) : IntervalSeq[Rational] = {
    val intervals = text.split(';').map(Interval.apply)
    def intervalToIntervalSet(i:Interval[Rational]) : IntervalSeq[Rational] = apply(i)
    val simpleSets = intervals.map(intervalToIntervalSet)
    (empty[Rational] /: simpleSets)(_ | _)
  }

  private def fromTo[T: Order](a:T, ak:Byte, b:T, bk:Byte) =
    new IntervalSeq[T](false, Array(a,b)(classTag), Array(ak,bk), implicitly[Order[T]])

  private def wrong : Nothing = throw new IllegalStateException("")

  private def singleton[T: Order](belowAll: Boolean, value: T, kind: Byte): IntervalSeq[T] =
    new IntervalSeq(belowAll, Array(value)(classTag), Array(kind), implicitly[Order[T]])

  private[interval] val K00 = 0.toByte

  private[interval] val K10 = 1.toByte

  private[interval] val K01 = 2.toByte

  private[interval] val K11 = 3.toByte

  private def classTag[T] = ClassTag.AnyRef.asInstanceOf[ClassTag[T]]

  private def negateKind(kind: Byte) = ((~kind) & 3).toByte

  private def valueAt(kind: Byte): Boolean = (kind & 1) != 0

  private def valueAbove(kind: Byte): Boolean = (kind & 2) != 0

  private def negateKinds(kinds:Array[Byte]): Array[Byte] = {
    var i = 0
    val result = new Array[Byte](kinds.length)
    while(i < kinds.length) {
      result(i) = negateKind(kinds(i))
      i += 1
    }
    result
  }

  private abstract class MergeOperation[T] {

    def lhs:IntervalSeq[T]

    def rhs:IntervalSeq[T]

    private[this] val a0 = lhs.belowAll

    private[this] val b0 = rhs.belowAll

    private[this] val r0 = op(a0, b0)

    private[this] val a = lhs.values

    private[this] val b = rhs.values

    private[this] val ak = lhs.kinds

    private[this] val bk = rhs.kinds

    private[this] val order = lhs.order

    private[this] val r = Array.ofDim[T](a.length + b.length)(classTag)

    private[this] val rk = new Array[Byte](a.length + b.length)

    private[this] var ri = 0

    def copyA(a0: Int, a1: Int): Unit = {
      System.arraycopy(a, a0, r, ri, a1 - a0)
      System.arraycopy(ak, a0, rk, ri, a1 - a0)
      ri += a1 - a0
    }

    def flipA(a0: Int, a1: Int): Unit = {
      System.arraycopy(a, a0, r, ri, a1 - a0)
      var ai = a0
      while(ai < a1) {
        rk(ri) = negateKind(ak(ai))
        ri += 1
        ai += 1
      }
    }

    def copyB(b0: Int, b1: Int): Unit = {
      System.arraycopy(b, b0, r, ri, b1 - b0)
      System.arraycopy(bk, b0, rk, ri, b1 - b0)
      ri += b1 - b0
    }

    def flipB(b0: Int, b1: Int): Unit = {
      System.arraycopy(b, b0, r, ri, b1 - b0)
      var bi = b0
      while(bi < b1) {
        rk(ri) = negateKind(bk(bi))
        ri += 1
        bi += 1
      }
    }

    def op(a:Boolean, b:Boolean) : Boolean

    def op(a:Byte, b:Byte) : Int

    def collision(ai: Int, bi: Int): Unit = {
      val kind = op(ak(ai), bk(bi)).toByte
      val below = rBelow
      if((below && kind != K11) || (!below && kind != K00)) {
        rk(ri) = kind
        r(ri) = a(ai)
        ri += 1
      }
    }

    def fromA(a0:Int, a1: Int, b:Boolean) : Unit

    def fromB(a:Boolean, b0:Int, b1: Int) : Unit

    @inline def valueAbove(kind: Byte): Boolean = (kind & 2) != 0

    @inline def aBelow(i:Int) = if(i>0) valueAbove(ak(i-1)) else a0

    @inline def bBelow(i:Int) = if(i>0) valueAbove(bk(i-1)) else b0

    @inline def rBelow = if(ri > 0) valueAbove(rk(ri-1)) else r0

    def binarySearch(array: Array[T], key: T, from: Int, until: Int): Int = {
      var low = from
      var high = until - 1
      while (low <= high) {
        val mid = (low + high) >>> 1
        val midVal = array(mid)
        val c = order.compare(midVal, key)
        if (c < 0) {
          low = mid + 1
        }
        else if (c > 0) {
          high = mid - 1
        }
        else {
          // scalastyle:off return
          return mid
          // scalastyle:on return
        }
      }
      -(low + 1)
    }

    def merge0(a0: Int, a1: Int, b0: Int, b1: Int): Unit = {
      if (a0 == a1) {
        fromB(aBelow(a0), b0, b1)
      } else if (b0 == b1) {
        fromA(a0, a1, bBelow(b0))
      } else {
        val am = (a0 + a1) / 2
        val res = binarySearch(b, a(am), b0, b1)
        if (res >= 0) {
          // same elements
          val bm = res
          // merge everything below a(am) with everything below the found element
          merge0(a0, am, b0, bm)
          // add the elements a(am) and b(bm)
          collision(am, bm)
          // merge everything above a(am) with everything above the found element
          merge0(am + 1, a1, bm + 1, b1)
        } else {
          val bm = -res - 1
          // merge everything below a(am) with everything below the found insertion point
          merge0(a0, am, b0, bm)
          // add a(am)
          fromA(am, am + 1, bBelow(bm))
          // everything above a(am) with everything above the found insertion point
          merge0(am + 1, a1, bm, b1)
        }
      }
    }

    merge0(0, a.length, 0, b.length)

    def result : IntervalSeq[T] = {
      if(ri == r.length)
        new IntervalSeq(r0, r, rk, order)
      else
        new IntervalSeq(r0, r.take(ri), rk.take(ri), order)
    }
  }

  private class And[T](val lhs:IntervalSeq[T], val rhs:IntervalSeq[T]) extends MergeOperation[T] {

    override def op(a: Boolean, b: Boolean): Boolean = a & b

    override def op(a: Byte, b: Byte): Int = a & b

    override def fromA(a0: Int, a1: Int, b: Boolean): Unit =
      if(b)
        copyA(a0,a1)

    override def fromB(a: Boolean, b0: Int, b1: Int): Unit =
      if(a)
        copyB(b0,b1)
  }

  private class Or[T](val lhs:IntervalSeq[T], val rhs:IntervalSeq[T]) extends MergeOperation[T] {

    override def op(a: Boolean, b: Boolean): Boolean = a | b

    override def op(a: Byte, b: Byte): Int = a | b

    override def fromA(a0: Int, a1: Int, b: Boolean): Unit =
      if(!b)
        copyA(a0,a1)

    override def fromB(a: Boolean, b0: Int, b1: Int): Unit =
      if(!a)
        copyB(b0,b1)
  }

  private class Xor[T](val lhs:IntervalSeq[T], val rhs:IntervalSeq[T]) extends MergeOperation[T] {

    override def op(a: Boolean, b: Boolean): Boolean = a ^ b

    override def op(a: Byte, b: Byte): Int = a ^ b

    override def fromA(a0: Int, a1: Int, b: Boolean): Unit =
      if(!b)
        copyA(a0,a1)
      else
        flipA(a0,a1)

    override def fromB(a: Boolean, b0: Int, b1: Int): Unit =
      if(!a)
        copyB(b0,b1)
      else
        flipB(b0,b1)
  }

  private abstract class BooleanOperation[T] {

    def lhs:IntervalSeq[T]

    def rhs:IntervalSeq[T]

    private[this] val a0 = lhs.belowAll

    private[this] val b0 = rhs.belowAll

    private[this] val a = lhs.values

    private[this] val b = rhs.values

    private[this] val ak = lhs.kinds

    private[this] val bk = rhs.kinds

    private[this] val order = lhs.order

    protected def op(a:Boolean, b:Boolean) : Boolean

    protected def op(a:Byte, b:Byte) : Boolean

    protected def collision(ai: Int, bi: Int): Boolean =
      op(ak(ai), bk(bi))

    protected def fromA(a0:Int, a1: Int, b:Boolean) : Boolean

    protected def fromB(a:Boolean, b0:Int, b1: Int) : Boolean

    @inline def valueAbove(kind: Byte): Boolean = (kind & 2) != 0

    @inline def aBelow(i:Int) = if(i>0) valueAbove(ak(i-1)) else a0

    @inline def bBelow(i:Int) = if(i>0) valueAbove(bk(i-1)) else b0

    def binarySearch(array: Array[T], key: T, from: Int, until: Int): Int = {
      var low = from
      var high = until - 1
      while (low <= high) {
        val mid = (low + high) >>> 1
        val midVal = array(mid)
        val c = order.compare(midVal, key)
        if (c < 0) {
          low = mid + 1
        }
        else if (c > 0) {
          high = mid - 1
        }
        else {
          // scalastyle:off return
          return mid
          // scalastyle:on return
        }
      }
      -(low + 1)
    }

    def merge0(a0: Int, a1: Int, b0: Int, b1: Int): Boolean = {
      if(a0 == a1 && b0 == b1) {
        true
      } else if (a0 == a1) {
        fromB(aBelow(a0), b0, b1)
      } else if (b0 == b1) {
        fromA(a0, a1, bBelow(b0))
      } else {
        val am = (a0 + a1) / 2
        val res = binarySearch(b, a(am), b0, b1)
        if (res >= 0) {
          // same elements
          val bm = res
          // merge everything below a(am) with everything below the found element
          merge0(a0, am, b0, bm) &&
          // add the elements a(am) and b(bm)
          collision(am, bm) &&
          // merge everything above a(am) with everything above the found element
          merge0(am + 1, a1, bm + 1, b1)
        } else {
          val bm = -res - 1
          // merge everything below a(am) with everything below the found insertion point
          merge0(a0, am, b0, bm) &&
          // add a(am)
          fromA(am, am + 1, bBelow(bm)) &&
          // everything above a(am) with everything above the found insertion point
          merge0(am + 1, a1, bm, b1)
        }
      }
    }

    val result = op(a0, b0) && merge0(0, a.length, 0, b.length)
  }

  private class IsSupersetOf[T](val lhs:IntervalSeq[T], val rhs:IntervalSeq[T]) extends BooleanOperation[T] {

    override def op(a: Boolean, b: Boolean): Boolean = a | !b

    override def op(a: Byte, b: Byte): Boolean = ((a | ~b) & 3) == 3

    override def fromA(a0: Int, a1: Int, b: Boolean): Boolean = !b

    override def fromB(a: Boolean, b0: Int, b1: Int): Boolean = a
  }

  private class Disjoint[T](val lhs:IntervalSeq[T], val rhs:IntervalSeq[T]) extends BooleanOperation[T] {

    override def op(a: Boolean, b: Boolean): Boolean = !(a & b)

    override def op(a: Byte, b: Byte): Boolean = (a & b) == 0

    override def fromA(a0: Int, a1: Int, b: Boolean): Boolean = !b

    override def fromB(a: Boolean, b0: Int, b1: Int): Boolean = !a
  }

  private final class IntervalIterator[T:Order](s: IntervalSeq[T]) extends AbstractIterator[Interval[T]] {

    private[this] val values = s.values

    private[this] val kinds = s.kinds

    private[this] var lower: Bound[T] = if (s.belowAll) Unbound() else null

    private[this] var i = 0

    private[this] def nextInterval() = {
      var result: Interval[T] = null
      if (i < kinds.length) {
        val kind = kinds(i)
        val value = values(i)
        i += 1
        if (lower eq null) kind match {
          case K10 =>
            result = Interval.point(value)
            lower = null
          case K11 =>
            result = null
            lower = Closed(value)
          case K01 =>
            result = null
            lower = Open(value)
          case _ => wrong
        } else kind match {
          case K01 =>
            val upper = Open(value)
            result = Interval.fromBounds[T](lower, upper)
            lower = upper
          case K00 =>
            val upper = Open(value)
            result = Interval.fromBounds[T](lower, upper)
            lower = null
          case K10 =>
            val upper = Closed(value)
            result = Interval.fromBounds[T](lower, upper)
            lower = null
          case _ => wrong
        }
      } else if (lower ne null) {
        result = Interval.fromBounds(lower, Unbound())
        lower = null
      } else {
        Iterator.empty.next()
      }
      result
    }

    def hasNext = (i < kinds.length) || (lower ne null)

    @tailrec
    override def next(): Interval[T] = {
      val result = nextInterval()
      if (result ne null)
        result
      else
        next()
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy