Feature: Polynomials and rational functions #469

Merged
lounres merged 132 commits from feature/polynomials into dev 2022-07-28 18:04:06 +03:00
11 changed files with 0 additions and 792 deletions
Showing only changes of commit a2b02ef09e - Show all commits

View File

@ -1,92 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:OptIn(UnstableKMathAPI::class)
package space.kscience.kmath.interpolation
import space.kscience.kmath.data.XYColumnarData
import space.kscience.kmath.functions.PiecewisePolynomial
import space.kscience.kmath.functions.asFunction
import space.kscience.kmath.functions.substitute
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.asBuffer
/**
* And interpolator for data with x column type [X], y column type [Y].
*/
public fun interface Interpolator<T, in X : T, Y : T> {
public fun interpolate(points: XYColumnarData<T, X, Y>): (X) -> Y
}
/**
* And interpolator returning [PiecewisePolynomial] function
*/
public interface PolynomialInterpolator<T : Comparable<T>> : Interpolator<T, T, T> {
public val algebra: Ring<T>
public fun getDefaultValue(): T = error("Out of bounds")
public fun interpolatePolynomials(points: XYColumnarData<T, T, T>): PiecewisePolynomial<T>
override fun interpolate(points: XYColumnarData<T, T, T>): (T) -> T = { x ->
interpolatePolynomials(points).substitute(algebra, x) ?: getDefaultValue()
}
}
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolatePolynomials(
x: Buffer<T>,
y: Buffer<T>,
): PiecewisePolynomial<T> {
val pointSet = XYColumnarData.of(x, y)
return interpolatePolynomials(pointSet)
}
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolatePolynomials(
data: Map<T, T>,
): PiecewisePolynomial<T> {
val pointSet = XYColumnarData.of(data.keys.toList().asBuffer(), data.values.toList().asBuffer())
return interpolatePolynomials(pointSet)
}
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolatePolynomials(
data: List<Pair<T, T>>,
): PiecewisePolynomial<T> {
val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer())
return interpolatePolynomials(pointSet)
}
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolate(
x: Buffer<T>,
y: Buffer<T>,
): (T) -> T? = interpolatePolynomials(x, y).asFunction(algebra)
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolate(
data: Map<T, T>,
): (T) -> T? = interpolatePolynomials(data).asFunction(algebra)
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolate(
data: List<Pair<T, T>>,
): (T) -> T? = interpolatePolynomials(data).asFunction(algebra)
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolate(
x: Buffer<T>,
y: Buffer<T>,
defaultValue: T,
): (T) -> T = interpolatePolynomials(x, y).asFunction(algebra, defaultValue)
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolate(
data: Map<T, T>,
defaultValue: T,
): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue)
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolate(
data: List<Pair<T, T>>,
defaultValue: T,
): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue)

View File

@ -1,43 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.interpolation
import space.kscience.kmath.data.XYColumnarData
import space.kscience.kmath.functions.PiecewisePolynomial
import space.kscience.kmath.functions.ListPolynomial
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Field
import space.kscience.kmath.operations.invoke
@OptIn(UnstableKMathAPI::class)
internal fun <T : Comparable<T>> insureSorted(points: XYColumnarData<*, T, *>) {
for (i in 0 until points.size - 1)
require(points.x[i + 1] > points.x[i]) { "Input data is not sorted at index $i" }
}
/**
* Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java
*/
public class LinearInterpolator<T : Comparable<T>>(override val algebra: Field<T>) : PolynomialInterpolator<T> {
@OptIn(UnstableKMathAPI::class)
override fun interpolatePolynomials(points: XYColumnarData<T, T, T>): PiecewisePolynomial<T> = algebra {
require(points.size > 0) { "Point array should not be empty" }
insureSorted(points)
PiecewisePolynomial(points.x[0]) {
for (i in 0 until points.size - 1) {
val slope = (points.y[i + 1] - points.y[i]) / (points.x[i + 1] - points.x[i])
val const = points.y[i] - slope * points.x[i]
val polynomial = ListPolynomial(const, slope)
putRight(points.x[i + 1], polynomial)
}
}
}
}
public val <T : Comparable<T>> Field<T>.linearInterpolator: LinearInterpolator<T>
get() = LinearInterpolator(this)

View File

