Feature: Polynomials and rational functions #469

Merged
lounres merged 132 commits from feature/polynomials into dev 2022-07-28 18:04:06 +03:00
17 changed files with 825 additions and 466 deletions
Showing only changes of commit 6ff79e28ac - Show all commits

View File

@ -59,7 +59,7 @@ public value class Polynomial<C>(
* @param A type of provided underlying ring of constants. It's [Ring] of [C].
* @param ring underlying ring of constants of type [A].
*/
public open class ListPolynomialSpace<C, A : Ring<C>>(
public open class PolynomialSpace<C, A : Ring<C>>(
/**
* Underlying ring of constants. Its operations on constants are inherited by local operations on constants.
*/
@ -293,9 +293,9 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
* @param A type of underlying ring of constants. It's [Ring] of [C].
* @param ring underlying ring of constants of type [A].
*/
public class ScalableListPolynomialSpace<C, A>(
public class ScalablePolynomialSpace<C, A>(
ring: A,
) : ListPolynomialSpace<C, A>(ring), ScaleOperations<Polynomial<C>> where A : Ring<C>, A : ScaleOperations<C> {
) : PolynomialSpace<C, A>(ring), ScaleOperations<Polynomial<C>> where A : Ring<C>, A : ScaleOperations<C> {
override fun scale(a: Polynomial<C>, value: Double): Polynomial<C> =
ring { Polynomial(a.coefficients.map { scale(it, value) }) }
}

View File

@ -11,7 +11,7 @@ package space.kscience.kmath.functions
* if [reverse] parameter is true.
*/
@Suppress("FunctionName")
public fun <C> ListPolynomial(coefficients: List<C>, reverse: Boolean = false): Polynomial<C> =
public fun <C> Polynomial(coefficients: List<C>, reverse: Boolean = false): Polynomial<C> =
Polynomial(with(coefficients) { if (reverse) reversed() else this })
/**
@ -19,10 +19,10 @@ public fun <C> ListPolynomial(coefficients: List<C>, reverse: Boolean = false):
* if [reverse] parameter is true.
*/
@Suppress("FunctionName")
public fun <C> ListPolynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial<C> =
public fun <C> Polynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial<C> =
Polynomial(with(coefficients) { if (reverse) reversed() else toList() })
/**
* Represents [this] constant as a [Polynomial].
*/
public fun <C> C.asListPolynomial() : Polynomial<C> = Polynomial(listOf(this))
public fun <C> C.asPolynomial() : Polynomial<C> = Polynomial(listOf(this))

View File

@ -14,31 +14,31 @@ import kotlin.math.pow
/**
* Creates a [ListPolynomialSpace] over a received ring.
* Creates a [PolynomialSpace] over a received ring.
*/
public inline val <C, A : Ring<C>> A.listPolynomialSpace: ListPolynomialSpace<C, A>
get() = ListPolynomialSpace(this)
public inline val <C, A : Ring<C>> A.polynomialSpace: PolynomialSpace<C, A>
get() = PolynomialSpace(this)
/**
* Creates a [ListPolynomialSpace]'s scope over a received ring.
* Creates a [PolynomialSpace]'s scope over a received ring.
*/ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block]
public inline fun <C, A : Ring<C>, R> A.listPolynomialSpace(block: ListPolynomialSpace<C, A>.() -> R): R {
public inline fun <C, A : Ring<C>, R> A.polynomialSpace(block: PolynomialSpace<C, A>.() -> R): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return ListPolynomialSpace(this).block()
return PolynomialSpace(this).block()
}
/**
* Creates a [ScalableListPolynomialSpace] over a received scalable ring.
* Creates a [ScalablePolynomialSpace] over a received scalable ring.
*/
public inline val <C, A> A.scalableListPolynomialSpace: ScalableListPolynomialSpace<C, A> where A : Ring<C>, A : ScaleOperations<C>
get() = ScalableListPolynomialSpace(this)
public inline val <C, A> A.scalablePolynomialSpace: ScalablePolynomialSpace<C, A> where A : Ring<C>, A : ScaleOperations<C>
get() = ScalablePolynomialSpace(this)
/**
* Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring.
* Creates a [ScalablePolynomialSpace]'s scope over a received scalable ring.
*/ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block]
public inline fun <C, A, R> A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace<C, A>.() -> R): R where A : Ring<C>, A : ScaleOperations<C> {
public inline fun <C, A, R> A.scalablePolynomialSpace(block: ScalablePolynomialSpace<C, A>.() -> R): R where A : Ring<C>, A : ScaleOperations<C> {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return ScalableListPolynomialSpace(this).block()
return ScalablePolynomialSpace(this).block()
}

View File

@ -7,7 +7,7 @@ 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.functions.Polynomial
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Field
import space.kscience.kmath.operations.invoke
@ -32,7 +32,7 @@ public class LinearInterpolator<T : Comparable<T>>(override val algebra: Field<T
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)
val polynomial = Polynomial(const, slope)
putRight(points.x[i + 1], polynomial)
}
}

