This repository has been archived by the owner on Feb 19, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 82
/
DistanceBinner.scala
75 lines (61 loc) · 2.44 KB
/
DistanceBinner.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package epic.features
import java.util
/**
*
* @author dlwh
*/
@SerialVersionUID(1L)
class DistanceBinner private (val binThresholds: Array[Int], preserveDirection: Boolean) extends Serializable{
def numBins = binThresholds.length + 1
def this(numBins: Int, numExactBins: Int, preserveDirection: Boolean) = this(DistanceBinner.mkBinArray(numBins, numExactBins), preserveDirection)
def this(numBins: Int = 8, preserveDirection: Boolean = true) = this(numBins, numBins/2+1, preserveDirection)
util.Arrays.sort(binThresholds)
val bins = Array.tabulate(binThresholds.last + 5){dist =>
var bin = util.Arrays.binarySearch(binThresholds, math.abs(dist))
if (bin < 0) bin = ~bin
if (preserveDirection) math.signum(dist) * (bin + 1)
else bin + 1
}
val negativeBins = Array.tabulate(binThresholds.last + 5){dist =>
var bin = util.Arrays.binarySearch(binThresholds, math.abs(dist))
if (bin < 0) bin = ~bin
if (preserveDirection) -(bin + 1)
else bin + 1
}
def distanceBin(a: Int, b: Int): Int = {
val dist: Int = b - a
distanceBin(dist)
}
def distanceBin(dist: Int): Int = {
val array = if (dist < 0) negativeBins else bins
val adist = math.min(math.abs(dist), array.length - 1)
array(adist)
}
def binnedDistance(a: Int, b: Int): Int = {
binnedDistance(b-a)
}
def binnedDistance(dist: Int): Int = {
val bin = distanceBin(dist)
if (dist == 0) 0
else if (bin < 0) {
if (-bin-1 >= binThresholds.length)
-(binThresholds.last + 1)
else -binThresholds(-bin-1)
} else if (bin >= binThresholds.length) {
binThresholds.last + 1
} else binThresholds(bin-1)
}
def binIds = 0 +: binThresholds.toIndexedSeq :+ (binThresholds.last + 1)
}
object DistanceBinner {
def mkBinArray(numBins: Int, numExactBins: Int): Array[Int] = {
if (numBins <= 1) Array(1)
else {
val exact = Array.range(1, numExactBins+1)
exact ++ Array.iterate(exact.last, (numBins - numExactBins) max 1)(exact => exact * 2).drop(1)
}
}
def apply(binThresholds: Array[Int], preserveDirection: Boolean): DistanceBinner = new DistanceBinner(binThresholds, preserveDirection)
def apply(numBins: Int, numExactBins: Int, preserveDirection: Boolean):DistanceBinner = apply(DistanceBinner.mkBinArray(numBins, numExactBins), preserveDirection)
def apply(numBins: Int = 8, preserveDirection: Boolean = true): DistanceBinner = apply(numBins, numBins/2 + 1, preserveDirection)
}