@ -1,83 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.interpolation
import space.kscience.kmath.data.XYColumnarData
import space.kscience.kmath.functions.PiecewisePolynomial
import space.kscience.kmath.functions.ListPolynomial
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.Field
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.DoubleBuffer
import space.kscience.kmath.structures.MutableBufferFactory
/**
* Generic spline interpolator. Not recommended for performance critical places, use platform-specific and type
* specific ones.
*
* Based on
* https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java
*/
public class SplineInterpolator<T : Comparable<T>>(
override val algebra: Field<T>,
public val bufferFactory: MutableBufferFactory<T>,
) : PolynomialInterpolator<T> {
//TODO possibly optimize zeroed buffers
@OptIn(UnstableKMathAPI::class)
override fun interpolatePolynomials(points: XYColumnarData<T, T, T>): PiecewisePolynomial<T> = algebra {
require(points.size >= 3) { "Can't use spline interpolator with less than 3 points" }
insureSorted(points)
// Number of intervals. The number of data points is n + 1.
val n = points.size - 1
// Differences between knot points
val h = bufferFactory(n) { i -> points.x[i + 1] - points.x[i] }
val mu = bufferFactory(n) { zero }
val z = bufferFactory(n + 1) { zero }
for (i in 1 until n) {
val g = 2.0 * (points.x[i + 1] - points.x[i - 1]) - h[i - 1] * mu[i - 1]
mu[i] = h[i] / g
z[i] =
((points.y[i + 1] * h[i - 1] - points.y[i] * (points.x[i + 1] - points.x[i - 1]) + points.y[i - 1] * h[i]) * 3.0 /
(h[i - 1] * h[i]) - h[i - 1] * z[i - 1]) / g
}
// cubic spline coefficients -- b is linear, c quadratic, d is cubic (original y's are constants)
PiecewisePolynomial(points.x[points.size - 1]) {
var cOld = zero
for (j in n - 1 downTo 0) {
val c = z[j] - mu[j] * cOld
val a = points.y[j]
val b = (points.y[j + 1] - points.y[j]) / h[j] - h[j] * (cOld + 2.0 * c) / 3.0
val d = (cOld - c) / (3.0 * h[j])
val x0 = points.x[j]
val x02 = x0 * x0
val x03 = x02 * x0
//Shift coefficients to represent absolute polynomial instead of one with an offset
val polynomial = ListPolynomial(
a - b * x0 + c * x02 - d * x03,
b - 2 * c * x0 + 3 * d * x02,
c - 3 * d * x0,
d
)
cOld = c
putLeft(x0, polynomial)
}
}
}
}
public fun <T : Comparable<T>> Field<T>.splineInterpolator(
bufferFactory: MutableBufferFactory<T>,
): SplineInterpolator<T> = SplineInterpolator(this, bufferFactory)
public val DoubleField.splineInterpolator: SplineInterpolator<Double>
get() = SplineInterpolator(this, ::DoubleBuffer)

View File

