Feature: Polynomials and rational functions #469

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

View File

@ -149,7 +149,7 @@ public interface AbstractPolynomialSpace<C, P: AbstractPolynomial<C>> : Ring<P>
* Check if the instant is zero constant.
*/
@JvmName("constantIsZero")
public fun C.isZero(): Boolean
public fun C.isZero(): Boolean = this == constantZero
/**
* Check if the instant is NOT zero constant.
*/
@ -159,7 +159,7 @@ public interface AbstractPolynomialSpace<C, P: AbstractPolynomial<C>> : Ring<P>
* Check if the instant is unit constant.
*/
@JvmName("constantIsOne")
public fun C.isOne(): Boolean
public fun C.isOne(): Boolean = this == constantOne
/**
* Check if the instant is NOT unit constant.
*/
@ -169,12 +169,21 @@ public interface AbstractPolynomialSpace<C, P: AbstractPolynomial<C>> : Ring<P>
* Check if the instant is minus unit constant.
*/
@JvmName("constantIsMinusOne")
public fun C.isMinusOne(): Boolean
public fun C.isMinusOne(): Boolean = this == -constantOne
/**
* Check if the instant is NOT minus unit constant.
*/
@JvmName("constantIsNotMinusOne")
public fun C.isNotMinusOne(): Boolean = !isMinusOne()
/**
* Instance of zero constant (zero of the underlying ring).
*/
public val constantZero: C
/**
* Instance of unit constant (unit of the underlying ring).
*/
public val constantOne: C
// endregion
// region Constant-polynomial relation
@ -401,19 +410,12 @@ public interface AbstractPolynomialSpaceOverRing<C, P: AbstractPolynomial<C>, A:
public override operator fun C.times(other: C): C = ring { this@times * other }
/**
* Check if the instant is zero constant.
* Instance of zero constant (zero of the underlying ring).
*/
@JvmName("constantIsZero")
public override fun C.isZero(): Boolean = ring { this == zero }
public override val constantZero: C get() = ring.zero
/**
* Check if the instant is unit constant.
* Instance of unit constant (unit of the underlying ring).
*/
@JvmName("constantIsOne")
public override fun C.isOne(): Boolean = ring { this == one }
/**
* Check if the instant is minus unit constant.
*/
@JvmName("constantIsMinusOne")
public override fun C.isMinusOne(): Boolean = ring { this == -one }
public override val constantOne: C get() = ring.one
// endregion
}

View File

@ -190,7 +190,7 @@ public interface AbstractRationalFunctionalSpace<C, P: AbstractPolynomial<C>, R:
* Check if the instant is zero constant.
*/
@JvmName("constantIsZero")
public fun C.isZero(): Boolean
public fun C.isZero(): Boolean = this == constantZero
/**
* Check if the instant is NOT zero constant.
*/
@ -200,7 +200,7 @@ public interface AbstractRationalFunctionalSpace<C, P: AbstractPolynomial<C>, R:
* Check if the instant is unit constant.
*/
@JvmName("constantIsOne")
public fun C.isOne(): Boolean
public fun C.isOne(): Boolean = this == constantOne
/**
* Check if the instant is NOT unit constant.
*/
@ -210,12 +210,21 @@ public interface AbstractRationalFunctionalSpace<C, P: AbstractPolynomial<C>, R:
* Check if the instant is minus unit constant.
*/
@JvmName("constantIsMinusOne")
public fun C.isMinusOne(): Boolean
public fun C.isMinusOne(): Boolean = this == -constantOne
/**
* Check if the instant is NOT minus unit constant.
*/
@JvmName("constantIsNotMinusOne")
public fun C.isNotMinusOne(): Boolean = !isMinusOne()
/**
* Instance of zero constant (zero of the underlying ring).
*/
public val constantZero: C
/**
* Instance of unit constant (unit of the underlying ring).
*/
public val constantOne: C
// endregion
// region Constant-polynomial relation
@ -399,7 +408,7 @@ public interface AbstractRationalFunctionalSpace<C, P: AbstractPolynomial<C>, R:
/**
* Check if the instant is zero rational function.
*/
public fun R.isZero(): Boolean = this equalsTo zero
public fun R.isZero(): Boolean = numerator equalsTo polynomialZero
/**
* Check if the instant is NOT zero rational function.
*/
@ -407,7 +416,7 @@ public interface AbstractRationalFunctionalSpace<C, P: AbstractPolynomial<C>, R:
/**
* Check if the instant is unit rational function.
*/
public fun R.isOne(): Boolean = this equalsTo one
public fun R.isOne(): Boolean = numerator equalsTo denominator
/**
* Check if the instant is NOT unit rational function.
*/
@ -415,7 +424,7 @@ public interface AbstractRationalFunctionalSpace<C, P: AbstractPolynomial<C>, R:
/**
* Check if the instant is minus unit rational function.
*/
public fun R.isMinusOne(): Boolean = this equalsTo -one
public fun R.isMinusOne(): Boolean = (numerator + denominator).isZero()
/**
* Check if the instant is NOT minus unit rational function.
*/
@ -597,35 +606,13 @@ public interface AbstractRationalFunctionalSpaceOverRing<C, P: AbstractPolynomia
public override operator fun C.times(other: C): C = ring { this@times * other }
/**
* Check if the instant is zero constant.
* Instance of zero constant (zero of the underlying ring).
*/
@JvmName("constantIsZero")
public override fun C.isZero(): Boolean = ring { this@isZero.isZero() }
public override val constantZero: C get() = ring.zero
/**
* Check if the instant is NOT zero constant.
* Instance of unit constant (unit of the underlying ring).
*/
@JvmName("constantIsNotZero")
public override fun C.isNotZero(): Boolean = ring { this@isNotZero.isNotZero() }
/**
* Check if the instant is unit constant.
*/
@JvmName("constantIsOne")
public override fun C.isOne(): Boolean = ring { this@isOne.isOne() }
/**
* Check if the instant is NOT unit constant.
*/
@JvmName("constantIsNotOne")
public override fun C.isNotOne(): Boolean = ring { this@isNotOne.isNotOne() }
/**
* Check if the instant is minus unit constant.
*/
@JvmName("constantIsMinusOne")
public override fun C.isMinusOne(): Boolean = ring { this@isMinusOne.isMinusOne() }
/**
* Check if the instant is NOT minus unit constant.
*/
@JvmName("constantIsNotMinusOne")
public override fun C.isNotMinusOne(): Boolean = ring { this@isNotMinusOne.isNotMinusOne() }
public override val constantOne: C get() = ring.one
// endregion
}
@ -786,6 +773,15 @@ public interface AbstractRationalFunctionalSpaceOverPolynomialSpace<C, P: Abstra
*/
@JvmName("constantIsNotMinusOne")
public override fun C.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() }
/**
* Instance of zero constant (zero of the underlying ring).
*/
public override val constantZero: C get() = polynomialRing.constantZero
/**
* Instance of unit constant (unit of the underlying ring).
*/
public override val constantOne: C get() = polynomialRing.constantOne
// endregion
// region Constant-polynomial relation

View File

