Coder Social home page Coder Social logo

fingertree's Introduction

FingerTree

Build Status Maven Central

statement

FingerTree is an immutable sequence data structure in Scala programming language, offering O(1) prepend and append, as well as a range of other useful properties [^1]. Finger trees can be used as building blocks for queues, double-ended queues, priority queues, indexed and summed sequences.

FingerTree is (C)opyright 2011–2020 by Hanns Holger Rutz. All rights reserved. It is released under the GNU Lesser General Public License v2.1+ and comes with absolutely no warranties. To contact the author, send an e-mail to contact at sciss.de.

The current implementation is a rewrite of previous versions. It tries to combine the advantages of the finger tree found in Scalaz (mainly the ability to have reducers / measures) and of the finger tree implementation by Daniel Spiewak (small, self-contained, much simpler and faster), but also has a more idiomatic Scala interface and comes with a range of useful applications, such as indexed and summed sequences.

[^1] Hinze, R. and Paterson, R., Finger trees: a simple general-purpose data structure, Journal of Functional Programming, vol. 16 no. 2 (2006), pp. 197--217

linking

The following dependency is necessary:

"de.sciss" %% "fingertree" % v

The current version v is "1.5.5".

building

This builds with sbt against Scala 2.13, 2.12, Dotty (JVM) and Scala 2.13 (JS). The last version to support Scala 2.11 is v1.5.4.

Standard targets are compile, package, doc, console, test, publishLocal.

contributing

Please see the file CONTRIBUTING.md

using

You can either implement your own data structure by wrapping a plain FingerTree instance. Trait FingerTreeLike can be used as a basis, it has two abstract methods tree and wrap which would need to be implemented.

Or you can use any of the provided ready-made data structures, such as IndexedSeq or IndexedSummedSeq. While the former might not be particularly interesting, as it does not add any functionality that is not found already in Scala's own immutable IndexedSeq (i.e. Vector), the latter provides the additional feature of measuring not just the indexed positions of the tree elements, but also an accumulative "sum" of any sort.

The core element for new structures is to provide an instance of Measure which is used by the finger tree to calculate the annotated meta data of the elements. The measure provides a zero value, a unit method which measures exactly one element, and a summation method |+| which accumulates measured data. To work correctly with the caching mechanism of the finger tree, |+| must be associative, i.e. (a |+| b) |+| c = a |+| (b |+| c).

Future versions will provide more ready-made structures, such as ordered sequences and interval sequences. In the meantime, you can check out the previous Scalaz based version of this project at git tag Scalaz, which includes those structures.

Indexed and summed sequence

A sequence that has efficient element look-up (random access), and additionally integrates its elements (a running summation).

import de.sciss.fingertree._

implicit val m = Measure.SummedIntInt
val sq = IndexedSummedSeq[Int,Int]((1 to 10).map(i => i * i): _*)
sq.sum  // result: 385
sq.sumUntil(sq.size/2)  // result: 55

Ranged sequence

A sequence of elements indexed by intervals. Allows for interval searches such as overlaps and intersections.

import de.sciss.fingertree._

val sq = RangedSeq(
  (1685, 1750) -> "Bach",
  (1866, 1925) -> "Satie",
  (1883, 1947) -> "Russolo",
  (1883, 1965) -> "Varèse",
  (1910, 1995) -> "Schaeffer",
  (1912, 1992) -> "Cage"
)(_._1, Ordering.Int)

implicit class Names(it: Iterator[(_, _)]) {
  def names = it.map(_._2).mkString(", ")
}

sq.intersect(1900).names               // were alive in this year: Satie, Varèse, Russolo
sq.filterIncludes(1900 -> 1930).names  // were alive during these years: Varèse, Russolo
sq.filterOverlaps(1900 -> 1930).names  // were alive at some point of this period: all but Bach

Ordered sequence

An ordered sequence that allows to find closest (floor or ceil) elements and create partial iterators.

import de.sciss.fingertree._

val sym = Seq(("Cs", 55), ("Fr", 87), ("K", 19), ("Li", 3), ("Na", 11), ("Rb", 37))
val sq  = OrderedSeq(sym: _*)(_._2, Ordering.Int)
val li  = sq.toList // List((Li,3), (Na,11), (K,19), (Rb,37), (Cs,55), (Fr,87))
val ceil20  = sq.ceilIterator  (20).toList  // List((Rb,37), (Cs,55), (Fr,87))
val floor20 = sq.floorIterator (20).toList  // List((K,19), (Rb,37), (Cs,55), (Fr,87))

todo

  • efficient bulk loading
  • (an max-priority-queue -- less interesting though, because there are already good structures in standard scala collections)
  • proper equals and hashCode methods
  • RangedSeq: element removal

fingertree's People

Contributors

miguel-negrao avatar sciss avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

fingertree's Issues

FingerTree.init

this is broken now it seems -- it drops the two right-most elements instead of just dropping one.

SortedSet / SortedMap

In GitLab by @Sciss on Dec 31, 2018, 13:52

since s.c.i.SortedMap does not have any API for querying floor and ceil elements of a key, this would be a very useful addition.

find1 bug ?

Hi,

After many hours debuging (many postlns...) my SuperCollider code, I finally decided to try if this was actually working in scala and I get the exact same error that I get in sc:

println( IndexedSeq(0,1,2,3,4,5,6,7,8,9,10,11,12)(7)) returns 9
println( IndexedSeq(0,1,2,3,4,5,6,7,8,9,10,11,12)(8)) returns 9 also.

My analysis in SuperCollider:

+++++find1+++++++++++
_Deep prfind1_
++Deep++[One(0), ++Deep++[One(Three(1, 2, 3)), !Empty!, Two(Three(4, 5, 6), Three(7, 8, 9))], Three(10, 11, 12)]
Deep measure :
class IndexedMeasureFT (0x10fca0fc0) {
got pred, init:[ a Function, 0 ]
Deep: first index check: 1
Deep: second index check: 10
foind in middle
_Deep prfind1_
++Deep++[One(Three(1, 2, 3)), !Empty!, Two(Three(4, 5, 6), Three(7, 8, 9))]
Deep measure :
Instance of DigitMeasureFT { (0x11180e588, gc=24, fmt=00, flg=00, set=02)
got pred, init:[ a Function, 1 ]
Deep: first index check: 4
Deep: second index check: 4
found in suffix
Two: first index check: 7
Two: measure dump
Instance of DigitMeasureFT { (0x11180f548, gc=24, fmt=00, flg=00, set=02)
Deep returned from suffix: [ 4, Three(7, 8, 9) ]
Deep: got from the middle: [ 4, Three(7, 8, 9) ]
[ 4, 1 ]
Three: first index check: 5
Three: second index check: 6
Deep returning from the middle: [ 4, 9 ]
9

So you see, when it gets to Two(Three(4, 5, 6), Three(7, 8, 9)) it detects correctly that it's in the second slot, but then it goes back to find1 of Deep which will pass the index 4 to the find1 of Three(7, 8, 9) not taking into account that it already discarded the Three(4, 5, 6).

Can you reproduce this ?

I think find1 of One, Two, etc need to return more information then just the element. Shouldn't they also return the measure of the elements that were already checked ?

equals

all wrappers (Indexed, IndexedSeq, Ordered, Ranged) should implement a proper equals method? Or maybe not, since evaluation is lazy?

RangedSeq.nextAfter

Find the first interval beginning at or after a given point.

As a workaround, if the point type is known, e.g. Long, this would be findIncludes((p, Long.MaxValue). Then findIncludes doesn't exist yet, either. So filterIncludes.headOption (if iterator had a headOption)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.