@ -1,48 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.integration
import space.kscience.kmath.functions.ListPolynomial
import space.kscience.kmath.functions.integrate
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.DoubleField
import kotlin.math.PI
import kotlin.math.sin
import kotlin.test.Test
import kotlin.test.assertEquals
@OptIn(UnstableKMathAPI::class)
class SplineIntegralTest {
@Test
fun integratePolynomial(){
val polynomial = ListPolynomial(1.0, 2.0, 3.0)
val integral = polynomial.integrate(DoubleField,1.0..2.0)
assertEquals(11.0, integral, 0.001)
}
@Test
fun gaussSin() {
val res = DoubleField.splineIntegrator.integrate(0.0..2 * PI, IntegrandMaxCalls(5)) { x ->
sin(x)
}
assertEquals(0.0, res.value, 1e-2)
}
@Test
fun gaussUniform() {
val res = DoubleField.splineIntegrator.integrate(35.0..100.0, IntegrandMaxCalls(20)) { x ->
if(x in 30.0..50.0){
1.0
} else {
0.0
}
}
assertEquals(15.0, res.value, 0.5)
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.interpolation
import space.kscience.kmath.operations.DoubleField
import kotlin.test.Test
import kotlin.test.assertEquals
internal class LinearInterpolatorTest {
@Test
fun testInterpolation() {
val data = listOf(
0.0 to 0.0,
1.0 to 1.0,
2.0 to 3.0,
3.0 to 4.0
)
//val polynomial: PiecewisePolynomial<Double> = DoubleField.linearInterpolator.interpolatePolynomials(data)
val function = DoubleField.linearInterpolator.interpolate(data)
assertEquals(null, function(-1.0))
assertEquals(0.5, function(0.5))
assertEquals(2.0, function(1.5))
assertEquals(3.0, function(2.0))
}
}

View File

@ -1,31 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.interpolation
import space.kscience.kmath.operations.DoubleField
import kotlin.math.PI
import kotlin.math.sin
import kotlin.test.Test
import kotlin.test.assertEquals
internal class SplineInterpolatorTest {
@Test
fun testInterpolation() {
val data = (0..10).map {
val x = it.toDouble() / 5 * PI
x to sin(x)
}
//val polynomial: PiecewisePolynomial<Double> = DoubleField.splineInterpolator.interpolatePolynomials(data)
val function = DoubleField.splineInterpolator.interpolate(data, Double.NaN)
assertEquals(Double.NaN, function(-1.0))
assertEquals(sin(0.5), function(0.5), 0.1)
assertEquals(sin(1.5), function(1.5), 0.1)
assertEquals(sin(2.0), function(2.0), 0.1)
}
}

View File

@ -1,142 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.test.misc
import space.kscience.kmath.functions.ListPolynomial
import space.kscience.kmath.functions.ListPolynomialSpace
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Ring
class IntModulo {
val residue: Int
val modulus: Int
@PublishedApi
internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) {
if (toCheckInput) {
require(modulus != 0) { "modulus can not be zero" }
this.modulus = if (modulus < 0) -modulus else modulus
this.residue = residue.mod(modulus)
} else {
this.residue = residue
this.modulus = modulus
}
}
constructor(residue: Int, modulus: Int) : this(residue, modulus, true)
operator fun unaryPlus(): IntModulo = this
operator fun unaryMinus(): IntModulo =
IntModulo(
if (residue == 0) 0 else modulus - residue,
modulus,
toCheckInput = false
)
operator fun plus(other: IntModulo): IntModulo {
require(modulus == other.modulus) { "can not add two residue different modulo" }
return IntModulo(
(residue + other.residue) % modulus,
modulus,
toCheckInput = false
)
}
operator fun plus(other: Int): IntModulo =
IntModulo(
(residue + other) % modulus,
modulus,
toCheckInput = false
)
operator fun minus(other: IntModulo): IntModulo {
require(modulus == other.modulus) { "can not subtract two residue different modulo" }
return IntModulo(
(residue - other.residue) % modulus,
modulus,
toCheckInput = false
)
}
operator fun minus(other: Int): IntModulo =
IntModulo(
(residue - other) % modulus,
modulus,
toCheckInput = false
)
operator fun times(other: IntModulo): IntModulo {
require(modulus == other.modulus) { "can not multiply two residue different modulo" }
return IntModulo(
(residue * other.residue) % modulus,
modulus,
toCheckInput = false
)
}
operator fun times(other: Int): IntModulo =
IntModulo(
(residue * other) % modulus,
modulus,
toCheckInput = false
)
operator fun div(other: IntModulo): IntModulo {
require(modulus == other.modulus) { "can not divide two residue different modulo" }
val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus)
require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" }
return IntModulo(
(residue * reciprocalCandidate) % modulus,
modulus,
toCheckInput = false
)
}
operator fun div(other: Int): IntModulo {
val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus)
require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" }
return IntModulo(
(residue * reciprocalCandidate) % modulus,
modulus,
toCheckInput = false
)
}
override fun equals(other: Any?): Boolean =
when (other) {
is IntModulo -> residue == other.residue && modulus == other.modulus
else -> false
}
override fun hashCode(): Int = residue.hashCode()
override fun toString(): String = "$residue mod $modulus"
}
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
@OptIn(UnstableKMathAPI::class)
class IntModuloRing : Ring<IntModulo> {
val modulus: Int
constructor(modulus: Int) {
require(modulus != 0) { "modulus can not be zero" }
this.modulus = if (modulus < 0) -modulus else modulus
}
override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false)
override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false)
fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false)
override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right
override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right
override inline fun IntModulo.unaryMinus(): IntModulo = -this
override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg
override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg
override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg
inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg
}
fun ListPolynomialSpace<IntModulo, IntModuloRing>.number(arg: Int) = IntModulo(arg, ring.modulus, toCheckInput = false)
fun ListPolynomialSpace<IntModulo, IntModuloRing>.ListPolynomial(vararg coefs: Int): ListPolynomial<IntModulo> =
ListPolynomial(coefs.map { IntModulo(it, ring.modulus) })
fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial<IntModulo> =
ListPolynomial(coefs.map { IntModulo(it, modulus) })

