| 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 |