Piecewise optimization

This commit is contained in:
Alexander Nozik 2021-05-23 20:01:07 +03:00
parent ec7a971df7
commit 380c76fe40
3 changed files with 42 additions and 13 deletions

View File

@ -15,7 +15,7 @@ allprojects {
}
group = "space.kscience"
version = "0.3.0-dev-12"
version = "0.3.0-dev-13"
}
subprojects {

View File

@ -26,4 +26,6 @@ public annotation class UnstableKMathAPI
"Refer to the documentation to use this API in performance-critical code",
RequiresOptIn.Level.WARNING
)
public annotation class PerformancePitfall
public annotation class PerformancePitfall(
val message: String = "Potential performance problem"
)

View File

@ -5,6 +5,7 @@
package space.kscience.kmath.functions
import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.operations.Ring
/**
@ -24,17 +25,43 @@ public fun interface Piecewise<T, R> {
* Represents piecewise-defined function where all the sub-functions are polynomials.
* @param pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no "holes" in it.
*/
public class PiecewisePolynomial<T : Comparable<T>>(
public val pieces: List<Pair<ClosedRange<T>, Polynomial<T>>>,
) : Piecewise<T, Polynomial<T>> {
public interface PiecewisePolynomial<T : Comparable<T>> : Piecewise<T, Polynomial<T>> {
public val pieces: Collection<Pair<ClosedRange<T>, Polynomial<T>>>
public override fun findPiece(arg: T): Polynomial<T>? {
return if (arg < pieces.first().first.start || arg >= pieces.last().first.endInclusive)
null
else {
pieces.firstOrNull { arg in it.first }?.second
public override fun findPiece(arg: T): Polynomial<T>?
}
/**
* A generic piecewise without constraints on how pieces are placed
*/
@PerformancePitfall("findPiece method of resulting piecewise is slow")
public fun <T : Comparable<T>> PiecewisePolynomial(
pieces: Collection<Pair<ClosedRange<T>, Polynomial<T>>>,
): PiecewisePolynomial<T> = object : PiecewisePolynomial<T> {
override val pieces: Collection<Pair<ClosedRange<T>, Polynomial<T>>> = pieces
override fun findPiece(arg: T): Polynomial<T>? = pieces.firstOrNull { arg in it.first }?.second
}
/**
* An optimized piecewise which uses not separate pieces, but a range separated by delimiters.
* The pices search is logarithmic
*/
private class OrderedPiecewisePolynomial<T : Comparable<T>>(
override val pieces: List<Pair<ClosedRange<T>, Polynomial<T>>>,
) : PiecewisePolynomial<T> {
override fun findPiece(arg: T): Polynomial<T>? {
val index = pieces.binarySearch { (range, _) ->
when {
arg >= range.endInclusive -> -1
arg < range.start -> +1
else -> 0
}
}
return if (index < 0) null else pieces[index].second
}
}
/**
@ -71,9 +98,9 @@ public class PiecewiseBuilder<T : Comparable<T>>(delimiter: T) {
pieces.add(0, piece)
}
public fun build(): PiecewisePolynomial<T> {
return PiecewisePolynomial(delimiters.zipWithNext { l, r -> l..r }.zip(pieces))
}
public fun build(): PiecewisePolynomial<T> = OrderedPiecewisePolynomial(delimiters.zipWithNext { l, r ->
l..r
}.zip(pieces))
}
/**