View File

@ -1,135 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.test.misc
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Field
import space.kscience.kmath.operations.NumbersAddOps
class Rational {
companion object {
val ZERO: Rational = Rational(0L)
val ONE: Rational = Rational(1L)
}
val numerator: Long
val denominator: Long
internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) {
if (toCheckInput) {
if (denominator == 0L) throw ArithmeticException("/ by zero")
val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < 0L) -it else it }
this.numerator = numerator / greatestCommonDivider
this.denominator = denominator / greatestCommonDivider
} else {
this.numerator = numerator
this.denominator = denominator
}
}
constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true)
constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true)
constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true)
constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true)
constructor(numerator: Int) : this(numerator.toLong(), 1L, false)
constructor(numerator: Long) : this(numerator, 1L, false)
operator fun unaryPlus(): Rational = this
operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator)
operator fun plus(other: Rational): Rational =
Rational(
numerator * other.denominator + denominator * other.numerator,
denominator * other.denominator
)
operator fun plus(other: Int): Rational =
Rational(
numerator + denominator * other.toLong(),
denominator
)
operator fun plus(other: Long): Rational =
Rational(
numerator + denominator * other,
denominator
)
operator fun minus(other: Rational): Rational =
Rational(
numerator * other.denominator - denominator * other.numerator,
denominator * other.denominator
)
operator fun minus(other: Int): Rational =
Rational(
numerator - denominator * other.toLong(),
denominator
)
operator fun minus(other: Long): Rational =
Rational(
numerator - denominator * other,
denominator
)
operator fun times(other: Rational): Rational =
Rational(
numerator * other.numerator,
denominator * other.denominator
)
operator fun times(other: Int): Rational =
Rational(
numerator * other.toLong(),
denominator
)
operator fun times(other: Long): Rational =
Rational(
numerator * other,
denominator
)
operator fun div(other: Rational): Rational =
Rational(
numerator * other.denominator,
denominator * other.numerator
)
operator fun div(other: Int): Rational =
Rational(
numerator,
denominator * other.toLong()
)
operator fun div(other: Long): Rational =
Rational(
numerator,
denominator * other
)
override fun equals(other: Any?): Boolean =
when (other) {
is Rational -> numerator == other.numerator && denominator == other.denominator
is Int -> numerator == other && denominator == 1L
is Long -> numerator == other && denominator == 1L
else -> false
}
override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode()
override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator"
}
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
@OptIn(UnstableKMathAPI::class)
object RationalField : Field<Rational>, NumbersAddOps<Rational> {
override inline val zero: Rational get() = Rational.ZERO
override inline val one: Rational get() = Rational.ONE
override inline fun number(value: Number): Rational = Rational(value.toLong())
override inline fun add(left: Rational, right: Rational): Rational = left + right
override inline fun multiply(left: Rational, right: Rational): Rational = left * right
override inline fun divide(left: Rational, right: Rational): Rational = left / right
override inline fun scale(a: Rational, value: Double): Rational = a * number(value)
override inline fun Rational.unaryMinus(): Rational = -this
override inline fun Rational.plus(arg: Rational): Rational = this + arg
override inline fun Rational.minus(arg: Rational): Rational = this - arg
override inline fun Rational.times(arg: Rational): Rational = this * arg
override inline fun Rational.div(arg: Rational): Rational = this / arg
}

View File

