Skip to content

Commit 6beac2f

Browse files
committed
index impl
1 parent 51343db commit 6beac2f

File tree

3 files changed

+127
-90
lines changed

3 files changed

+127
-90
lines changed
Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
package qnt.breeze
22

3-
import breeze.linalg.{SliceVector, Vector}
3+
import breeze.linalg.Vector
44

5-
import scala.collection.mutable
5+
import scala.collection.{IterableOnce, mutable}
66
import scala.reflect.ClassTag
77

8-
class IndexVector[V]
9-
(
8+
class IndexVector[V] (
109
private val data: Array[V],
10+
val unique: Boolean,
1111
val ordered: Boolean,
1212
val reversed: Boolean,
13-
)(implicit ord: Ordering[V], tag: ClassTag[V]) extends IndexVectorLike[V] {
13+
) (implicit ord: Ordering[V], tag: ClassTag[V]) extends IndexVectorLike[V] {
1414

1515
private val valueToIdxMap = new mutable.HashMap[V,Int]()
1616

@@ -22,21 +22,21 @@ class IndexVector[V]
2222
}
2323
for (i <- data.indices) {
2424
var v = data(i)
25-
if(valueToIdxMap.contains(v)) {
25+
if(unique && valueToIdxMap.contains(v)) {
2626
throw new IllegalArgumentException(s"duplicate idx=$i val=$v")
2727
}
2828
valueToIdxMap(v) = i
2929
}
3030

3131
override def copy: IndexVector[V] = {
32-
IndexVector[V](toArray, ordered, reversed)
32+
IndexVector[V](toArray, unique, ordered, reversed)
3333
}
3434

3535
override def update(i: Int, v: V): Unit = {
3636
if (data(i) == v) {
3737
return
3838
}
39-
if (data.contains(v)) {
39+
if (unique && data.contains(v)) {
4040
throw new IllegalStateException(s"duplicate $i")
4141
}
4242
if (ordered) {
@@ -56,43 +56,48 @@ class IndexVector[V]
5656
valueToIdxMap.remove(data(i))
5757
data(i) = v
5858
valueToIdxMap(v) = i
59-
60-
SliceVector
6159
}
6260

6361
override def length: Int = data.length
6462

6563
override def apply(i: Int): V = data(i)
6664

67-
override def indexOfExact(v:V): Option[Int] = valueToIdxMap.get(v)
68-
69-
override def sliceSeq(idx: Iterator[Int]): SliceIndexVector[V] = new SliceIndexVector[V](this, idx.toIndexedSeq)
65+
override def indexOfExact(v:V): Option[Int] =
66+
if(unique) valueToIdxMap.get(v) else throw new IllegalStateException("not unique")
7067

68+
override def sliceIdx(idx: IterableOnce[Int]): SliceIndexVector[V] =
69+
new SliceIndexVector[V](this, idx.iterator.toIndexedSeq)
7170

7271
}
7372

7473
object IndexVector {
7574

76-
def apply[V](data: Array[V], ordered: Boolean, reversed: Boolean)
75+
def apply[V](data: IterableOnce[V], unique: Boolean, ordered: Boolean, reversed: Boolean)
7776
(implicit ord: Ordering[V], tag: ClassTag[V]) : IndexVector[V] = {
78-
new IndexVector[V](data, ordered, reversed)(ord, tag)
77+
new IndexVector[V](data.iterator.toArray, unique, ordered, reversed)(ord, tag)
7978
}
8079

81-
def apply[V](sliceVector: SliceVector[Int, V])
82-
(implicit ord: Ordering[V], tag: ClassTag[V]) : IndexVector[V] = {
83-
sliceVector.tensor match {
84-
case t: IndexVector[V] =>
85-
val values = sliceVector.toArray
86-
apply(values, t.ordered, t.reversed)
87-
case _ =>
88-
throw new IllegalArgumentException("tensor of slice is not IndexVector")
89-
}
80+
def apply[V](data: IterableOnce[V])(implicit ord: Ordering[V], tag: ClassTag[V]) : IndexVector[V] = {
81+
val arr = data.iterator.toArray
82+
val unique = arr.distinct.length == arr.length
83+
val ascending = arr.indices.forall(i => i == arr.indices.end || ord.lt(arr(i), arr(i+1)))
84+
val descending = arr.indices.forall(i => i == arr.indices.end || ord.gt(arr(i), arr(i+1)))
85+
apply(arr, unique, ascending || descending, descending)
9086
}
9187

92-
def apply[V](vector: Vector[V], ordered: Boolean, reversed: Boolean)
88+
def apply[V](sliceVector: SliceIndexVector[V])
9389
(implicit ord: Ordering[V], tag: ClassTag[V]) : IndexVector[V] = {
94-
val values = vector.toArray
95-
apply(values, ordered, reversed)
90+
val values = sliceVector.toArray
91+
val t = sliceVector.indexVector
92+
apply(values, t.unique, t.ordered, t.reversed)
9693
}
94+
95+
def apply[V](vector: Vector[V], unique: Boolean, ordered: Boolean, reversed: Boolean)
96+
(implicit ord: Ordering[V], tag: ClassTag[V]) : IndexVector[V]
97+
= apply(vector.valuesIterator, unique, ordered, reversed)
98+
99+
def apply[V](vector: Vector[V]) (implicit ord: Ordering[V], tag: ClassTag[V]) : IndexVector[V]
100+
= apply(vector.valuesIterator)
101+
97102
}
98103

src/main/scala/qnt/breeze/IndexVectorLike.scala

Lines changed: 79 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,37 @@ import scala.reflect.ClassTag
66

77
trait IndexVectorLike[V] extends breeze.linalg.Vector[V] with VectorLike[V, IndexVectorLike[V]] {
88

9-
// TODO unique ?
9+
def unique: Boolean
1010
def ordered: Boolean
11-
1211
def reversed: Boolean
1312

1413
override def activeSize: Int = length
15-
1614
override def activeIterator: Iterator[(Int, V)] = iterator
17-
1815
override def activeValuesIterator: Iterator[V] = valuesIterator
19-
2016
override def activeKeysIterator: Iterator[Int] = keysIterator
21-
2217
override def repr: IndexVectorLike[V] = this
23-
2418
override def toString: String = {
25-
valuesIterator.mkString(s"IndexVector(ordered=$ordered, reversed=$reversed, data=[", ", ", "])")
19+
valuesIterator.mkString(s"Index(unique=$unique,ordered=$ordered,reversed=$reversed,data=[", ", ", "])")
2620
}
2721

2822
override def copy: IndexVector[V]
2923

3024
def merge(other: IndexVectorLike[V])(implicit ord: Ordering[V], tag: ClassTag[V]): IndexVectorLike[V] = {
3125
var vals = Array.concat(toArray, other.toArray)
32-
vals = vals.distinct
26+
if(unique) {
27+
vals = vals.distinct
28+
}
3329
if (ordered) {
3430
vals = vals.sorted(ord)
3531
if (reversed) {
3632
vals = vals.reverse
3733
}
3834
}
39-
IndexVector[V](vals, ordered, reversed)
35+
IndexVector[V](vals, unique, ordered, reversed)
4036
}
4137

4238
def indexOfUnexact(value: V)(implicit ord: Ordering[V]): Option[(Int, Int)] = {
43-
var exact = indexOfExact(value)
39+
var exact = if(unique) indexOfExact(value) else None
4440
if (exact.isDefined) {
4541
Some((exact.get, exact.get))
4642
} else {
@@ -50,27 +46,52 @@ trait IndexVectorLike[V] extends breeze.linalg.Vector[V] with VectorLike[V, Inde
5046

5147
def indexOfExact(value: V): Option[Int]
5248

49+
// returns range of indexes
50+
// or index of first element that less and index of first element that great
51+
// or None
52+
// TODO tests
5353
def indexOfBinarySearch(value: V)(implicit ord: Ordering[V]): Option[(Int, Int)] = {
54-
if (!ordered) {
54+
if (!ordered || length < 1) {
5555
return None
5656
}
5757

58-
var leftIdx = 0
59-
var rightIdx = this.length - 1
58+
var leftLeftIdx = 0
59+
var rightRightIdx = this.length - 1
6060

61-
if (leftIdx > rightIdx) {
62-
return None
61+
var leftVal: V = apply(leftLeftIdx)
62+
var rightVal: V = apply(rightRightIdx)
63+
64+
@inline
65+
def findSameRightIdx(leftIdx: Int, leftVal: V) = {
66+
var rightIdx = leftIdx
67+
if (!unique) {
68+
do rightIdx += 1
69+
while (rightIdx < length && apply(rightIdx) == leftVal)
70+
rightIdx -= 1
71+
}
72+
rightIdx
6373
}
6474

65-
var leftVal: V = apply(leftIdx)
66-
var rightVal: V = apply(rightIdx)
75+
@inline
76+
def findSameLeftIdx(rightIdx: Int, rightVal: V) = {
77+
var leftIdx = rightIdx
78+
if (!unique) {
79+
do leftIdx -= 1
80+
while (rightIdx > 0 && apply(leftIdx) == rightVal)
81+
leftIdx += 1
82+
}
83+
leftIdx
84+
}
85+
86+
var leftRightIdx = findSameRightIdx(leftLeftIdx, leftVal)
87+
var rightLeftIdx = findSameLeftIdx(rightRightIdx, rightVal)
6788

6889
if (leftVal == value) {
69-
return Some((leftIdx, leftIdx))
90+
return Some((leftLeftIdx, leftRightIdx))
7091
}
7192

7293
if (rightVal == value) {
73-
return Some((rightIdx, rightIdx))
94+
return Some((leftLeftIdx, rightLeftIdx))
7495
}
7596

7697
if (ord.lt(rightVal, value) ^ reversed) {
@@ -81,64 +102,75 @@ trait IndexVectorLike[V] extends breeze.linalg.Vector[V] with VectorLike[V, Inde
81102
return None
82103
}
83104

84-
while (rightIdx - leftIdx > 1) {
85-
val midIdx = (rightIdx + leftIdx) / 2
105+
while (rightLeftIdx - leftRightIdx > 0) {
106+
val midIdx = (rightLeftIdx + leftRightIdx) / 2
86107
val midVal = apply(midIdx)
108+
109+
var midLeftIdx = findSameLeftIdx(midIdx, midVal)
110+
var midRightIdx = findSameRightIdx(midIdx, midVal)
111+
87112
if (midVal == value) {
88-
return Some((midIdx, midIdx))
113+
return Some((midLeftIdx, midRightIdx))
89114
} else if (ord.lt(midVal, value) ^ reversed) {
90-
leftIdx = midIdx
115+
leftLeftIdx = midLeftIdx
116+
leftRightIdx = midRightIdx
91117
leftVal = midVal
92118
} else if (ord.gt(midVal, value) ^ reversed) {
93-
rightIdx = midIdx
119+
rightRightIdx = midRightIdx
120+
rightLeftIdx = midLeftIdx
94121
rightVal = midVal
95122
}
96123
}
97-
Some((leftIdx, rightIdx))
124+
Some((leftRightIdx, rightLeftIdx))
98125
}
99126

100127
def sliceMask(mask: breeze.linalg.Vector[Boolean]): SliceIndexVector[V] = sliceMask(mask.valuesIterator)
101-
def sliceMask(mask: Boolean*): SliceIndexVector[V] = sliceMask(mask.iterator)
102-
def sliceMask(mask: Iterable[Boolean]): SliceIndexVector[V] = sliceMask(mask.iterator)
103-
def sliceMask(mask: Iterator[Boolean]): SliceIndexVector[V] = sliceSeq(mask.zipWithIndex.filter(_._1).map(_._2))
128+
def sliceMask(mask: Boolean*): SliceIndexVector[V] = sliceMask(mask)
129+
def sliceMask(mask: IterableOnce[Boolean]): SliceIndexVector[V] =
130+
sliceIdx(mask.iterator.zipWithIndex.filter(_._1).map(_._2))
104131

105-
def sliceSeq(idx: breeze.linalg.Vector[Int]): SliceIndexVector[V] = sliceSeq(idx.valuesIterator)
106-
def sliceSeq(idx: Int*): SliceIndexVector[V] = sliceSeq(idx.iterator)
107-
def sliceSeq(idx: Iterable[Int]): SliceIndexVector[V] = sliceSeq(idx.iterator)
108-
def sliceSeq(idx: Iterator[Int]): SliceIndexVector[V]
132+
def sliceIdx(idx: breeze.linalg.Vector[Int]): SliceIndexVector[V] = sliceIdx(idx.valuesIterator)
133+
def sliceIdx(idx: Int*): SliceIndexVector[V] = sliceIdx(idx.iterator)
134+
def sliceIdx(idx: IterableOnce[Int]): SliceIndexVector[V]
109135

110-
def sliceRange(start: Int, end: Int, step: Int, left: Boolean, right: Boolean, round: Boolean)
111-
: SliceIndexVector[V] = sliceSeq(RoundArrayRange(length, start, end, step, left, right, round))
136+
def sliceRange(start: Int, end: Int, step: Int, keepStart: Boolean, keepEnd: Boolean, round: Boolean)
137+
: SliceIndexVector[V] = sliceIdx(RoundArrayRange(length, start, end, step, keepStart, keepEnd, round))
112138

113139
def loc(v: V): Option[Int] = indexOfExact(v)
114140

115-
def sliceLoc(v: breeze.linalg.Vector[V]): SliceIndexVector[V] = sliceLoc(v.valuesIterator)
116-
def sliceLoc(v: V*):SliceIndexVector[V] = sliceLoc(v.iterator)
117-
def sliceLoc(v: Iterable[V]): SliceIndexVector[V] = sliceLoc(v.iterator)
118-
def sliceLoc(v: Iterator[V]): SliceIndexVector[V] = {
119-
var idxo = v.map(indexOfExact).filter(_.isDefined).map(_.get)
120-
sliceSeq(idxo)
141+
def sliceLoc(vals: breeze.linalg.Vector[V]): SliceIndexVector[V] = sliceLoc(vals.valuesIterator)
142+
def sliceLoc(vals: V*):SliceIndexVector[V] = sliceLoc(vals.iterator)
143+
def sliceLoc(vals: IterableOnce[V]): SliceIndexVector[V] = {
144+
sliceIdx(vals.iterator.map(indexOfExact).filter(_.isDefined).map(_.get))
121145
}
122146

123147
def sliceLocRange(start: V, end: V, step: Int = 1,
124-
left: Boolean = true, right: Boolean = true, round: Boolean = true)
148+
keepStart: Boolean = true, keepEnd: Boolean = true, round: Boolean = true)
125149
(implicit ord: Ordering[V], tag: ClassTag[V]): SliceIndexVector[V] = {
126150
val startIdx = indexOfUnexact(start)(ord)
127151
val endIdx = indexOfUnexact(end)(ord)
128152
if(startIdx.isEmpty || endIdx.isEmpty) {
129-
IndexVectorLike.empty[V].sliceSeq(Seq())
153+
IndexVectorLike.empty[V].sliceIdx()
130154
} else {
131155
sliceRange(
132-
if(step > 0) startIdx.get._2 else startIdx.get._1,
133-
if(step > 0) endIdx.get._1 else endIdx.get._2,
156+
if(step > 0)
157+
if(!unique && keepStart && apply(startIdx.get._1) == start) startIdx.get._1 else startIdx.get._2
158+
else
159+
if(!unique && keepEnd && apply(startIdx.get._1) == start) startIdx.get._2 else startIdx.get._1
160+
,
161+
if(step > 0)
162+
if(!unique && keepEnd && apply(endIdx.get._1) == end) startIdx.get._2 else startIdx.get._1
163+
else
164+
if(!unique && keepStart && apply(endIdx.get._1) == end) startIdx.get._1 else startIdx.get._2
165+
,
134166
step,
135-
left, right, round
167+
keepStart, keepEnd, round
136168
)
137169
}
138170
}
139171
}
140172

141173
object IndexVectorLike {
142174
def empty[V](implicit ord: Ordering[V], tag: ClassTag[V])
143-
= new IndexVector[V](Array[V](), true, false)(ord, tag)
175+
= new IndexVector[V](Array.empty[V], true,true, false)(ord, tag)
144176
}

src/main/scala/qnt/breeze/SliceIndexVector.scala

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,36 @@ package qnt.breeze
33
import scala.reflect.ClassTag
44

55
class SliceIndexVector[V](
6-
tensor: IndexVector[V],
7-
slices: IndexedSeq[Int]
8-
)
9-
(implicit ord: Ordering[V], tag: ClassTag[V])
6+
val indexVector: IndexVector[V],
7+
val slices: IndexedSeq[Int]
8+
) (implicit ord: Ordering[V], tag: ClassTag[V])
109
extends IndexVectorLike[V] {
1110

12-
override val ordered: Boolean = tensor.ordered && (
13-
slices.indices.forall(i => i == slices.length - 1 || slices(i) < slices(i + 1))
14-
||
15-
slices.indices.forall(i => i == slices.length - 1 || slices(i) > slices(i + 1))
16-
)
11+
override val unique: Boolean = indexVector.unique && slices.distinct.length == slices.length
1712

18-
override val reversed: Boolean = tensor.reversed ^ slices.indices.forall(i => i == slices.length - 1 || slices(i) > slices(i + 1))
13+
override val ordered: Boolean = indexVector.ordered &&
14+
(slices.indices.forall(i => i == slices.length - 1 || slices(i) < slices(i + 1))
15+
|| slices.indices.forall(i => i == slices.length - 1 || slices(i) > slices(i + 1)))
16+
17+
override val reversed: Boolean = indexVector.reversed ^
18+
slices.indices.forall(i => i == slices.indices.end || slices(i) > slices(i + 1))
1919

2020
private val tensorToLocalIdxMap = slices.zipWithIndex.toMap
2121

2222
override def indexOfExact(value: V): Option[Int] = {
23-
var origIdx = tensor.indexOfExact(value)
23+
var origIdx = indexVector.indexOfExact(value)
2424
if (origIdx.isEmpty) origIdx else tensorToLocalIdxMap.get(origIdx.get)
2525
}
2626

27-
override def copy: IndexVector[V] = IndexVector(toArray, ordered, reversed)
27+
override def copy: IndexVector[V] = IndexVector(toArray, unique, ordered, reversed)
2828

2929
override def length: Int = slices.length
3030

31-
override def apply(i: Int): V = tensor(slices(i))
31+
override def apply(i: Int): V = indexVector(slices(i))
3232

33-
override def update(i: Int, v: V): Unit = tensor(slices(i))
33+
override def update(i: Int, v: V): Unit = indexVector(slices(i))
3434

35-
override def sliceSeq(idx: Iterator[Int]): SliceIndexVector[V]
36-
= new SliceIndexVector[V](tensor, idx.map(i => slices(i)).toIndexedSeq)
35+
override def sliceIdx(idx: IterableOnce[Int]): SliceIndexVector[V]
36+
= new SliceIndexVector[V](indexVector, idx.iterator.map(i => slices(i)).toIndexedSeq)
3737

3838
}

0 commit comments

Comments
 (0)