View File

@ -7,7 +7,7 @@ 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.functions.Polynomial
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.Field
@ -61,7 +61,7 @@ public class SplineInterpolator<T : Comparable<T>>(
val x02 = x0 * x0
val x03 = x02 * x0
//Shift coefficients to represent absolute polynomial instead of one with an offset
val polynomial = ListPolynomial(
val polynomial = Polynomial(
a - b * x0 + c * x02 - d * x03,
b - 2 * c * x0 + 3 * d * x02,
c - 3 * d * x0,

View File

@ -1,303 +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:Suppress("LocalVariableName")
package space.kscience.kmath.functions
import space.kscience.kmath.functions.testUtils.*
import kotlin.test.*
class ListPolynomialTest {
@Test
fun test_Polynomial_Constant_plus() {
RationalField.listPolynomialSpace {
assertEquals(
ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3),
"test 1"
)
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2),
"test 2"
)
assertEquals(
ListPolynomial(Rational(0)),
ListPolynomial(Rational(-2)) + Rational(2),
"test 3"
)
assertEquals(
ListPolynomial(Rational(0)),
ListPolynomial<Rational>() + Rational(0),
"test 4"
)
assertEquals(
ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1),
"test 5"
)
assertEquals(
ListPolynomial(Rational(-1)),
ListPolynomial(Rational(-2)) + Rational(1),
"test 6"
)
assertEquals(
ListPolynomial(Rational(2)),
ListPolynomial<Rational>() + Rational(2),
"test 7"
)
}
}
@Test
fun test_Polynomial_Constant_minus() {
RationalField.listPolynomialSpace {
assertEquals(
ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3),
"test 1"
)
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2),
"test 2"
)
assertEquals(
ListPolynomial(Rational(0)),
ListPolynomial(Rational(2)) - Rational(2),
"test 3"
)
assertEquals(
ListPolynomial(Rational(0)),
ListPolynomial<Rational>() - Rational(0),
"test 4"
)
assertEquals(
ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1),
"test 5"
)
assertEquals(
ListPolynomial(Rational(1)),
ListPolynomial(Rational(2)) - Rational(1),
"test 6"
)
assertEquals(
ListPolynomial(Rational(-2)),
ListPolynomial<Rational>() - Rational(2),
"test 7"
)
}
}
@Test
fun test_Polynomial_Constant_times() {
IntModuloRing(35).listPolynomialSpace {
assertEquals(
ListPolynomial(34, 2, 1, 20, 2),
ListPolynomial(22, 26, 13, 15, 26) * m(27),
"test 1"
)
assertEquals(
ListPolynomial(0, 0, 0, 0, 0),
ListPolynomial(7, 0, 49, 21, 14) * m(15),
"test 2"
)
}
}
@Test
fun test_Constant_Polynomial_plus() {
RationalField.listPolynomialSpace {
assertEquals(
ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)),
"test 1"
)
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
Rational(2) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 2"
)
assertEquals(
ListPolynomial(Rational(0)),
Rational(2) + ListPolynomial(Rational(-2)),
"test 3"
)
assertEquals(
ListPolynomial(Rational(0)),
Rational(0) + ListPolynomial(),
"test 4"
)
assertEquals(
ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
Rational(1) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 5"
)
assertEquals(
ListPolynomial(Rational(-1)),
Rational(1) + ListPolynomial(Rational(-2)),
"test 6"
)
assertEquals(
ListPolynomial(Rational(2)),
Rational(2) + ListPolynomial(),
"test 7"
)
}
}
@Test
fun test_Constant_Polynomial_minus() {
RationalField.listPolynomialSpace {
assertEquals(
ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)),
"test 1"
)
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
Rational(-2) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 2"
)
assertEquals(
ListPolynomial(Rational(0)),
Rational(-2) - ListPolynomial(Rational(-2)),
"test 3"
)
assertEquals(
ListPolynomial(Rational(0)),
Rational(0) - ListPolynomial(),
"test 4"
)
assertEquals(
ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
Rational(-1) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 5"
)
assertEquals(
ListPolynomial(Rational(1)),
Rational(-1) - ListPolynomial(Rational(-2)),
"test 6"
)
assertEquals(
ListPolynomial(Rational(-2)),
Rational(-2) - ListPolynomial(),
"test 7"
)
}
}
@Test
fun test_Constant_Polynomial_times() {
IntModuloRing(35).listPolynomialSpace {
assertEquals(
ListPolynomial(34, 2, 1, 20, 2),
m(27) * ListPolynomial(22, 26, 13, 15, 26),
"test 1"
)
assertEquals(
ListPolynomial(0, 0, 0, 0, 0),
m(15) * ListPolynomial(7, 0, 49, 21, 14),
"test 2"
)
}
}
@Test
fun test_Polynomial_unaryMinus() {
RationalField.listPolynomialSpace {
assertEquals(
ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)),
-ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)),
"test 1"
)
assertEquals(
ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)),
-ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)),
"test 2"
)
}
}
@Test
fun test_Polynomial_Polynomial_plus() {
RationalField.listPolynomialSpace {
// (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2
assertEquals(
ListPolynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)),
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) +
ListPolynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)),
"test 1"
)
// (-2/9 - 8/3 x) + (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 5/12 x + 2/4 x^2
assertEquals(
ListPolynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)),
ListPolynomial(Rational(-2, 9), Rational(-8, 3)) +
ListPolynomial(Rational(0), Rational(9, 4), Rational(2, 4)),
"test 2"
)
// (-4/7 - 2/6 x + 0 x^2 + 0 x^3) + (-6/3 - 7/2 x + 2/3 x^2) ?= -18/7 - 23/6 x + 2/3 x^2
assertEquals(
ListPolynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3), Rational(0)),
ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) +
ListPolynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)),
"test 3"
)
// (-2/4 - 6/9 x - 4/9 x^2) + (2/4 + 6/9 x + 4/9 x^2) ?= 0
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(0)),
ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) +
ListPolynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)),
"test 4"
)
}
}
@Test
fun test_Polynomial_Polynomial_minus() {
RationalField.listPolynomialSpace {
// (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2
assertEquals(
ListPolynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)),
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) -
ListPolynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)),
"test 1"
)
// (-2/9 - 8/3 x) - (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 59/12 x - 2/4 x^2
assertEquals(
ListPolynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)),
ListPolynomial(Rational(-2, 9), Rational(-8, 3)) -
ListPolynomial(Rational(0), Rational(9, 4), Rational(2, 4)),
"test 2"
)
// (-4/7 - 2/6 x + 0 x^2 + 0 x^3) - (-6/3 - 7/2 x + 2/3 x^2) ?= 10/7 + 19/6 x - 2/3 x^2
assertEquals(
ListPolynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3), Rational(0)),
ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) -
ListPolynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)),
"test 3"
)
// (-2/4 - 6/9 x - 4/9 x^2) - (-2/4 - 6/9 x - 4/9 x^2) ?= 0
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(0)),
ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) -
ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)),
"test 4"
)
}
}
@Test
fun test_Polynomial_Polynomial_times() {
IntModuloRing(35).listPolynomialSpace {
// (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4
assertEquals(
ListPolynomial(1, 0, 1, 0, 1),
ListPolynomial(1, -1, 1) * ListPolynomial(1, 1, 1),
"test 1"
)
// Spoiler: 5 * 7 = 0
assertEquals(
ListPolynomial(0, 0, 0, 0, 0),
ListPolynomial(5, -25, 10) * ListPolynomial(21, 14, -7),
"test 2"
)
}
}
}