@ -1,107 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.test.misc
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.*
class RationalWithMemorization private constructor(
val value: Rational,
override val memory : OperationsMemory
): WithMemorization {
companion object {
/**
* Constant containing the zero (the additive identity) of the [Rational] field.
*/
public val ZERO: RationalWithMemorization = RationalWithMemorization(Rational.ZERO, object : Endpoint {})
/**
* Constant containing the one (the multiplicative identity) of the [Rational] field.
*/
public val ONE: RationalWithMemorization = RationalWithMemorization(Rational.ONE, object : Endpoint {})
}
constructor(numerator: Int, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {})
constructor(numerator: Int, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {})
constructor(numerator: Long, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {})
constructor(numerator: Long, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {})
constructor(numerator: Int) : this(Rational(numerator), object : Endpoint {})
constructor(numerator: Long) : this(Rational(numerator), object : Endpoint {})
operator fun unaryPlus(): RationalWithMemorization = this
operator fun unaryMinus(): RationalWithMemorization = RationalWithMemorization(
-value,
object : Negation {
override val negated: OperationsMemory = memory
}
)
operator fun plus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization(
value + other.value,
object : Sum {
override val augend: OperationsMemory = memory
override val addend: OperationsMemory = other.memory
}
)
operator fun minus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization(
value - other.value,
object : Difference {
override val minuend: OperationsMemory = memory
override val subtrahend: OperationsMemory = other.memory
}
)
operator fun times(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization(
value * other.value,
object : Product {
override val multiplicand: OperationsMemory = memory
override val multiplier: OperationsMemory = other.memory
}
)
operator fun div(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization(
value / other.value,
object : Quotient {
override val dividend: OperationsMemory = memory
override val divisor: OperationsMemory = other.memory
}
)
override fun equals(other: Any?): Boolean =
other is RationalWithMemorization && value == other.value
override fun hashCode(): Int = value.hashCode()
override fun toString(): String = value.toString()
}
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
object RationalWithMemorizationRing : Ring<RationalWithMemorization> {
override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO
override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE
override inline fun add(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left + right
override inline fun multiply(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left * right
override inline fun RationalWithMemorization.unaryMinus(): RationalWithMemorization = -this
override inline fun RationalWithMemorization.plus(arg: RationalWithMemorization): RationalWithMemorization = this + arg
override inline fun RationalWithMemorization.minus(arg: RationalWithMemorization): RationalWithMemorization = this - arg
override inline fun RationalWithMemorization.times(arg: RationalWithMemorization): RationalWithMemorization = this * arg
}
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
object RationalWithMemorizationField : Field<RationalWithMemorization> {
override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO
override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE
override inline fun number(value: Number): RationalWithMemorization = RationalWithMemorization(value.toLong())
override inline fun add(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left + right
override inline fun multiply(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left * right
override inline fun divide(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left / right
override inline fun scale(a: RationalWithMemorization, value: Double): RationalWithMemorization = a * number(value)
override inline fun RationalWithMemorization.unaryMinus(): RationalWithMemorization = -this
override inline fun RationalWithMemorization.plus(arg: RationalWithMemorization): RationalWithMemorization = this + arg
override inline fun RationalWithMemorization.minus(arg: RationalWithMemorization): RationalWithMemorization = this - arg
override inline fun RationalWithMemorization.times(arg: RationalWithMemorization): RationalWithMemorization = this * arg
override inline fun RationalWithMemorization.div(arg: RationalWithMemorization): RationalWithMemorization = this / arg
}

View File

@ -1,51 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.test.misc
sealed interface OperationsMemory
interface Endpoint: OperationsMemory
interface Negation: OperationsMemory {
val negated: OperationsMemory
}
interface Sum: OperationsMemory {
val augend: OperationsMemory
val addend: OperationsMemory
}
interface Difference: OperationsMemory {
val minuend: OperationsMemory
val subtrahend: OperationsMemory
}
interface Product: OperationsMemory {
val multiplicand: OperationsMemory
val multiplier: OperationsMemory
}
interface Quotient: OperationsMemory {
val dividend: OperationsMemory
val divisor: OperationsMemory
}
fun equalMemories(one: OperationsMemory, other: OperationsMemory) : Boolean =
when(one) {
is Negation -> other is Negation && equalMemories(one.negated, other.negated)
is Sum -> other is Sum && equalMemories(one.augend, other.augend) && equalMemories(one.addend, other.addend)
is Difference -> other is Difference && equalMemories(one.minuend, other.minuend) && equalMemories(one.subtrahend, other.subtrahend)
is Product -> other is Product && equalMemories(one.multiplicand, other.multiplicand) && equalMemories(one.multiplier, other.multiplier)
is Quotient -> other is Quotient && equalMemories(one.dividend, other.dividend) && equalMemories(one.divisor, other.divisor)
is Endpoint -> one === other
}
interface WithMemorization {
val memory: OperationsMemory
}
fun equalMemories(one: WithMemorization, other: WithMemorization) : Boolean = equalMemories(one.memory, other.memory)

View File

@ -1,31 +0,0 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.test.misc
// TODO: Move to corresponding module "kmath-number-theory"
import kotlin.math.abs
data class BezoutIdentityWithGCD<T>(val first: T, val second: T, val gcd: T)
tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a)
fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD<Int> =
when {
a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) }
a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) }
b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) }
else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1)
}
internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD<Int> =
if (b == 0) BezoutIdentityWithGCD(m1, m3, a)
else {
val quotient = a / b
val reminder = a % b
bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4)
}