1 | package com.github.sanity.pav | |
2 | ||
3 | import com.github.sanity.pav.PairAdjacentViolators.InterpolationStrategy.SPLINE | |
4 | ||
5 | /** | |
6 | * Implements the "pair adjacent violators" algorithm, also known as "pool adjacent violators", for isotonic regression. | |
7 | */ | |
8 | ||
9 | ||
10 | class PairAdjacentViolators @JvmOverloads constructor(originalPoints: Iterable<Point>, mode: PAVMode = PAVMode.INCREASING) { | |
11 | ||
12 | /** | |
13 | * A point in 2D space, with an optional weight (defaults to 1). | |
14 | */ | |
15 |
3
1. getWeight : replaced return of double value with -(x + 1) for com/github/sanity/pav/PairAdjacentViolators$Point::getWeight → SURVIVED 2. getX : replaced return of double value with -(x + 1) for com/github/sanity/pav/PairAdjacentViolators$Point::getX → KILLED 3. getY : replaced return of double value with -(x + 1) for com/github/sanity/pav/PairAdjacentViolators$Point::getY → KILLED |
data class Point @JvmOverloads constructor(val x: Double, val y: Double, val weight: Double = 1.0) { |
16 | fun merge(other: Point): Point { | |
17 |
1
1. merge : Replaced double addition with subtraction → KILLED |
val combinedWeight = weight + other.weight |
18 |
4
1. merge : Replaced double multiplication with division → KILLED 2. merge : Replaced double multiplication with division → KILLED 3. merge : Replaced double addition with subtraction → KILLED 4. merge : Replaced double division with multiplication → KILLED |
val nx = ((x * weight) + (other.x * other.weight)) / combinedWeight |
19 |
4
1. merge : Replaced double multiplication with division → KILLED 2. merge : Replaced double multiplication with division → KILLED 3. merge : Replaced double addition with subtraction → KILLED 4. merge : Replaced double division with multiplication → KILLED |
val ny = ((y * weight) + (other.y * other.weight)) / combinedWeight |
20 |
1
1. merge : mutated return of Object value for com/github/sanity/pav/PairAdjacentViolators$Point::merge to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return Point(nx, ny, combinedWeight) |
21 | } | |
22 | ||
23 |
2
1. toString : negated conditional → NO_COVERAGE 2. toString : mutated return of Object value for com/github/sanity/pav/PairAdjacentViolators$Point::toString to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
override fun toString() = "($x, $y${if (weight != 1.0) " :$weight" else ""})" |
24 | } | |
25 | ||
26 | /** | |
27 | * The points after the regression, should either be increasing or decreasing depending | |
28 | * on how the PairAdjacentViolators object is configured. | |
29 | */ | |
30 |
1
1. getIsotonicPoints : mutated return of Object value for com/github/sanity/pav/PairAdjacentViolators::getIsotonicPoints to ( if (x != null) null else throw new RuntimeException ) → KILLED |
val isotonicPoints: List<Point> |
31 | ||
32 | init { | |
33 | val points: PairSubstitutingDoublyLinkedList<Point> = PairSubstitutingDoublyLinkedList.createFromList(originalPoints.sortedBy { it.x }) | |
34 |
1
1. |
points.iterate { cursor -> |
35 | val previous = cursor.previousValue | |
36 | val next = cursor.nextValue | |
37 |
1
1. invoke : negated conditional → KILLED |
if (previous != null) { |
38 | val shouldMerge = when (mode) { | |
39 |
2
1. invoke : changed conditional boundary → SURVIVED 2. invoke : negated conditional → KILLED |
PAVMode.INCREASING -> previous.y >= next.y |
40 |
2
1. invoke : changed conditional boundary → SURVIVED 2. invoke : negated conditional → KILLED |
PAVMode.DECREASING -> previous.y <= next.y |
41 | } | |
42 |
1
1. invoke : negated conditional → KILLED |
if (shouldMerge) { |
43 | previous.merge(next) | |
44 | } else { | |
45 | null | |
46 | } | |
47 | } else { | |
48 | null | |
49 |
1
1. invoke : mutated return of Object value for com/github/sanity/pav/PairAdjacentViolators$1::invoke to ( if (x != null) null else throw new RuntimeException ) → KILLED |
} |
50 | } | |
51 | ||
52 | isotonicPoints = points.toArrayList() | |
53 | } | |
54 | ||
55 | @JvmOverloads fun interpolator(strategy: InterpolationStrategy = SPLINE): (Double) -> Double { | |
56 | when (strategy) { | |
57 |
1
1. interpolator : mutated return of Object value for com/github/sanity/pav/PairAdjacentViolators::interpolator to ( if (x != null) null else throw new RuntimeException ) → KILLED |
SPLINE -> return { |
58 | val spline = MonotoneSpline(isotonicPoints.map { it.x }.toDoubleArray(), isotonicPoints.map { it.y }.toDoubleArray()) | |
59 |
1
1. invoke : replaced return of double value with -(x + 1) for com/github/sanity/pav/PairAdjacentViolators$interpolator$1::invoke → KILLED |
spline.interpolate(it) |
60 | } | |
61 | } | |
62 | } | |
63 | ||
64 | @JvmOverloads fun inverseInterpolator(strategy: InterpolationStrategy = SPLINE): (Double) -> Double { | |
65 | when (strategy) { | |
66 |
1
1. inverseInterpolator : mutated return of Object value for com/github/sanity/pav/PairAdjacentViolators::inverseInterpolator to ( if (x != null) null else throw new RuntimeException ) → KILLED |
SPLINE -> return { |
67 | val spline = MonotoneSpline(isotonicPoints.map { it.y }.toDoubleArray(), isotonicPoints.map { it.x }.toDoubleArray()) | |
68 |
1
1. invoke : replaced return of double value with -(x + 1) for com/github/sanity/pav/PairAdjacentViolators$inverseInterpolator$1::invoke → KILLED |
spline.interpolate(it) |
69 | } | |
70 | } | |
71 | } | |
72 | ||
73 | enum class InterpolationStrategy { | |
74 | SPLINE | |
75 | } | |
76 | ||
77 | enum class PAVMode { | |
78 | INCREASING, DECREASING | |
79 | } | |
80 | } | |
Mutations | ||
15 |
1.1 2.2 3.3 |
|
17 |
1.1 |
|
18 |
1.1 2.2 3.3 4.4 |
|
19 |
1.1 2.2 3.3 4.4 |
|
20 |
1.1 |
|
23 |
1.1 2.2 |
|
30 |
1.1 |
|
34 |
1.1 |
|
37 |
1.1 |
|
39 |
1.1 2.2 |
|
40 |
1.1 2.2 |
|
42 |
1.1 |
|
49 |
1.1 |
|
57 |
1.1 |
|
59 |
1.1 |
|
66 |
1.1 |
|
68 |
1.1 |
|
83 |
1.1 2.2 |
|
87 |
1.1 2.2 |