View File

@ -1,134 +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.functions
import space.kscience.kmath.functions.testUtils.Rational
import space.kscience.kmath.functions.testUtils.RationalField
import space.kscience.kmath.misc.UnstableKMathAPI
import kotlin.test.Test
import kotlin.test.assertEquals
@OptIn(UnstableKMathAPI::class)
class ListPolynomialUtilTest {
@Test
fun test_Polynomial_substitute_Double() {
assertEquals(
0.0,
ListPolynomial(1.0, -2.0, 1.0).substitute(1.0),
0.001,
"test 1"
)
assertEquals(
0.0,
ListPolynomial(1.0, -2.0, 1.0).substitute(1.0),
0.001,
"test 1"
)
assertEquals(
1.1931904761904761,
ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2),
0.001,
"test 2"
)
assertEquals(
0.5681904761904762,
ListPolynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2),
0.001,
"test 3"
)
assertEquals(
1.1811904761904761,
ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).substitute(0.2),
0.001,
"test 4"
)
assertEquals(
1.1703333333333332,
ListPolynomial(0.625, 2.6666666666666665, 0.0, 1.5).substitute(0.2),
0.001,
"test 5"
)
}
@Test
fun test_Polynomial_substitute_Constant() {
assertEquals(
Rational(0),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)),
"test 1"
)
assertEquals(
Rational(25057, 21000),
ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(3, 2))
.substitute(RationalField, Rational(1, 5)),
"test 2"
)
assertEquals(
Rational(2983, 5250),
ListPolynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2))
.substitute(RationalField, Rational(1, 5)),
"test 3"
)
assertEquals(
Rational(4961, 4200),
ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(0))
.substitute(RationalField, Rational(1, 5)),
"test 4"
)
assertEquals(
Rational(3511, 3000),
ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(0), Rational(3, 2))
.substitute(RationalField, Rational(1, 5)),
"test 5"
)
}
@Test
fun test_Polynomial_derivative() {
assertEquals(
ListPolynomial(Rational(-2), Rational(2)),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField),
"test 1"
)
assertEquals(
ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)),
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField),
"test 2"
)
assertEquals(
ListPolynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)),
ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField),
"test 3"
)
assertEquals(
ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)),
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField),
"test 4"
)
}
@Test
fun test_Polynomial_antiderivative() {
assertEquals(
ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)),
ListPolynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField),
"test 1"
)
assertEquals(
ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)),
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField),
"test 2"
)
assertEquals(
ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)),
ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField),
"test 3"
)
assertEquals(
ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)),
ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField),
"test 4"
)
}
}