@ -1,3 +1,8 @@
/*
* 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.operations.*
@ -305,7 +310,7 @@ internal fun Map<Variable, UInt>.cleanUp() = filterValues { it > 0U }
//fun <C, A: Ring<C>> Variable.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(mapOf<Variable, UInt>(this to 1U) to one))
//
//context(LabeledPolynomialSpace<C, A>)
//fun <C, A: Ring<C>> Variable.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(mapOf<Variable, UInt>(this to 1U) to ring.one))
//fun <C, A: Ring<C>> Variable.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(mapOf<Variable, UInt>(this to 1U) to constantOne))
//
//context(A)
//fun <C, A: Ring<C>> Variable.asLabeledPolynomial(c: C) : LabeledPolynomial<C> =
@ -328,71 +333,54 @@ internal fun Map<Variable, UInt>.cleanUp() = filterValues { it > 0U }
*/
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME")
public class LabeledPolynomialSpace<C, A : Ring<C>>(
public val ring: A,
) : AbstractPolynomialSpace<C, LabeledPolynomial<C>> {
// region Constant-integer relation
@JvmName("constantIntPlus")
public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) }
@JvmName("constantIntMinus")
public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) }
@JvmName("constantIntTimes")
public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) }
// endregion
// region Integer-constant relation
@JvmName("intConstantPlus")
public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) }
@JvmName("intConstantMinus")
public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) }
@JvmName("intConstantTimes")
public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) }
// endregion
public override val ring: A,
) : AbstractPolynomialSpaceOverRing<C, LabeledPolynomial<C>, A> {
// region Variable-integer relation
public operator fun Variable.plus(other: Int): LabeledPolynomial<C> =
if (other == 0) LabeledPolynomial<C>(mapOf(
mapOf(this@plus to 1U) to ring.one,
mapOf(this@plus to 1U) to constantOne,
))
else LabeledPolynomial<C>(mapOf(
mapOf(this@plus to 1U) to ring.one,
emptyMap<Variable, UInt>() to ring.one * other,
mapOf(this@plus to 1U) to constantOne,
emptyMap<Variable, UInt>() to constantOne * other,
))
public operator fun Variable.minus(other: Int): LabeledPolynomial<C> =
if (other == 0) LabeledPolynomial<C>(mapOf(
mapOf(this@minus to 1U) to -ring.one,
mapOf(this@minus to 1U) to -constantOne,
))
else LabeledPolynomial<C>(mapOf(
mapOf(this@minus to 1U) to -ring.one,
emptyMap<Variable, UInt>() to ring.one * other,
mapOf(this@minus to 1U) to -constantOne,
emptyMap<Variable, UInt>() to constantOne * other,
))
public operator fun Variable.times(other: Int): LabeledPolynomial<C> =
if (other == 0) zero
else LabeledPolynomial<C>(mapOf(
mapOf(this to 1U) to ring.one * other,
mapOf(this to 1U) to constantOne * other,
))
// endregion
// region Integer-variable relation
public operator fun Int.plus(other: Variable): LabeledPolynomial<C> =
if (this == 0) LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to ring.one,
mapOf(other to 1U) to constantOne,
))
else LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to ring.one,
emptyMap<Variable, UInt>() to ring.one * this@plus,
mapOf(other to 1U) to constantOne,
emptyMap<Variable, UInt>() to constantOne * this@plus,
))
public operator fun Int.minus(other: Variable): LabeledPolynomial<C> =
if (this == 0) LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to -ring.one,
mapOf(other to 1U) to -constantOne,
))
else LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to -ring.one,
emptyMap<Variable, UInt>() to ring.one * this@minus,
mapOf(other to 1U) to -constantOne,
emptyMap<Variable, UInt>() to constantOne * this@minus,
))
public operator fun Int.times(other: Variable): LabeledPolynomial<C> =
if (this == 0) zero
else LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to ring.one * this@times,
mapOf(other to 1U) to constantOne * this@times,
))
// endregion
@ -406,7 +394,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyMap<Variable, UInt>()
val result = getOrElse(degs) { ring.zero } + other
val result = getOrElse(degs) { constantZero } + other
if (result.isZero()) remove(degs)
else this[degs] = result
@ -421,7 +409,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyMap<Variable, UInt>()
val result = getOrElse(degs) { ring.zero } - other
val result = getOrElse(degs) { constantZero } - other
if (result.isZero()) remove(degs)
else this[degs] = result
@ -447,7 +435,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyMap<Variable, UInt>()
val result = this@plus + getOrElse(degs) { ring.zero }
val result = this@plus + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
@ -462,7 +450,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyMap<Variable, UInt>()
val result = this@minus - getOrElse(degs) { ring.zero }
val result = this@minus - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
@ -478,44 +466,21 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
)
// endregion
// region Constant-constant relation
@JvmName("constantUnaryMinus")
override operator fun C.unaryMinus(): C = ring { -this@unaryMinus }
@JvmName("constantPlus")
override operator fun C.plus(other: C): C = ring { this@plus + other }
@JvmName("constantMinus")
override operator fun C.minus(other: C): C = ring { this@minus - other }
@JvmName("constantTimes")
override operator fun C.times(other: C): C = ring { this@times * other }
@JvmName("constantIsZero")
public override fun C.isZero(): Boolean = ring { this == zero }
@JvmName("constantIsNotZero")
public override fun C.isNotZero(): Boolean = ring { this != zero }
@JvmName("constantIsOne")
public override fun C.isOne(): Boolean = ring { this == one }
@JvmName("constantIsNotOne")
public override fun C.isNotOne(): Boolean = ring { this != one }
@JvmName("constantIsMinusOne")
public override fun C.isMinusOne(): Boolean = ring { this == -one }
@JvmName("constantIsNotMinusOne")
public override fun C.isNotMinusOne(): Boolean = ring { this != -one }
// endregion
// region Constant-variable relation
public operator fun C.plus(other: Variable): LabeledPolynomial<C> =
if (isZero()) LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to ring.one,
mapOf(other to 1U) to constantOne,
))
else LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to ring.one,
mapOf(other to 1U) to constantOne,
emptyMap<Variable, UInt>() to this@plus,
))
public operator fun C.minus(other: Variable): LabeledPolynomial<C> =
if (isZero()) LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to -ring.one,
mapOf(other to 1U) to -constantOne,
))
else LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to -ring.one,
mapOf(other to 1U) to -constantOne,
emptyMap<Variable, UInt>() to this@minus,
))
public operator fun C.times(other: Variable): LabeledPolynomial<C> =
@ -528,18 +493,18 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
// region Variable-constant relation
public operator fun Variable.plus(other: C): LabeledPolynomial<C> =
if (other.isZero()) LabeledPolynomial<C>(mapOf(
mapOf(this@plus to 1U) to ring.one,
mapOf(this@plus to 1U) to constantOne,
))
else LabeledPolynomial<C>(mapOf(
mapOf(this@plus to 1U) to ring.one,
mapOf(this@plus to 1U) to constantOne,
emptyMap<Variable, UInt>() to other,
))
public operator fun Variable.minus(other: C): LabeledPolynomial<C> =
if (other.isZero()) LabeledPolynomial<C>(mapOf(
mapOf(this@minus to 1U) to -ring.one,
mapOf(this@minus to 1U) to -constantOne,
))
else LabeledPolynomial<C>(mapOf(
mapOf(this@minus to 1U) to -ring.one,
mapOf(this@minus to 1U) to -constantOne,
emptyMap<Variable, UInt>() to other,
))
public operator fun Variable.times(other: C): LabeledPolynomial<C> =
@ -559,7 +524,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyMap<Variable, UInt>()
val result = this@plus + getOrElse(degs) { ring.zero }
val result = this@plus + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
@ -577,7 +542,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
val degs = emptyMap<Variable, UInt>()
val result = this@minus - getOrElse(degs) { ring.zero }
val result = this@minus - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
@ -607,7 +572,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyMap<Variable, UInt>()
val result = getOrElse(degs) { ring.zero } + other
val result = getOrElse(degs) { constantZero } + other
if (result.isZero()) remove(degs)
else this[degs] = result
@ -628,7 +593,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
val degs = emptyMap<Variable, UInt>()
val result = getOrElse(degs) { ring.zero } - other
val result = getOrElse(degs) { constantZero } - other
if (result.isZero()) remove(degs)
else this[degs] = result
@ -651,37 +616,37 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
// region Variable-variable relation
public operator fun Variable.plus(other: Variable): LabeledPolynomial<C> =
if (this == other) LabeledPolynomial<C>(mapOf(
mapOf(this to 1U) to ring.one * 2
mapOf(this to 1U) to constantOne * 2
))
else LabeledPolynomial<C>(mapOf(
mapOf(this to 1U) to ring.one,
mapOf(other to 1U) to ring.one,
mapOf(this to 1U) to constantOne,
mapOf(other to 1U) to constantOne,
))
public operator fun Variable.minus(other: Variable): LabeledPolynomial<C> =
if (this == other) zero
else LabeledPolynomial<C>(mapOf(
mapOf(this to 1U) to ring.one,
mapOf(other to 1U) to -ring.one,
mapOf(this to 1U) to constantOne,
mapOf(other to 1U) to -constantOne,
))
public operator fun Variable.times(other: Variable): LabeledPolynomial<C> =
if (this == other) LabeledPolynomial<C>(mapOf(
mapOf(this to 2U) to ring.one
mapOf(this to 2U) to constantOne
))
else LabeledPolynomial<C>(mapOf(
mapOf(this to 1U, other to 1U) to ring.one,
mapOf(this to 1U, other to 1U) to constantOne,
))
// endregion
// region Variable-polynomial relation
public operator fun Variable.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
with(other.coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(mapOf(this@plus to 1u) to ring.one))
if (isEmpty()) LabeledPolynomial<C>(mapOf(mapOf(this@plus to 1u) to constantOne))
else LabeledPolynomial<C>(
toMutableMap()
.apply {
val degs = mapOf(this@plus to 1U)
val result = ring.one + getOrElse(degs) { ring.zero }
val result = constantOne + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
@ -690,7 +655,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
}
public operator fun Variable.minus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
with(other.coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(mapOf(this@minus to 1u) to ring.one))
if (isEmpty()) LabeledPolynomial<C>(mapOf(mapOf(this@minus to 1u) to constantOne))
else LabeledPolynomial<C>(
toMutableMap()
.apply {
@ -698,7 +663,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
val degs = mapOf(this@minus to 1U)
val result = ring.one - getOrElse(degs) { ring.zero }
val result = constantOne - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
@ -715,13 +680,13 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
// region Polynomial-variable relation
public operator fun LabeledPolynomial<C>.plus(other: Variable): LabeledPolynomial<C> =
with(coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(mapOf(other to 1u) to ring.one))
if (isEmpty()) LabeledPolynomial<C>(mapOf(mapOf(other to 1u) to constantOne))
else LabeledPolynomial<C>(
toMutableMap()
.apply {
val degs = mapOf(other to 1U)
val result = ring.one + getOrElse(degs) { ring.zero }
val result = constantOne + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
@ -730,13 +695,13 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
}
public operator fun LabeledPolynomial<C>.minus(other: Variable): LabeledPolynomial<C> =
with(coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(mapOf(other to 1u) to ring.one))
if (isEmpty()) LabeledPolynomial<C>(mapOf(mapOf(other to 1u) to constantOne))
else LabeledPolynomial<C>(
toMutableMap()
.apply {
val degs = mapOf(other to 1U)
val result = ring.one - getOrElse(degs) { ring.zero }
val result = constantOne - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
@ -799,8 +764,8 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
)
}
override val zero: LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(emptyMap<Variable, UInt>() to ring.zero))
override val one: LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(emptyMap<Variable, UInt>() to ring.one))
override val zero: LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(emptyMap<Variable, UInt>() to constantZero))
override val one: LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(emptyMap<Variable, UInt>() to constantOne))
// TODO: Docs
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals")
@ -872,7 +837,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
override fun LabeledPolynomial<C>.asConstantOrNull(): C? =
with(coefficients) {
if(isConstant()) getOrElse(emptyMap()) { ring.zero }
if(isConstant()) getOrElse(emptyMap()) { constantZero }
else null
}

