Feature: Polynomials and rational functions #469

Merged
lounres merged 132 commits from feature/polynomials into dev 2022-07-28 18:04:06 +03:00
2 changed files with 83 additions and 20 deletions
Showing only changes of commit 7f7b550674 - Show all commits

View File

@ -6,6 +6,7 @@
package space.kscience.kmath.functions package space.kscience.kmath.functions
import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.Ring
@ -103,6 +104,61 @@ public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(
public fun <C> C.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this)) public fun <C> C.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this))
@DslMarker
@UnstableKMathAPI
internal annotation class LabeledPolynomialConstructorDSL
@UnstableKMathAPI
@LabeledPolynomialConstructorDSL
public class LabeledPolynomialTermSignatureBuilder {
private val signature: MutableMap<Symbol, UInt> = LinkedHashMap()
public fun build(): Map<Symbol, UInt> = signature
public infix fun Symbol.inPowerOf(deg: UInt) {
signature[this] = deg
}
@Suppress("NOTHING_TO_INLINE")
public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg
@Suppress("NOTHING_TO_INLINE")
public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg
@Suppress("NOTHING_TO_INLINE")
public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg
}
@UnstableKMathAPI
public class LabeledPolynomialBuilder<C>(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) {
private val coefficients: MutableMap<Map<Symbol, UInt>, C> = LinkedHashMap(capacity)
public fun build(): LabeledPolynomial<C> = LabeledPolynomial<C>(coefficients)
public operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit) {
val signature = LabeledPolynomialTermSignatureBuilder().apply(block).build()
coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke)
}
@Suppress("NOTHING_TO_INLINE")
public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block)
@Suppress("NOTHING_TO_INLINE")
public inline infix fun (LabeledPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this)
@Suppress("NOTHING_TO_INLINE")
public infix fun sig(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): LabeledPolynomialTermSignatureBuilder.() -> Unit = block
}
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
@UnstableKMathAPI
@LabeledPolynomialConstructorDSL
@Suppress("FunctionName")
public inline fun <C, A: Ring<C>> A.LabeledPolynomial(block: LabeledPolynomialBuilder<C>.() -> Unit) : LabeledPolynomial<C> = LabeledPolynomialBuilder(zero, ::add).apply(block).build()
@UnstableKMathAPI
@LabeledPolynomialConstructorDSL
@Suppress("FunctionName")
public inline fun <C, A: Ring<C>> A.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder<C>.() -> Unit) : LabeledPolynomial<C> = LabeledPolynomialBuilder(zero, ::add, capacity).apply(block).build()
@UnstableKMathAPI
@LabeledPolynomialConstructorDSL
@Suppress("FunctionName")
public inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(block: LabeledPolynomialBuilder<C>.() -> Unit) : LabeledPolynomial<C> = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build()
@UnstableKMathAPI
@LabeledPolynomialConstructorDSL
@Suppress("FunctionName")
public inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder<C>.() -> Unit) : LabeledPolynomial<C> = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build()
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
@Suppress("FunctionName") @Suppress("FunctionName")

View File