View File

@ -0,0 +1,303 @@
/*
* 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:Suppress("LocalVariableName")
package space.kscience.kmath.functions
import space.kscience.kmath.functions.testUtils.*
import kotlin.test.*
class PolynomialTest {
@Test
fun test_Polynomial_Constant_plus() {
RationalField.polynomialSpace {
assertEquals(
Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3),
"test 1"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2),
"test 2"
)
assertEquals(
Polynomial(Rational(0)),
Polynomial(Rational(-2)) + Rational(2),
"test 3"
)
assertEquals(
Polynomial(Rational(0)),
Polynomial<Rational>() + Rational(0),
"test 4"
)
assertEquals(
Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1),
"test 5"
)
assertEquals(
Polynomial(Rational(-1)),
Polynomial(Rational(-2)) + Rational(1),
"test 6"
)
assertEquals(
Polynomial(Rational(2)),
Polynomial<Rational>() + Rational(2),
"test 7"
)
}
}
@Test
fun test_Polynomial_Constant_minus() {
RationalField.polynomialSpace {
assertEquals(
Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3),
"test 1"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2),
"test 2"
)
assertEquals(
Polynomial(Rational(0)),
Polynomial(Rational(2)) - Rational(2),
"test 3"
)
assertEquals(
Polynomial(Rational(0)),
Polynomial<Rational>() - Rational(0),
"test 4"
)
assertEquals(
Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1),
"test 5"
)
assertEquals(
Polynomial(Rational(1)),
Polynomial(Rational(2)) - Rational(1),
"test 6"
)
assertEquals(
Polynomial(Rational(-2)),
Polynomial<Rational>() - Rational(2),
"test 7"
)
}
}
@Test
fun test_Polynomial_Constant_times() {
IntModuloRing(35).polynomialSpace {
assertEquals(
Polynomial(34, 2, 1, 20, 2),
Polynomial(22, 26, 13, 15, 26) * m(27),
"test 1"
)
assertEquals(
Polynomial(0, 0, 0, 0, 0),
Polynomial(7, 0, 49, 21, 14) * m(15),
"test 2"
)
}
}
@Test
fun test_Constant_Polynomial_plus() {
RationalField.polynomialSpace {
assertEquals(
Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)),
Rational(-3) + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)),
"test 1"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
Rational(2) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 2"
)
assertEquals(
Polynomial(Rational(0)),
Rational(2) + Polynomial(Rational(-2)),
"test 3"
)
assertEquals(
Polynomial(Rational(0)),
Rational(0) + Polynomial(),
"test 4"
)
assertEquals(
Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)),
Rational(1) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 5"
)
assertEquals(
Polynomial(Rational(-1)),
Rational(1) + Polynomial(Rational(-2)),
"test 6"
)
assertEquals(
Polynomial(Rational(2)),
Rational(2) + Polynomial(),
"test 7"
)
}
}
@Test
fun test_Constant_Polynomial_minus() {
RationalField.polynomialSpace {
assertEquals(
Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)),
Rational(3) - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)),
"test 1"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)),
Rational(-2) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 2"
)
assertEquals(
Polynomial(Rational(0)),
Rational(-2) - Polynomial(Rational(-2)),
"test 3"
)
assertEquals(
Polynomial(Rational(0)),
Rational(0) - Polynomial(),
"test 4"
)
assertEquals(
Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)),
Rational(-1) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)),
"test 5"
)
assertEquals(
Polynomial(Rational(1)),
Rational(-1) - Polynomial(Rational(-2)),
"test 6"
)
assertEquals(
Polynomial(Rational(-2)),
Rational(-2) - Polynomial(),
"test 7"
)
}
}
@Test
fun test_Constant_Polynomial_times() {
IntModuloRing(35).polynomialSpace {
assertEquals(
Polynomial(34, 2, 1, 20, 2),
m(27) * Polynomial(22, 26, 13, 15, 26),
"test 1"
)
assertEquals(
Polynomial(0, 0, 0, 0, 0),
m(15) * Polynomial(7, 0, 49, 21, 14),
"test 2"
)
}
}
@Test
fun test_Polynomial_unaryMinus() {
RationalField.polynomialSpace {
assertEquals(
Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)),
-Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)),
"test 1"
)
assertEquals(
Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)),
-Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)),
"test 2"
)
}
}
@Test
fun test_Polynomial_Polynomial_plus() {
RationalField.polynomialSpace {
// (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2
assertEquals(
Polynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)),
Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) +
Polynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)),
"test 1"
)
// (-2/9 - 8/3 x) + (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 5/12 x + 2/4 x^2
assertEquals(
Polynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)),
Polynomial(Rational(-2, 9), Rational(-8, 3)) +
Polynomial(Rational(0), Rational(9, 4), Rational(2, 4)),
"test 2"
)
// (-4/7 - 2/6 x + 0 x^2 + 0 x^3) + (-6/3 - 7/2 x + 2/3 x^2) ?= -18/7 - 23/6 x + 2/3 x^2
assertEquals(
Polynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3), Rational(0)),
Polynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) +
Polynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)),
"test 3"
)
// (-2/4 - 6/9 x - 4/9 x^2) + (2/4 + 6/9 x + 4/9 x^2) ?= 0
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0)),
Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) +
Polynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)),
"test 4"
)
}
}
@Test
fun test_Polynomial_Polynomial_minus() {
RationalField.polynomialSpace {
// (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2
assertEquals(
Polynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)),
Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) -
Polynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)),
"test 1"
)
// (-2/9 - 8/3 x) - (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 59/12 x - 2/4 x^2
assertEquals(
Polynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)),
Polynomial(Rational(-2, 9), Rational(-8, 3)) -
Polynomial(Rational(0), Rational(9, 4), Rational(2, 4)),
"test 2"
)
// (-4/7 - 2/6 x + 0 x^2 + 0 x^3) - (-6/3 - 7/2 x + 2/3 x^2) ?= 10/7 + 19/6 x - 2/3 x^2
assertEquals(
Polynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3), Rational(0)),
Polynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) -
Polynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)),
"test 3"
)
// (-2/4 - 6/9 x - 4/9 x^2) - (-2/4 - 6/9 x - 4/9 x^2) ?= 0
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0)),
Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) -
Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)),
"test 4"
)
}
}
@Test
fun test_Polynomial_Polynomial_times() {
IntModuloRing(35).polynomialSpace {
// (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4
assertEquals(
Polynomial(1, 0, 1, 0, 1),
Polynomial(1, -1, 1) * Polynomial(1, 1, 1),
"test 1"
)
// Spoiler: 5 * 7 = 0
assertEquals(
Polynomial(0, 0, 0, 0, 0),
Polynomial(5, -25, 10) * Polynomial(21, 14, -7),
"test 2"
)
}
}
}

View File

@ -0,0 +1,134 @@
/*
* 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.functions
import space.kscience.kmath.functions.testUtils.Rational
import space.kscience.kmath.functions.testUtils.RationalField
import space.kscience.kmath.misc.UnstableKMathAPI
import kotlin.test.Test
import kotlin.test.assertEquals
@OptIn(UnstableKMathAPI::class)
class PolynomialUtilTest {
@Test
fun test_Polynomial_substitute_Double() {
assertEquals(
0.0,
Polynomial(1.0, -2.0, 1.0).substitute(1.0),
0.001,
"test 1"
)
assertEquals(
0.0,
Polynomial(1.0, -2.0, 1.0).substitute(1.0),
0.001,
"test 1"
)
assertEquals(
1.1931904761904761,
Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2),
0.001,
"test 2"
)
assertEquals(
0.5681904761904762,
Polynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2),
0.001,
"test 3"
)
assertEquals(
1.1811904761904761,
Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).substitute(0.2),
0.001,
"test 4"
)
assertEquals(
1.1703333333333332,
Polynomial(0.625, 2.6666666666666665, 0.0, 1.5).substitute(0.2),
0.001,
"test 5"
)
}
@Test
fun test_Polynomial_substitute_Constant() {
assertEquals(
Rational(0),
Polynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)),
"test 1"
)
assertEquals(
Rational(25057, 21000),
Polynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(3, 2))
.substitute(RationalField, Rational(1, 5)),
"test 2"
)
assertEquals(
Rational(2983, 5250),
Polynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2))
.substitute(RationalField, Rational(1, 5)),
"test 3"
)
assertEquals(
Rational(4961, 4200),
Polynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(0))
.substitute(RationalField, Rational(1, 5)),
"test 4"
)
assertEquals(
Rational(3511, 3000),
Polynomial(Rational(5, 8), Rational(8, 3), Rational(0), Rational(3, 2))
.substitute(RationalField, Rational(1, 5)),
"test 5"
)
}
@Test
fun test_Polynomial_derivative() {
assertEquals(
Polynomial(Rational(-2), Rational(2)),
Polynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField),
"test 1"
)
assertEquals(
Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)),
Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField),
"test 2"
)
assertEquals(
Polynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)),
Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField),
"test 3"
)
assertEquals(
Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)),
Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField),
"test 4"
)
}
@Test
fun test_Polynomial_antiderivative() {
assertEquals(
Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)),
Polynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField),
"test 1"
)
assertEquals(
Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)),
Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField),
"test 2"
)
assertEquals(
Polynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)),
Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField),
"test 3"
)
assertEquals(
Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)),
Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField),
"test 4"
)
}
}

View File

@ -5,7 +5,7 @@
package space.kscience.kmath.integration
import space.kscience.kmath.functions.ListPolynomial
import space.kscience.kmath.functions.Polynomial
import space.kscience.kmath.functions.integrate
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.DoubleField
@ -19,7 +19,7 @@ class SplineIntegralTest {
@Test
fun integratePolynomial(){
val polynomial = ListPolynomial(1.0, 2.0, 3.0)
val polynomial = Polynomial(1.0, 2.0, 3.0)
val integral = polynomial.integrate(DoubleField,1.0..2.0)
assertEquals(11.0, integral, 0.001)
}

View File

@ -6,6 +6,7 @@
package space.kscience.kmath.functions
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.functions.testUtils.assertEquals
import space.kscience.kmath.functions.testUtils.Rational
import space.kscience.kmath.functions.testUtils.RationalField
import space.kscience.kmath.functions.testUtils.iota

View File

@ -6,13 +6,13 @@
package space.kscience.kmath.functions.testUtils
import space.kscience.kmath.functions.Polynomial
import space.kscience.kmath.functions.ListPolynomialSpace
import space.kscience.kmath.functions.PolynomialSpace
public fun ListPolynomialSpace<IntModulo, IntModuloRing>.ListPolynomial(vararg coefs: Int): Polynomial<IntModulo> =
public fun PolynomialSpace<IntModulo, IntModuloRing>.Polynomial(vararg coefs: Int): Polynomial<IntModulo> =
Polynomial(coefs.map { IntModulo(it, ring.modulus) })
public fun IntModuloRing.ListPolynomial(vararg coefs: Int): Polynomial<IntModulo> =
public fun IntModuloRing.Polynomial(vararg coefs: Int): Polynomial<IntModulo> =
Polynomial(coefs.map { IntModulo(it, modulus) })
public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus)
public fun ListPolynomialSpace<IntModulo, IntModuloRing>.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus)
public fun PolynomialSpace<IntModulo, IntModuloRing>.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus)

View File

@ -0,0 +1,133 @@
/*
* 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:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
package space.kscience.kmath.functions.testUtils
import space.kscience.kmath.operations.Ring
public class IntModulo {
public val residue: Int
public 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(this.modulus)
} else {
this.residue = residue
this.modulus = modulus
}
}
public constructor(residue: Int, modulus: Int) : this(residue, modulus, true)
public operator fun unaryPlus(): IntModulo = this
public operator fun unaryMinus(): IntModulo =
IntModulo(
if (residue == 0) 0 else modulus - residue,
modulus,
toCheckInput = false
)
public 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
)
}
public operator fun plus(other: Int): IntModulo =
IntModulo(
(residue + other) % modulus,
modulus,
toCheckInput = false
)
public 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
)
}
public operator fun minus(other: Int): IntModulo =
IntModulo(
(residue - other) % modulus,
modulus,
toCheckInput = false
)
public 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
)
}
public operator fun times(other: Int): IntModulo =
IntModulo(
(residue * other) % modulus,
modulus,
toCheckInput = false
)
public 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
)
}
public 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")
public class IntModuloRing : Ring<IntModulo> {
public val modulus: Int
public 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)
public fun number(arg: Int): IntModulo = 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
public inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg
}

View File

@ -0,0 +1,20 @@
/*
* 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.functions.testUtils
import space.kscience.kmath.functions.ListPolynomial
import space.kscience.kmath.functions.Polynomial
import space.kscience.kmath.functions.ListPolynomialSpace
import space.kscience.kmath.functions.PolynomialSpaceOverRing
public fun ListPolynomialSpace<IntModulo, IntModuloRing>.ListPolynomial(vararg coefs: Int): ListPolynomial<IntModulo> =
ListPolynomial(coefs.map { IntModulo(it, ring.modulus) })
public fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial<IntModulo> =
ListPolynomial(coefs.map { IntModulo(it, modulus) })
public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus)
public fun PolynomialSpaceOverRing<IntModulo, *, IntModuloRing>.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus)

View File

@ -0,0 +1,29 @@
/*
* 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.functions.testUtils
import kotlin.math.abs
internal data class BezoutIdentityWithGCD<T>(val first: T, val second: T, val gcd: T)
internal tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a)
internal 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)
}

View File

@ -0,0 +1,177 @@
/*
* 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:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
package space.kscience.kmath.functions.testUtils
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Field
import space.kscience.kmath.operations.NumbersAddOps
@Suppress("NAME_SHADOWING")
public class Rational {
public companion object {
public val ZERO: Rational = Rational(0L)
public val ONE: Rational = Rational(1L)
}
public val numerator: Long
public 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
}
}
public constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true)
public constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true)
public constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true)
public constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true)
public constructor(numerator: Int) : this(numerator.toLong(), 1L, false)
public constructor(numerator: Long) : this(numerator, 1L, false)
public operator fun unaryPlus(): Rational = this
public operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator)
public operator fun plus(other: Rational): Rational {
val denominatorsGcd = gcd(denominator, other.denominator)
val dividedThisDenominator = denominator / denominatorsGcd
val dividedOtherDenominator = other.denominator / denominatorsGcd
val numeratorCandidate = numerator * dividedOtherDenominator + dividedThisDenominator * other.numerator
val secondGcd = gcd(numeratorCandidate, denominatorsGcd)
return Rational(
numeratorCandidate / secondGcd,
dividedThisDenominator * (other.denominator / secondGcd),
toCheckInput = false
)
}
public operator fun plus(other: Int): Rational =
Rational(
numerator + denominator * other.toLong(),
denominator,
toCheckInput = false
)
public operator fun plus(other: Long): Rational =
Rational(
numerator + denominator * other,
denominator,
toCheckInput = false
)
public operator fun minus(other: Rational): Rational {
val denominatorsGcd = gcd(denominator, other.denominator)
val dividedThisDenominator = denominator / denominatorsGcd
val dividedOtherDenominator = other.denominator / denominatorsGcd
val numeratorCandidate = numerator * dividedOtherDenominator - dividedThisDenominator * other.numerator
val secondGcd = gcd(numeratorCandidate, denominatorsGcd)
return Rational(
numeratorCandidate / secondGcd,
dividedThisDenominator * (other.denominator / secondGcd),
toCheckInput = false
)
}
public operator fun minus(other: Int): Rational =
Rational(
numerator - denominator * other.toLong(),
denominator,
toCheckInput = false
)
public operator fun minus(other: Long): Rational =
Rational(
numerator - denominator * other,
denominator,
toCheckInput = false
)
public operator fun times(other: Rational): Rational {
val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator)
val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator)
return Rational(
(numerator / otherDenominatorAndThisNumeratorGcd) * (other.numerator / thisDenominatorAndOtherNumeratorGcd),
(denominator / thisDenominatorAndOtherNumeratorGcd) * (other.denominator / otherDenominatorAndThisNumeratorGcd),
toCheckInput = false
)
}
public operator fun times(other: Int): Rational {
val other = other.toLong()
val denominatorAndOtherGcd = gcd(denominator, other)
return Rational(
numerator * (other / denominatorAndOtherGcd),
denominator / denominatorAndOtherGcd,
toCheckInput = false
)
}
public operator fun times(other: Long): Rational {
val denominatorAndOtherGcd = gcd(denominator, other)
return Rational(
numerator * (other / denominatorAndOtherGcd),
denominator / denominatorAndOtherGcd,
toCheckInput = false
)
}
public operator fun div(other: Rational): Rational {
val denominatorsGcd = gcd(denominator, other.denominator)
val numeratorsGcd = gcd(numerator, other.numerator)
return Rational(
(numerator / numeratorsGcd) * (other.denominator / denominatorsGcd),
(denominator / denominatorsGcd) * (other.numerator / numeratorsGcd)
)
}
public operator fun div(other: Int): Rational {
val other = other.toLong()
val numeratorAndOtherGcd = gcd(numerator, other)
return Rational(
numerator / numeratorAndOtherGcd,
denominator * (other / numeratorAndOtherGcd),
toCheckInput = false
)
}
public operator fun div(other: Long): Rational {
val numeratorAndOtherGcd = gcd(numerator, other)
return Rational(
numerator / numeratorAndOtherGcd,
denominator * (other / numeratorAndOtherGcd),
toCheckInput = false
)
}
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")
@OptIn(UnstableKMathAPI::class)
public 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

@ -91,7 +91,6 @@ public fun assertEquals(
)
}
// FIXME: Don't understand why but the same function from test-utils-functions module can not be used
public inline fun <reified T : Throwable> assertFailsWithTypeAndMessage(
expectedMessage: String? = null,
assertionMessage: String? = null,