View File

@ -0,0 +1,464 @@
/*
* 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.operations.Ring
import space.kscience.kmath.operations.invoke
public class LabeledRationalFunction<C>(
public override val numerator: LabeledPolynomial<C>,
public override val denominator: LabeledPolynomial<C>
) : AbstractRationalFunction<C, LabeledPolynomial<C>> {
override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}"
}
// region Internal utilities
/**
* Represents internal [LabeledRationalFunction] errors.
*/
internal class LabeledRationalFunctionError : Error {
constructor(): super()
constructor(message: String): super(message)
constructor(message: String?, cause: Throwable?): super(message, cause)
constructor(cause: Throwable?): super(cause)
}
/**
* Throws an [LabeledRationalFunctionError] with the given [message].
*/
internal fun labeledRationalFunctionError(message: Any): Nothing = throw LabeledRationalFunctionError(message.toString())
// endregion
// region Constructors and converters
// Waiting for context receivers :( TODO: Replace with context receivers when they will be available
//context(RationalFunctionSpace<C, A>)
//@Suppress("FunctionName")
//internal fun <C, A: Ring<C>> RationalFunction(numerator: Polynomial<C>, denominator: Polynomial<C>): RationalFunction<C> =
// if (denominator.isZero()) throw ArithmeticException("/ by zero")
// else RationalFunction<C>(numerator, denominator)
//context(RationalFunctionSpace<C, A>)
//@Suppress("FunctionName")
//public fun <C, A: Ring<C>> RationalFunction(numeratorCoefficients: List<C>, denominatorCoefficients: List<C>, reverse: Boolean = false): RationalFunction<C> =
// RationalFunction<C>(
// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ),
// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) }
// )
//context(RationalFunctionSpace<C, A>)
//@Suppress("FunctionName")
//public fun <C, A: Ring<C>> RationalFunction(numerator: Polynomial<C>): RationalFunction<C> =
// RationalFunction(numerator, onePolynomial)
//context(RationalFunctionSpace<C, A>)
//@Suppress("FunctionName")
//public fun <C, A: Ring<C>> RationalFunction(numeratorCoefficients: List<C>, reverse: Boolean = false): RationalFunction<C> =
// RationalFunction(
// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } )
// )
// TODO: Rewrite former constructors as fabrics
//constructor(numeratorCoefficients: Map<Map<Variable, Int>, C>, denominatorCoefficients: Map<Map<Variable, Int>, C>) : this(
//LabeledPolynomial(numeratorCoefficients),
//LabeledPolynomial(denominatorCoefficients)
//)
//
//constructor(numeratorCoefficients: Collection<Pair<Map<Variable, Int>, C>>, denominatorCoefficients: Collection<Pair<Map<Variable, Int>, C>>) : this(
//LabeledPolynomial(numeratorCoefficients),
//LabeledPolynomial(denominatorCoefficients)
//)
//
//constructor(numerator: LabeledPolynomial<C>) : this(numerator, numerator.getOne())
//constructor(numeratorCoefficients: Map<Map<Variable, Int>, C>) : this(
//LabeledPolynomial(numeratorCoefficients)
//)
//
//constructor(numeratorCoefficients: Collection<Pair<Map<Variable, Int>, C>>) : this(
//LabeledPolynomial(numeratorCoefficients)
//)
// endregion
public class LabeledRationalFunctionSpace<C, A: Ring<C>>(
public val ring: A,
) : AbstractRationalFunctionalSpaceOverPolynomialSpace<C, LabeledPolynomial<C>, LabeledRationalFunction<C>, A> {
override val polynomialRing : LabeledPolynomialSpace<C, A> = LabeledPolynomialSpace(ring)
// region Rational-integer relation
/**
* Returns sum of the rational function and the integer represented as rational function.
*
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
*/
public override operator fun LabeledRationalFunction<C>.plus(other: Int): LabeledRationalFunction<C> =
LabeledRationalFunction(
numerator + denominator * other,
denominator
)
/**
* Returns difference between the rational function and the integer represented as rational function.
*
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
*/
public override operator fun LabeledRationalFunction<C>.minus(other: Int): LabeledRationalFunction<C> =
LabeledRationalFunction(
numerator - denominator * other,
denominator
)
/**
* Returns product of the rational function and the integer represented as rational function.
*
* The operation is equivalent to sum of [other] copies of [this].
*/
public override operator fun LabeledRationalFunction<C>.times(other: Int): LabeledRationalFunction<C> =
LabeledRationalFunction(
numerator * other,
denominator
)
// endregion
// region Integer-Rational relation
/**
* Returns sum of the integer represented as rational function and the rational function.
*
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
*/
public override operator fun Int.plus(other: LabeledRationalFunction<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
other.denominator * this + other.numerator,
other.denominator
)
/**
* Returns difference between the integer represented as rational function and the rational function.
*
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
*/
public override operator fun Int.minus(other: LabeledRationalFunction<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
other.denominator * this - other.numerator,
other.denominator
)
/**
* Returns product of the integer represented as rational function and the rational function.
*
* The operation is equivalent to sum of [this] copies of [other].
*/
public override operator fun Int.times(other: LabeledRationalFunction<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
this * other.numerator,
other.denominator
)
// endregion
// region Constant-rational relation
/**
* Returns sum of the constant represented as rational function and the rational function.
*/
public override operator fun C.plus(other: LabeledRationalFunction<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
other.denominator * this + other.numerator,
other.denominator
)
/**
* Returns difference between the constant represented as polynomial and the rational function.
*/
public override operator fun C.minus(other: LabeledRationalFunction<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
other.denominator * this - other.numerator,
other.denominator
)
/**
* Returns product of the constant represented as polynomial and the rational function.
*/
public override operator fun C.times(other: LabeledRationalFunction<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
this * other.numerator,
other.denominator
)
// endregion
// region Rational-constant relation
/**
* Returns sum of the constant represented as rational function and the rational function.
*/
public override operator fun LabeledRationalFunction<C>.plus(other: C): LabeledRationalFunction<C> =
LabeledRationalFunction(
numerator + denominator * other,
denominator
)
/**
* Returns difference between the constant represented as rational function and the rational function.
*/
public override operator fun LabeledRationalFunction<C>.minus(other: C): LabeledRationalFunction<C> =
LabeledRationalFunction(
numerator - denominator * other,
denominator
)
/**
* Returns product of the constant represented as rational function and the rational function.
*/
public override operator fun LabeledRationalFunction<C>.times(other: C): LabeledRationalFunction<C> =
LabeledRationalFunction(
numerator * other,
denominator
)
// endregion
// region Polynomial-rational relation
/**
* Returns sum of the polynomial represented as rational function and the rational function.
*/
public override operator fun LabeledPolynomial<C>.plus(other: LabeledRationalFunction<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
other.denominator * this + other.numerator,
other.denominator
)
/**
* Returns difference between the polynomial represented as polynomial and the rational function.
*/
public override operator fun LabeledPolynomial<C>.minus(other: LabeledRationalFunction<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
other.denominator * this - other.numerator,
other.denominator
)
/**
* Returns product of the polynomial represented as polynomial and the rational function.
*/
public override operator fun LabeledPolynomial<C>.times(other: LabeledRationalFunction<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
this * other.numerator,
other.denominator
)
// endregion
// region Rational-polynomial relation
/**
* Returns sum of the polynomial represented as rational function and the rational function.
*/
public override operator fun LabeledRationalFunction<C>.plus(other: LabeledPolynomial<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
numerator + denominator * other,
denominator
)
/**
* Returns difference between the polynomial represented as rational function and the rational function.
*/
public override operator fun LabeledRationalFunction<C>.minus(other: LabeledPolynomial<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
numerator - denominator * other,
denominator
)
/**
* Returns product of the polynomial represented as rational function and the rational function.
*/
public override operator fun LabeledRationalFunction<C>.times(other: LabeledPolynomial<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
numerator * other,
denominator
)
// endregion
// region Rational-rational relation
/**
* Returns negation of the rational function.
*/
public override operator fun LabeledRationalFunction<C>.unaryMinus(): LabeledRationalFunction<C> = LabeledRationalFunction(-numerator, denominator)
/**
* Returns sum of the rational functions.
*/
public override operator fun LabeledRationalFunction<C>.plus(other: LabeledRationalFunction<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
numerator * other.denominator + denominator * other.numerator,
denominator * other.denominator
)
/**
* Returns difference of the rational functions.
*/
public override operator fun LabeledRationalFunction<C>.minus(other: LabeledRationalFunction<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
numerator * other.denominator - denominator * other.numerator,
denominator * other.denominator
)
/**
* Returns product of the rational functions.
*/
public override operator fun LabeledRationalFunction<C>.times(other: LabeledRationalFunction<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
numerator * other.numerator,
denominator * other.denominator
)
/**
* Instance of zero rational function (zero of the rational functions ring).
*/
public override val zero: LabeledRationalFunction<C> = LabeledRationalFunction(polynomialZero, polynomialOne)
/**
* Instance of unit polynomial (unit of the rational functions ring).
*/
public override val one: LabeledRationalFunction<C> = LabeledRationalFunction(polynomialOne, polynomialOne)
/**
* Checks equality of the rational functions.
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals")
public override infix fun LabeledRationalFunction<C>.equalsTo(other: LabeledRationalFunction<C>): Boolean {
if (this === other) return true
if ( !(numerator.isZero() xor other.numerator.isZero()) ) return false
val variables = this.variables union other.variables
val thisNumeratorDegrees = this.numerator.degrees
val thisDenominatorDegrees = this.denominator.degrees
val otherNumeratorDegrees = other.numerator.degrees
val otherDenominatorDegrees = other.denominator.degrees
for (variable in variables)
if (
thisNumeratorDegrees.getOrElse(variable) { 0u } + otherDenominatorDegrees.getOrElse(variable) { 0u }
!= thisDenominatorDegrees.getOrElse(variable) { 0u } + otherNumeratorDegrees.getOrElse(variable) { 0u }
) return false
return numerator * other.denominator equalsTo other.numerator * denominator
}
// endregion
// region Polynomial properties
/**
* Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents
* in which they are appeared in the polynomial.
*
* As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty.
* And keys of the map is the same as in [variables].
*/
public val LabeledPolynomial<C>.degrees: Map<Variable, UInt> get() = polynomialRing { degrees }
/**
* Set of all variables that appear in the polynomial in positive exponents.
*/
public val LabeledPolynomial<C>.variables: Set<Variable> get() = polynomialRing { variables }
/**
* Count of all variables that appear in the polynomial in positive exponents.
*/
public val LabeledPolynomial<C>.countOfVariables: Int get() = polynomialRing { countOfVariables }
// endregion
// region Rational properties
/**
* Count of all variables that appear in the polynomial in positive exponents.
*/
public val LabeledRationalFunction<C>.variables: Set<Variable>
get() = numerator.variables union denominator.variables
/**
* Count of all variables that appear in the polynomial in positive exponents.
*/
public val LabeledRationalFunction<C>.countOfVariables: Int get() = variables.size
// endregion
// region REST TODO: Разобрать
public operator fun LabeledRationalFunction<C>.div(other: LabeledRationalFunction<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
numerator * other.denominator,
denominator * other.numerator
)
public operator fun LabeledRationalFunction<C>.div(other: LabeledPolynomial<C>): LabeledRationalFunction<C> =
LabeledRationalFunction(
numerator,
denominator * other
)
public operator fun LabeledRationalFunction<C>.div(other: C): LabeledRationalFunction<C> =
LabeledRationalFunction(
numerator,
denominator * other
)
// operator fun invoke(arg: Map<Variable, C>): LabeledRationalFunction<C> =
// LabeledRationalFunction(
// numerator(arg),
// denominator(arg)
// )
//
// @JvmName("invokeLabeledPolynomial")
// operator fun invoke(arg: Map<Variable, LabeledPolynomial<C>>): LabeledRationalFunction<C> =
// LabeledRationalFunction(
// numerator(arg),
// denominator(arg)
// )
//
// @JvmName("invokeLabeledRationalFunction")
// operator fun invoke(arg: Map<Variable, LabeledRationalFunction<C>>): LabeledRationalFunction<C> {
// var num = numerator invokeRFTakeNumerator arg
// var den = denominator invokeRFTakeNumerator arg
// for (variable in variables) if (variable in arg) {
// val degreeDif = degrees[variable]!!
// if (degreeDif > 0)
// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif)
// else
// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif)
// }
// return LabeledRationalFunction(num, den)
// }
//
// override fun toString(): String = toString(emptyMap())
//
// fun toString(names: Map<Variable, String> = emptyMap()): String =
// when (true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toString(names)
// else -> "${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)}"
// }
//
// fun toString(namer: (Variable) -> String): String =
// when (true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toString(namer)
// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}"
// }
//
// fun toStringWithBrackets(names: Map<Variable, String> = emptyMap()): String =
// when (true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toStringWithBrackets(names)
// else -> "(${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)})"
// }
//
// fun toStringWithBrackets(namer: (Variable) -> String): String =
// when (true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toStringWithBrackets(namer)
// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})"
// }
//
// fun toReversedString(names: Map<Variable, String> = emptyMap()): String =
// when (true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toReversedString(names)
// else -> "${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)}"
// }
//
// fun toReversedString(namer: (Variable) -> String): String =
// when (true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toReversedString(namer)
// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}"
// }
//
// fun toReversedStringWithBrackets(names: Map<Variable, String> = emptyMap()): String =
// when (true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toReversedStringWithBrackets(names)
// else -> "(${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)})"
// }
//
// fun toReversedStringWithBrackets(namer: (Variable) -> String): String =
// when (true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer)
// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})"
// }
}

