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" group = "space.kscience"
version = "0.3.0-dev-12" version = "0.3.0-dev-13"
} }
subprojects { subprojects {

View File

@ -26,4 +26,6 @@ public annotation class UnstableKMathAPI
"Refer to the documentation to use this API in performance-critical code", "Refer to the documentation to use this API in performance-critical code",
RequiresOptIn.Level.WARNING 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 package space.kscience.kmath.functions
import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.operations.Ring 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. * 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. * @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 interface PiecewisePolynomial<T : Comparable<T>> : Piecewise<T, Polynomial<T>> {
public val pieces: List<Pair<ClosedRange<T>, Polynomial<T>>>, public val pieces: Collection<Pair<ClosedRange<T>, Polynomial<T>>>
) : Piecewise<T, Polynomial<T>> {
public override fun findPiece(arg: 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 * 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) pieces.add(0, piece)
} }
public fun build(): PiecewisePolynomial<T> { public fun build(): PiecewisePolynomial<T> = OrderedPiecewisePolynomial(delimiters.zipWithNext { l, r ->
return PiecewisePolynomial(delimiters.zipWithNext { l, r -> l..r }.zip(pieces)) l..r
} }.zip(pieces))
} }
/** /**