@ -5,8 +5,8 @@
package space.kscience.kmath.functions package space.kscience.kmath.functions
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.invoke
/** /**
@ -97,8 +97,10 @@ public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomia
public fun <C> C.asNumberedPolynomial() : NumberedPolynomial<C> = NumberedPolynomial<C>(mapOf(emptyList<UInt>() to this)) public fun <C> C.asNumberedPolynomial() : NumberedPolynomial<C> = NumberedPolynomial<C>(mapOf(emptyList<UInt>() to this))
@DslMarker @DslMarker
@UnstableKMathAPI
internal annotation class NumberedPolynomialConstructorDSL internal annotation class NumberedPolynomialConstructorDSL
@UnstableKMathAPI
@NumberedPolynomialConstructorDSL @NumberedPolynomialConstructorDSL
public class NumberedPolynomialTermSignatureBuilder { public class NumberedPolynomialTermSignatureBuilder {
private val signature: MutableList<UInt> = ArrayList() private val signature: MutableList<UInt> = ArrayList()
@ -111,43 +113,48 @@ public class NumberedPolynomialTermSignatureBuilder {
signature[this] = deg signature[this] = deg
} }
} }
public infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg @Suppress("NOTHING_TO_INLINE")
public infix fun Int.of(deg: UInt): Unit = this inPowerOf deg public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg
@Suppress("NOTHING_TO_INLINE")
public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg
@Suppress("NOTHING_TO_INLINE")
public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg
} }
@NumberedPolynomialConstructorDSL @UnstableKMathAPI
public class NumberedPolynomialBuilderOverRing<C> internal constructor(internal val context: Ring<C>, capacity: Int = 0) { public class NumberedPolynomialBuilder<C>(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) {
private val coefficients: MutableMap<List<UInt>, C> = LinkedHashMap(capacity) private val coefficients: MutableMap<List<UInt>, C> = LinkedHashMap(capacity)
public fun build(): NumberedPolynomial<C> = NumberedPolynomial<C>(coefficients) public fun build(): NumberedPolynomial<C> = NumberedPolynomial<C>(coefficients)
public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) {
val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build()
coefficients[signature] = context { coefficients.getOrElse(signature) { zero } + this@invoke } coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke)
} }
public infix fun C.with(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) @Suppress("NOTHING_TO_INLINE")
public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block)
@Suppress("NOTHING_TO_INLINE")
public inline infix fun (NumberedPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this)
@Suppress("NOTHING_TO_INLINE")
public infix fun sig(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): NumberedPolynomialTermSignatureBuilder.() -> Unit = block
} }
@NumberedPolynomialConstructorDSL // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available
public class NumberedPolynomialBuilderOverPolynomialSpace<C> internal constructor(internal val context: NumberedPolynomialSpace<C, *>, capacity: Int = 0) {
private val coefficients: MutableMap<List<UInt>, C> = LinkedHashMap(capacity)
public fun build(): NumberedPolynomial<C> = NumberedPolynomial<C>(coefficients)
public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) {
val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build()
coefficients[signature] = context { coefficients.getOrElse(signature) { constantZero } + this@invoke }
}
}
@UnstableKMathAPI
@NumberedPolynomialConstructorDSL @NumberedPolynomialConstructorDSL
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> A.NumberedPolynomial(block: NumberedPolynomialBuilderOverRing<C>.() -> Unit) : NumberedPolynomial<C> = NumberedPolynomialBuilderOverRing(this).apply(block).build() public inline fun <C, A: Ring<C>> A.NumberedPolynomial(block: NumberedPolynomialBuilder<C>.() -> Unit) : NumberedPolynomial<C> = NumberedPolynomialBuilder(zero, ::add).apply(block).build()
@UnstableKMathAPI
@NumberedPolynomialConstructorDSL @NumberedPolynomialConstructorDSL
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverRing<C>.() -> Unit) : NumberedPolynomial<C> = NumberedPolynomialBuilderOverRing(this, capacity).apply(block).build() public inline fun <C, A: Ring<C>> A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder<C>.() -> Unit) : NumberedPolynomial<C> = NumberedPolynomialBuilder(zero, ::add, capacity).apply(block).build()
@UnstableKMathAPI
@NumberedPolynomialConstructorDSL @NumberedPolynomialConstructorDSL
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(block: NumberedPolynomialBuilderOverPolynomialSpace<C>.() -> Unit) : NumberedPolynomial<C> = NumberedPolynomialBuilderOverPolynomialSpace(this).apply(block).build() public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(block: NumberedPolynomialBuilder<C>.() -> Unit) : NumberedPolynomial<C> = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build()
@UnstableKMathAPI
@NumberedPolynomialConstructorDSL @NumberedPolynomialConstructorDSL
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverPolynomialSpace<C>.() -> Unit) : NumberedPolynomial<C> = NumberedPolynomialBuilderOverPolynomialSpace(this, capacity).apply(block).build() public inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder<C>.() -> Unit) : NumberedPolynomial<C> = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build()
// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available