View File

@ -1,3 +1,8 @@
/*
* 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.operations.*
@ -272,7 +277,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyList<UInt>()
val result = getOrElse(degs) { ring.zero } + other
val result = getOrElse(degs) { constantZero } + other
if (result.isZero()) remove(degs)
else this[degs] = result
@ -287,7 +292,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyList<UInt>()
val result = getOrElse(degs) { ring.zero } - other
val result = getOrElse(degs) { constantZero } - other
if (result.isZero()) remove(degs)
else this[degs] = result
@ -313,7 +318,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyList<UInt>()
val result = this@plus + getOrElse(degs) { ring.zero }
val result = this@plus + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
@ -328,7 +333,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyList<UInt>()
val result = this@minus - getOrElse(degs) { ring.zero }
val result = this@minus - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
@ -354,7 +359,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyList<UInt>()
val result = this@plus + getOrElse(degs) { ring.zero }
val result = this@plus + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
@ -372,7 +377,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
val degs = emptyList<UInt>()
val result = this@minus - getOrElse(degs) { ring.zero }
val result = this@minus - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
@ -402,7 +407,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyList<UInt>()
val result = getOrElse(degs) { ring.zero } + other
val result = getOrElse(degs) { constantZero } + other
if (result.isZero()) remove(degs)
else this[degs] = result
@ -421,7 +426,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyList<UInt>()
val result = getOrElse(degs) { ring.zero } - other
val result = getOrElse(degs) { constantZero } - other
if (result.isZero()) remove(degs)
else this[degs] = result
@ -522,7 +527,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
override val one: NumberedPolynomial<C> =
NumberedPolynomial<C>(
mapOf(
listOf<UInt>() to ring.one // 1 * x_1^0 * x_2^0 * ...
listOf<UInt>() to constantOne // 1 * x_1^0 * x_2^0 * ...
)
)
@ -538,6 +543,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
// Not sure is it necessary...
// region Polynomial properties
// TODO: Replace `countOfVariables` with `lastVariable` and create new `countOfVariables`
/**
* Count of all variables that appear in the polynomial in positive exponents.
*/
@ -590,7 +596,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
override fun NumberedPolynomial<C>.asConstantOrNull(): C? =
with(coefficients) {
if(isConstant()) getOrElse(emptyList()) { ring.zero }
if(isConstant()) getOrElse(emptyList()) { constantZero }
else null
}

View File

@ -0,0 +1,453 @@
/*
* 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.operations.*
import kotlin.math.max
public class NumberedRationalFunction<C> internal constructor(
public override val numerator: NumberedPolynomial<C>,
public override val denominator: NumberedPolynomial<C>
) : AbstractRationalFunction<C, NumberedPolynomial<C>> {
override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}"
}
// region Internal utilities
/**
* Represents internal [NumberedRationalFunction] errors.
*/
internal class NumberedRationalFunctionError : Error {
constructor(): super()
constructor(message: String): super(message)
constructor(message: String?, cause: Throwable?): super(message, cause)
constructor(cause: Throwable?): super(cause)
}
/**
* Throws an [NumberedRationalFunctionError] with the given [message].
*/
internal fun numberedRationalFunctionError(message: Any): Nothing = throw NumberedRationalFunctionError(message.toString())
// endregion
// region Constructors and converters
// Waiting for context receivers :( TODO: Replace with context receivers when they will be available
//context(RationalFunctionSpace<C, A>)
//@Suppress("FunctionName")
//internal fun <C, A: Ring<C>> RationalFunction(numerator: Polynomial<C>, denominator: Polynomial<C>): RationalFunction<C> =
// if (denominator.isZero()) throw ArithmeticException("/ by zero")
// else RationalFunction<C>(numerator, denominator)
//context(RationalFunctionSpace<C, A>)
//@Suppress("FunctionName")
//public fun <C, A: Ring<C>> RationalFunction(numeratorCoefficients: List<C>, denominatorCoefficients: List<C>, reverse: Boolean = false): RationalFunction<C> =
// RationalFunction<C>(
// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ),
// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) }
// )
//context(RationalFunctionSpace<C, A>)
//@Suppress("FunctionName")
//public fun <C, A: Ring<C>> RationalFunction(numerator: Polynomial<C>): RationalFunction<C> =
// RationalFunction(numerator, onePolynomial)
//context(RationalFunctionSpace<C, A>)
//@Suppress("FunctionName")
//public fun <C, A: Ring<C>> RationalFunction(numeratorCoefficients: List<C>, reverse: Boolean = false): RationalFunction<C> =
// RationalFunction(
// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } )
// )
// TODO: Rewrite former constructors as fabrics
//constructor(numeratorCoefficients: Map<List<Int>, C>, denominatorCoefficients: Map<List<Int>, C>) : this(
//Polynomial(numeratorCoefficients),
//Polynomial(denominatorCoefficients)
//)
//constructor(numeratorCoefficients: Collection<Pair<List<Int>, C>>, denominatorCoefficients: Collection<Pair<List<Int>, C>>) : this(
//Polynomial(numeratorCoefficients),
//Polynomial(denominatorCoefficients)
//)
//constructor(numerator: Polynomial<C>) : this(numerator, numerator.getOne())
//constructor(numeratorCoefficients: Map<List<Int>, C>) : this(
//Polynomial(numeratorCoefficients)
//)
//constructor(numeratorCoefficients: Collection<Pair<List<Int>, C>>) : this(
//Polynomial(numeratorCoefficients)
//)
// endregion
public class NumberedRationalFunctionSpace<C, A: Ring<C>> (
public val ring: A,
) : AbstractRationalFunctionalSpaceOverPolynomialSpace<C, NumberedPolynomial<C>, NumberedRationalFunction<C>, A> {
override val polynomialRing : NumberedPolynomialSpace<C, A> = NumberedPolynomialSpace(ring)
// region Rational-integer relation
/**
* Returns sum of the rational function and the integer represented as rational function.
*
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
*/
public override operator fun NumberedRationalFunction<C>.plus(other: Int): NumberedRationalFunction<C> =
NumberedRationalFunction(
numerator + denominator * other,
denominator
)
/**
* Returns difference between the rational function and the integer represented as rational function.
*
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
*/
public override operator fun NumberedRationalFunction<C>.minus(other: Int): NumberedRationalFunction<C> =
NumberedRationalFunction(
numerator - denominator * other,
denominator
)
/**
* Returns product of the rational function and the integer represented as rational function.
*
* The operation is equivalent to sum of [other] copies of [this].
*/
public override operator fun NumberedRationalFunction<C>.times(other: Int): NumberedRationalFunction<C> =
NumberedRationalFunction(
numerator * other,
denominator
)
// endregion
// region Integer-Rational relation
/**
* Returns sum of the integer represented as rational function and the rational function.
*
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
*/
public override operator fun Int.plus(other: NumberedRationalFunction<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
other.denominator * this + other.numerator,
other.denominator
)
/**
* Returns difference between the integer represented as rational function and the rational function.
*
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
*/
public override operator fun Int.minus(other: NumberedRationalFunction<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
other.denominator * this - other.numerator,
other.denominator
)
/**
* Returns product of the integer represented as rational function and the rational function.
*
* The operation is equivalent to sum of [this] copies of [other].
*/
public override operator fun Int.times(other: NumberedRationalFunction<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
this * other.numerator,
other.denominator
)
// endregion
// region Constant-rational relation
/**
* Returns sum of the constant represented as rational function and the rational function.
*/
public override operator fun C.plus(other: NumberedRationalFunction<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
other.denominator * this + other.numerator,
other.denominator
)
/**
* Returns difference between the constant represented as polynomial and the rational function.
*/
public override operator fun C.minus(other: NumberedRationalFunction<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
other.denominator * this - other.numerator,
other.denominator
)
/**
* Returns product of the constant represented as polynomial and the rational function.
*/
public override operator fun C.times(other: NumberedRationalFunction<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
this * other.numerator,
other.denominator
)
// endregion
// region Rational-constant relation
/**
* Returns sum of the constant represented as rational function and the rational function.
*/
public override operator fun NumberedRationalFunction<C>.plus(other: C): NumberedRationalFunction<C> =
NumberedRationalFunction(
numerator + denominator * other,
denominator
)
/**
* Returns difference between the constant represented as rational function and the rational function.
*/
public override operator fun NumberedRationalFunction<C>.minus(other: C): NumberedRationalFunction<C> =
NumberedRationalFunction(
numerator - denominator * other,
denominator
)
/**
* Returns product of the constant represented as rational function and the rational function.
*/
public override operator fun NumberedRationalFunction<C>.times(other: C): NumberedRationalFunction<C> =
NumberedRationalFunction(
numerator * other,
denominator
)
// endregion
// region Polynomial-rational relation
/**
* Returns sum of the polynomial represented as rational function and the rational function.
*/
public override operator fun NumberedPolynomial<C>.plus(other: NumberedRationalFunction<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
other.denominator * this + other.numerator,
other.denominator
)
/**
* Returns difference between the polynomial represented as polynomial and the rational function.
*/
public override operator fun NumberedPolynomial<C>.minus(other: NumberedRationalFunction<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
other.denominator * this - other.numerator,
other.denominator
)
/**
* Returns product of the polynomial represented as polynomial and the rational function.
*/
public override operator fun NumberedPolynomial<C>.times(other: NumberedRationalFunction<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
this * other.numerator,
other.denominator
)
// endregion
// region Rational-polynomial relation
/**
* Returns sum of the polynomial represented as rational function and the rational function.
*/
public override operator fun NumberedRationalFunction<C>.plus(other: NumberedPolynomial<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
numerator + denominator * other,
denominator
)
/**
* Returns difference between the polynomial represented as rational function and the rational function.
*/
public override operator fun NumberedRationalFunction<C>.minus(other: NumberedPolynomial<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
numerator - denominator * other,
denominator
)
/**
* Returns product of the polynomial represented as rational function and the rational function.
*/
public override operator fun NumberedRationalFunction<C>.times(other: NumberedPolynomial<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
numerator * other,
denominator
)
// endregion
// region Rational-rational relation
/**
* Returns negation of the rational function.
*/
public override operator fun NumberedRationalFunction<C>.unaryMinus(): NumberedRationalFunction<C> = NumberedRationalFunction(-numerator, denominator)
/**
* Returns sum of the rational functions.
*/
public override operator fun NumberedRationalFunction<C>.plus(other: NumberedRationalFunction<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
numerator * other.denominator + denominator * other.numerator,
denominator * other.denominator
)
/**
* Returns difference of the rational functions.
*/
public override operator fun NumberedRationalFunction<C>.minus(other: NumberedRationalFunction<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
numerator * other.denominator - denominator * other.numerator,
denominator * other.denominator
)
/**
* Returns product of the rational functions.
*/
public override operator fun NumberedRationalFunction<C>.times(other: NumberedRationalFunction<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
numerator * other.numerator,
denominator * other.denominator
)
/**
* Instance of zero rational function (zero of the rational functions ring).
*/
public override val zero: NumberedRationalFunction<C> = NumberedRationalFunction(polynomialZero, polynomialOne)
/**
* Instance of unit polynomial (unit of the rational functions ring).
*/
public override val one: NumberedRationalFunction<C> = NumberedRationalFunction(polynomialOne, polynomialOne)
/**
* Checks equality of the rational functions.
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals")
public override infix fun NumberedRationalFunction<C>.equalsTo(other: NumberedRationalFunction<C>): Boolean {
if (this === other) return true
if ( !(numerator.isZero() xor other.numerator.isZero()) ) return false
val countOfVariables = max(this.countOfVariables, other.countOfVariables)
val thisNumeratorDegrees = this.numerator.degrees
val thisDenominatorDegrees = this.denominator.degrees
val otherNumeratorDegrees = other.numerator.degrees
val otherDenominatorDegrees = other.denominator.degrees
for (variable in 0 until countOfVariables)
if (
thisNumeratorDegrees.getOrElse(variable) { 0u } + otherDenominatorDegrees.getOrElse(variable) { 0u }
!= thisDenominatorDegrees.getOrElse(variable) { 0u } + otherNumeratorDegrees.getOrElse(variable) { 0u }
) return false
return numerator * other.denominator equalsTo other.numerator * denominator
}
// endregion
// region Polynomial properties
/**
* Count of all variables that appear in the polynomial in positive exponents.
*/
public val NumberedPolynomial<C>.countOfVariables: Int get() = polynomialRing { countOfVariables }
/**
* List that associates indices of variables (that appear in the polynomial in positive exponents) with their most
* exponents in which the variables are appeared in the polynomial.
*
* As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty.
* And size of the list is [countOfVariables].
*/
public val NumberedPolynomial<C>.degrees: List<UInt> get() = polynomialRing { degrees }
// endregion
// region Rational properties
/**
* Count of all variables that appear in the polynomial in positive exponents.
*/
public val NumberedRationalFunction<C>.countOfVariables: Int
get() = polynomialRing { max(numerator.countOfVariables, denominator.countOfVariables) }
// endregion
// region REST TODO: Разобрать
public operator fun NumberedRationalFunction<C>.div(other: NumberedRationalFunction<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
numerator * other.denominator,
denominator * other.numerator
)
public operator fun NumberedRationalFunction<C>.div(other: NumberedPolynomial<C>): NumberedRationalFunction<C> =
NumberedRationalFunction(
numerator,
denominator * other
)
public operator fun NumberedRationalFunction<C>.div(other: C): NumberedRationalFunction<C> =
NumberedRationalFunction(
numerator,
denominator * other
)
// operator fun invoke(arg: Map<Int, C>): NumberedRationalFunction<C> =
// NumberedRationalFunction(
// numerator(arg),
// denominator(arg)
// )
//
// @JvmName("invokePolynomial")
// operator fun invoke(arg: Map<Int, Polynomial<C>>): NumberedRationalFunction<C> =
// NumberedRationalFunction(
// numerator(arg),
// denominator(arg)
// )
//
// @JvmName("invokeRationalFunction")
// operator fun invoke(arg: Map<Int, NumberedRationalFunction<C>>): NumberedRationalFunction<C> {
// var num = numerator invokeRFTakeNumerator arg
// var den = denominator invokeRFTakeNumerator arg
// for (variable in 0 until max(numerator.countOfVariables, denominator.countOfVariables)) if (variable in arg) {
// val degreeDif = numerator.degrees.getOrElse(variable) { 0 } - denominator.degrees.getOrElse(variable) { 0 }
// if (degreeDif > 0)
// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif)
// else
// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif)
// }
// return NumberedRationalFunction(num, den)
// }
//
// override fun toString(): String = toString(Polynomial.variableName)
//
// fun toString(withVariableName: String = Polynomial.variableName): String =
// when(true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toString(withVariableName)
// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}"
// }
//
// fun toString(namer: (Int) -> String): String =
// when(true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toString(namer)
// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}"
// }
//
// fun toStringWithBrackets(withVariableName: String = Polynomial.variableName): String =
// when(true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName)
// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})"
// }
//
// fun toStringWithBrackets(namer: (Int) -> String): String =
// when(true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toStringWithBrackets(namer)
// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})"
// }
//
// fun toReversedString(withVariableName: String = Polynomial.variableName): String =
// when(true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toReversedString(withVariableName)
// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}"
// }
//
// fun toReversedString(namer: (Int) -> String): String =
// when(true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toReversedString(namer)
// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}"
// }
//
// fun toReversedStringWithBrackets(withVariableName: String = Polynomial.variableName): String =
// when(true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName)
// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})"
// }
//
// fun toReversedStringWithBrackets(namer: (Int) -> String): String =
// when(true) {
// numerator.isZero() -> "0"
// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer)
// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})"
// }
}

View File

@ -80,7 +80,7 @@ public open class PolynomialSpace<C, A : Ring<C>>(
coefficients
.toMutableList()
.apply {
val result = getOrElse(0) { ring.zero } + other
val result = getOrElse(0) { constantZero } + other
val isResultZero = result.isZero()
when {
@ -97,7 +97,7 @@ public open class PolynomialSpace<C, A : Ring<C>>(
coefficients
.toMutableList()
.apply {
val result = getOrElse(0) { ring.zero } - other
val result = getOrElse(0) { constantZero } - other
val isResultZero = result.isZero()
when {
@ -124,7 +124,7 @@ public open class PolynomialSpace<C, A : Ring<C>>(
other.coefficients
.toMutableList()
.apply {
val result = this@plus + getOrElse(0) { ring.zero }
val result = this@plus + getOrElse(0) { constantZero }
val isResultZero = result.isZero()
when {
@ -143,7 +143,7 @@ public open class PolynomialSpace<C, A : Ring<C>>(
.apply {
forEachIndexed { index, c -> if (index != 0) this[index] = -c }
val result = this@minus - getOrElse(0) { ring.zero }
val result = this@minus - getOrElse(0) { constantZero }
val isResultZero = result.isZero()
when {
@ -281,7 +281,7 @@ public open class PolynomialSpace<C, A : Ring<C>>(
else -> coefficients[it] + other.coefficients[it]
}
}
.ifEmpty { listOf(ring.zero) }
.ifEmpty { listOf(constantZero) }
)
public override operator fun Polynomial<C>.minus(other: Polynomial<C>): Polynomial<C> =
Polynomial(
@ -293,7 +293,7 @@ public open class PolynomialSpace<C, A : Ring<C>>(
else -> coefficients[it] - other.coefficients[it]
}
}
.ifEmpty { listOf(ring.zero) }
.ifEmpty { listOf(constantZero) }
)
public override operator fun Polynomial<C>.times(other: Polynomial<C>): Polynomial<C> {
val thisDegree = degree
@ -321,7 +321,7 @@ public open class PolynomialSpace<C, A : Ring<C>>(
with(coefficients) { isNotEmpty() && asSequence().withIndex().any { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } } // TODO: It's better to write new methods like `anyIndexed`. But what's better way to do it?
override val zero: Polynomial<C> = Polynomial(emptyList())
override val one: Polynomial<C> = Polynomial(listOf(ring.one))
override val one: Polynomial<C> = Polynomial(listOf(constantZero))
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals")
public override infix fun Polynomial<C>.equalsTo(other: Polynomial<C>): Boolean =
@ -337,12 +337,12 @@ public open class PolynomialSpace<C, A : Ring<C>>(
// region Polynomial properties
public override val Polynomial<C>.degree: Int get() = coefficients.indexOfLast { it != ring.zero }
public override val Polynomial<C>.degree: Int get() = coefficients.indexOfLast { it != constantZero }
public override fun Polynomial<C>.asConstantOrNull(): C? =
with(coefficients) {
when {
isEmpty() -> ring.zero
isEmpty() -> constantZero
degree > 0 -> null
else -> first()
}

View File

@ -1,3 +1,8 @@
/*
* 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.operations.*
@ -270,19 +275,6 @@ public class RationalFunctionSpace<C, A : Ring<C>> (
denominator * other.denominator
)
/**
* Check if the instant is zero rational function.
*/
public override fun RationalFunction<C>.isZero(): Boolean = numerator.isZero()
/**
* Check if the instant is unit rational function.
*/
public override fun RationalFunction<C>.isOne(): Boolean = numerator.equalsTo(denominator)
/**
* Check if the instant is minus unit rational function.
*/
public override fun RationalFunction<C>.isMinusOne(): Boolean = (numerator + denominator).isZero()
/**
* Instance of zero rational function (zero of the rational functions ring).
*/

View File

@ -1,3 +1,8 @@
/*
* 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.operations.*
@ -30,7 +35,7 @@ import kotlin.contracts.*
//fun <C, A: Ring<C>> power(arg: Variable, pow: UInt): LabeledPolynomial<C> =
// if (pow == 0U) one
// else LabeledPolynomial<C>(mapOf(
// mapOf(arg to pow) to ring.one
// mapOf(arg to pow) to constantOne
// ))
//
//// endregion

View File

@ -0,0 +1,130 @@
package math.polynomials
import math.ringsAndFields.*
import space.kscience.kmath.functions.LabeledRationalFunction
fun <T: Ring<T>> T.toLabeledRationalFunction() = LabeledRationalFunction(this.toLabeledPolynomial())
// region Operator extensions
// region Field case
fun <T: Field<T>> LabeledRationalFunction<T>.reduced(): LabeledRationalFunction<T> {
val greatestCommonDivider = polynomialGCD(numerator, denominator)
return LabeledRationalFunction(
numerator / greatestCommonDivider,
denominator / greatestCommonDivider
)
}
// endregion
// region Constants
operator fun <T: Ring<T>> T.plus(other: LabeledRationalFunction<T>) = other + this
operator fun <T: Ring<T>> Integer.plus(other: LabeledRationalFunction<T>) = other + this
operator fun <T: Ring<T>> Int.plus(other: LabeledRationalFunction<T>) = other + this
operator fun <T: Ring<T>> Long.plus(other: LabeledRationalFunction<T>) = other + this
operator fun <T: Ring<T>> T.minus(other: LabeledRationalFunction<T>) = -other + this
operator fun <T: Ring<T>> Integer.minus(other: LabeledRationalFunction<T>) = -other + this
operator fun <T: Ring<T>> Int.minus(other: LabeledRationalFunction<T>) = -other + this
operator fun <T: Ring<T>> Long.minus(other: LabeledRationalFunction<T>) = -other + this
operator fun <T: Ring<T>> T.times(other: LabeledRationalFunction<T>) = other * this
operator fun <T: Ring<T>> Integer.times(other: LabeledRationalFunction<T>) = other * this
operator fun <T: Ring<T>> Int.times(other: LabeledRationalFunction<T>) = other * this
operator fun <T: Ring<T>> Long.times(other: LabeledRationalFunction<T>) = other * this
// endregion
// region Polynomials
operator fun <T: Ring<T>> LabeledRationalFunction<T>.plus(other: UnivariatePolynomial<T>) =
LabeledRationalFunction(
numerator + denominator * other.toLabeledPolynomial(),
denominator
)
operator fun <T: Ring<T>> LabeledRationalFunction<T>.plus(other: UnivariateRationalFunction<T>) =
LabeledRationalFunction(
numerator * other.denominator.toLabeledPolynomial() + denominator * other.numerator.toLabeledPolynomial(),
denominator * other.denominator.toLabeledPolynomial()
)
operator fun <T: Ring<T>> LabeledRationalFunction<T>.plus(other: Polynomial<T>) =
LabeledRationalFunction(
numerator + denominator * other.toLabeledPolynomial(),
denominator
)
operator fun <T: Ring<T>> LabeledRationalFunction<T>.plus(other: NumberedRationalFunction<T>) =
LabeledRationalFunction(
numerator * other.denominator.toLabeledPolynomial() + denominator * other.numerator.toLabeledPolynomial(),
denominator * other.denominator.toLabeledPolynomial()
)
operator fun <T: Ring<T>> LabeledRationalFunction<T>.minus(other: UnivariatePolynomial<T>) =
LabeledRationalFunction(
numerator - denominator * other.toLabeledPolynomial(),
denominator
)
operator fun <T: Ring<T>> LabeledRationalFunction<T>.minus(other: UnivariateRationalFunction<T>) =
LabeledRationalFunction(
numerator * other.denominator.toLabeledPolynomial() - denominator * other.numerator.toLabeledPolynomial(),
denominator * other.denominator.toLabeledPolynomial()
)
operator fun <T: Ring<T>> LabeledRationalFunction<T>.minus(other: Polynomial<T>) =
LabeledRationalFunction(
numerator - denominator * other.toLabeledPolynomial(),
denominator
)
operator fun <T: Ring<T>> LabeledRationalFunction<T>.minus(other: NumberedRationalFunction<T>) =
LabeledRationalFunction(
numerator * other.denominator.toLabeledPolynomial() - denominator * other.numerator.toLabeledPolynomial(),
denominator * other.denominator.toLabeledPolynomial()
)
operator fun <T: Ring<T>> LabeledRationalFunction<T>.times(other: UnivariatePolynomial<T>) =
LabeledRationalFunction(
numerator * other.toLabeledPolynomial(),
denominator
)
operator fun <T: Ring<T>> LabeledRationalFunction<T>.times(other: UnivariateRationalFunction<T>) =
LabeledRationalFunction(
numerator * other.numerator.toLabeledPolynomial(),
denominator * other.denominator.toLabeledPolynomial()
)
operator fun <T: Ring<T>> LabeledRationalFunction<T>.times(other: Polynomial<T>) =
LabeledRationalFunction(
numerator * other.toLabeledPolynomial(),
denominator
)
operator fun <T: Ring<T>> LabeledRationalFunction<T>.times(other: NumberedRationalFunction<T>) =
LabeledRationalFunction(
numerator * other.numerator.toLabeledPolynomial(),
denominator * other.denominator.toLabeledPolynomial()
)
operator fun <T: Ring<T>> LabeledRationalFunction<T>.div(other: UnivariatePolynomial<T>) =
LabeledRationalFunction(
numerator,
denominator * other.toLabeledPolynomial()
)
operator fun <T: Ring<T>> LabeledRationalFunction<T>.div(other: UnivariateRationalFunction<T>) =
LabeledRationalFunction(
numerator * other.denominator.toLabeledPolynomial(),
denominator * other.numerator.toLabeledPolynomial()
)
operator fun <T: Ring<T>> LabeledRationalFunction<T>.div(other: Polynomial<T>) =
LabeledRationalFunction(
numerator,
denominator * other.toLabeledPolynomial()
)
operator fun <T: Ring<T>> LabeledRationalFunction<T>.div(other: NumberedRationalFunction<T>) =
LabeledRationalFunction(
numerator * other.denominator.toLabeledPolynomial(),
denominator * other.numerator.toLabeledPolynomial()
)
// endregion
// endregion

View File

@ -0,0 +1,23 @@
/*
* 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
//// region Operator extensions
//
//// region Field case
//
//fun <T: Field<T>> NumberedRationalFunction<T>.reduced(): NumberedRationalFunction<T> {
// val greatestCommonDivider = polynomialGCD(numerator, denominator)
// return NumberedRationalFunction(
// numerator / greatestCommonDivider,
// denominator / greatestCommonDivider
// )
//}
//
//// endregion
//
//// endregion

View File

@ -1,3 +1,8 @@
/*
* 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