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 242 additions and 1183 deletions
Showing only changes of commit 060f0ee35d - Show all commits

View File

@ -58,6 +58,8 @@ internal fun Map<Symbol, UInt>.cleanUp() = filterValues { it > 0U }
@Suppress("FunctionName", "NOTHING_TO_INLINE")
internal inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>, toCheckInput: Boolean = true) : LabeledPolynomial<C> = ring.LabeledPolynomial(coefs, toCheckInput)
@Suppress("FunctionName", "NOTHING_TO_INLINE")
internal inline fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>, toCheckInput: Boolean = true) : LabeledPolynomial<C> = ring.LabeledPolynomial(coefs, toCheckInput)
@Suppress("FunctionName")
internal fun <C, A: Ring<C>> A.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>, toCheckInput: Boolean = true) : LabeledPolynomial<C> {
if (!toCheckInput) return LabeledPolynomial<C>(coefs)
@ -70,13 +72,13 @@ internal fun <C, A: Ring<C>> A.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C
fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value
}
return LabeledPolynomial<C>(
fixedCoefs.filterValues { it != zero }
)
return LabeledPolynomial<C>(fixedCoefs)
}
@Suppress("FunctionName", "NOTHING_TO_INLINE")
internal inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>, toCheckInput: Boolean = true) : LabeledPolynomial<C> = ring.LabeledPolynomial(pairs, toCheckInput)
@Suppress("FunctionName", "NOTHING_TO_INLINE")
internal inline fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>, toCheckInput: Boolean = true) : LabeledPolynomial<C> = ring.LabeledPolynomial(pairs, toCheckInput)
@Suppress("FunctionName")
internal fun <C, A: Ring<C>> A.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>, toCheckInput: Boolean = true) : LabeledPolynomial<C> {
if (!toCheckInput) return LabeledPolynomial<C>(pairs.toMap())
@ -89,13 +91,13 @@ internal fun <C, A: Ring<C>> A.LabeledPolynomial(pairs: Collection<Pair<Map<Symb
fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value
}
return LabeledPolynomial<C>(
fixedCoefs.filterValues { it != zero }
)
return LabeledPolynomial<C>(fixedCoefs)
}
@Suppress("FunctionName", "NOTHING_TO_INLINE")
internal inline fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>, toCheckInput: Boolean = true) : LabeledPolynomial<C> = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput)
@Suppress("FunctionName", "NOTHING_TO_INLINE")
internal inline fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>, toCheckInput: Boolean = true) : LabeledPolynomial<C> = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput)
@Suppress("FunctionName")
internal fun <C, A: Ring<C>> A.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>, toCheckInput: Boolean = true) : LabeledPolynomial<C> {
if (!toCheckInput) return LabeledPolynomial<C>(pairs.toMap())
@ -108,25 +110,29 @@ internal fun <C, A: Ring<C>> A.LabeledPolynomial(vararg pairs: Pair<Map<Symbol,
fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value
}
return LabeledPolynomial<C>(
fixedCoefs.filterValues { it != zero }
)
return LabeledPolynomial<C>(fixedCoefs)
}
@Suppress("FunctionName")
public fun <C, A: Ring<C>> A.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(coefs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(coefs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(coefs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> A.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>) : LabeledPolynomial<C> = LabeledPolynomial(pairs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>) : LabeledPolynomial<C> = LabeledPolynomial(pairs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>) : LabeledPolynomial<C> = LabeledPolynomial(pairs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> A.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(*pairs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(*pairs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(*pairs, toCheckInput = true)
//context(A)
//public fun <C, A: Ring<C>> Symbol.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(mapOf(this to 1u) to one))
@ -196,19 +202,17 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
*/
public override operator fun LabeledPolynomial<C>.plus(other: Int): LabeledPolynomial<C> =
if (other == 0) this
else
LabeledPolynomial(
coefficients
.toMutableMap()
else with(coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to other.asConstant()))
else LabeledPolynomial<C>(
toMutableMap()
.apply {
val degs = emptyMap<Symbol, UInt>()
val result = getOrElse(degs) { constantZero } + other
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = getOrElse(degs) { constantZero } + other
}
)
}
/**
* Returns difference between the polynomial and the integer represented as polynomial.
*
@ -216,19 +220,17 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
*/
public override operator fun LabeledPolynomial<C>.minus(other: Int): LabeledPolynomial<C> =
if (other == 0) this
else
LabeledPolynomial(
coefficients
.toMutableMap()
else with(coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to (-other).asConstant()))
else LabeledPolynomial<C>(
toMutableMap()
.apply {
val degs = emptyMap<Symbol, UInt>()
val result = getOrElse(degs) { constantZero } - other
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = getOrElse(degs) { constantZero } - other
}
)
}
/**
* Returns product of the polynomial and the integer represented as polynomial.
*
@ -238,7 +240,8 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
if (other == 0) zero
else LabeledPolynomial(
coefficients
.applyAndRemoveZeros {
.toMutableMap()
.apply {
for (degs in keys) this[degs] = this[degs]!! * other
}
)
@ -250,19 +253,17 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
*/
public override operator fun Int.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
if (this == 0) other
else
LabeledPolynomial(
other.coefficients
.toMutableMap()
else with(other.coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this@plus.asConstant()))
else LabeledPolynomial<C>(
toMutableMap()
.apply {
val degs = emptyMap<Symbol, UInt>()
val result = this@plus + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = this@plus + getOrElse(degs) { constantZero }
}
)
}
/**
* Returns difference between the integer represented as polynomial and the polynomial.
*
@ -270,19 +271,17 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
*/
public override operator fun Int.minus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
if (this == 0) other
else
LabeledPolynomial(
other.coefficients
.toMutableMap()
else with(other.coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this@minus.asConstant()))
else LabeledPolynomial<C>(
toMutableMap()
.apply {
val degs = emptyMap<Symbol, UInt>()
val result = this@minus - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = this@minus - getOrElse(degs) { constantZero }
}
)
}
/**
* Returns product of the integer represented as polynomial and the polynomial.
*
@ -292,7 +291,8 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
if (this == 0) zero
else LabeledPolynomial(
other.coefficients
.applyAndRemoveZeros {
.toMutableMap()
.apply {
for (degs in keys) this[degs] = this@times * this[degs]!!
}
)
@ -303,46 +303,32 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
public override fun number(value: Int): LabeledPolynomial<C> = number(constantNumber(value))
public override operator fun C.plus(other: Symbol): LabeledPolynomial<C> =
if (isZero()) LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to constantOne,
))
else LabeledPolynomial<C>(mapOf(
LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to constantOne,
emptyMap<Symbol, UInt>() to this@plus,
))
public override operator fun C.minus(other: Symbol): LabeledPolynomial<C> =
if (isZero()) LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to -constantOne,
))
else LabeledPolynomial<C>(mapOf(
LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to -constantOne,
emptyMap<Symbol, UInt>() to this@minus,
))
public override operator fun C.times(other: Symbol): LabeledPolynomial<C> =
if (isZero()) zero
else LabeledPolynomial<C>(mapOf(
LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to this@times,
))
public override operator fun Symbol.plus(other: C): LabeledPolynomial<C> =
if (other.isZero()) LabeledPolynomial<C>(mapOf(
mapOf(this@plus to 1U) to constantOne,
))
else LabeledPolynomial<C>(mapOf(
LabeledPolynomial<C>(mapOf(
mapOf(this@plus to 1U) to constantOne,
emptyMap<Symbol, UInt>() to other,
))
public override operator fun Symbol.minus(other: C): LabeledPolynomial<C> =
if (other.isZero()) LabeledPolynomial<C>(mapOf(
mapOf(this@minus to 1U) to -constantOne,
))
else LabeledPolynomial<C>(mapOf(
LabeledPolynomial<C>(mapOf(
mapOf(this@minus to 1U) to -constantOne,
emptyMap<Symbol, UInt>() to other,
))
public override operator fun Symbol.times(other: C): LabeledPolynomial<C> =
if (other.isZero()) zero
else LabeledPolynomial<C>(mapOf(
LabeledPolynomial<C>(mapOf(
mapOf(this@times to 1U) to other,
))
@ -350,18 +336,14 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns sum of the constant represented as polynomial and the polynomial.
*/
override operator fun C.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
if (this.isZero()) other
else with(other.coefficients) {
with(other.coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this@plus))
else LabeledPolynomial<C>(
toMutableMap()
.apply {
val degs = emptyMap<Symbol, UInt>()
val result = this@plus + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = this@plus + getOrElse(degs) { constantZero }
}
)
}
@ -369,8 +351,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns difference between the constant represented as polynomial and the polynomial.
*/
override operator fun C.minus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
if (this.isZero()) other
else with(other.coefficients) {
with(other.coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this@minus))
else LabeledPolynomial<C>(
toMutableMap()
@ -379,10 +360,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
val degs = emptyMap<Symbol, UInt>()
val result = this@minus - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = this@minus - getOrElse(degs) { constantZero }
}
)
}
@ -390,10 +368,10 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns product of the constant represented as polynomial and the polynomial.
*/
override operator fun C.times(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
if (this.isZero()) zero
else LabeledPolynomial<C>(
LabeledPolynomial<C>(
other.coefficients
.applyAndRemoveZeros {
.toMutableMap()
.apply {
for (degs in keys) this[degs] = this@times * this[degs]!!
}
)
@ -402,18 +380,14 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns sum of the constant represented as polynomial and the polynomial.
*/
override operator fun LabeledPolynomial<C>.plus(other: C): LabeledPolynomial<C> =
if (other.isZero()) this
else with(coefficients) {
with(coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to other))
else LabeledPolynomial<C>(
toMutableMap()
.apply {
val degs = emptyMap<Symbol, UInt>()
val result = getOrElse(degs) { constantZero } + other
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = getOrElse(degs) { constantZero } + other
}
)
}
@ -421,8 +395,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns difference between the constant represented as polynomial and the polynomial.
*/
override operator fun LabeledPolynomial<C>.minus(other: C): LabeledPolynomial<C> =
if (other.isZero()) this
else with(coefficients) {
with(coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to other))
else LabeledPolynomial<C>(
toMutableMap()
@ -431,10 +404,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
val degs = emptyMap<Symbol, UInt>()
val result = getOrElse(degs) { constantZero } - other
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = getOrElse(degs) { constantZero } - other
}
)
}
@ -442,10 +412,10 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns product of the constant represented as polynomial and the polynomial.
*/
override operator fun LabeledPolynomial<C>.times(other: C): LabeledPolynomial<C> =
if (other.isZero()) zero
else LabeledPolynomial<C>(
LabeledPolynomial<C>(
coefficients
.applyAndRemoveZeros {
.toMutableMap()
.apply {
for (degs in keys) this[degs] = this[degs]!! * other
}
)
@ -454,8 +424,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Converts the constant [value] to polynomial.
*/
public override fun number(value: C): LabeledPolynomial<C> =
if (value == 0) zero
else LabeledPolynomial(mapOf(emptyMap<Symbol, UInt>() to value))
LabeledPolynomial(mapOf(emptyMap<Symbol, UInt>() to value))
public override operator fun Symbol.unaryPlus(): LabeledPolynomial<C> =
LabeledPolynomial<C>(mapOf(
@ -495,10 +464,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = mapOf(this@plus to 1U)
val result = constantOne + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = constantOne + getOrElse(degs) { constantZero }
}
)
}
@ -512,10 +478,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
val degs = mapOf(this@minus to 1U)
val result = constantOne - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = constantOne - getOrElse(degs) { constantZero }
}
)
}
@ -533,10 +496,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = mapOf(other to 1U)
val result = constantOne + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = constantOne + getOrElse(degs) { constantZero }
}
)
}
@ -548,10 +508,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = mapOf(other to 1U)
val result = constantOne - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = constantOne - getOrElse(degs) { constantZero }
}
)
}
@ -573,7 +530,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
*/
override operator fun LabeledPolynomial<C>.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
LabeledPolynomial<C>(
buildCoefficients(coefficients.size + other.coefficients.size) {
buildMap(coefficients.size + other.coefficients.size) {
other.coefficients.mapValuesTo(this) { it.value }
other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value }
}
@ -583,7 +540,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
*/
override operator fun LabeledPolynomial<C>.minus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
LabeledPolynomial<C>(
buildCoefficients(coefficients.size + other.coefficients.size) {
buildMap(coefficients.size + other.coefficients.size) {
other.coefficients.mapValuesTo(this) { it.value }
other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value }
}
@ -592,11 +549,8 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns product of the polynomials.
*/
override operator fun LabeledPolynomial<C>.times(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
when {
isZero() -> zero
other.isZero() -> zero
else -> LabeledPolynomial<C>(
buildCoefficients(coefficients.size * other.coefficients.size) {
LabeledPolynomial<C>(
buildMap(coefficients.size * other.coefficients.size) {
for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) {
val degs = degs1.toMutableMap()
degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg }
@ -605,7 +559,6 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
}
}
)
}
/**
* Instance of zero polynomial (zero of the polynomial ring).
@ -616,22 +569,12 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
*/
override val one: LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to constantOne))
/**
* Checks equality of the polynomials.
*/
override infix fun LabeledPolynomial<C>.equalsTo(other: LabeledPolynomial<C>): Boolean =
when {
this === other -> true
else -> coefficients.size == other.coefficients.size &&
coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } }
}
/**
* Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1.
*/
override val LabeledPolynomial<C>.degree: Int
get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.values.sum().toInt() } ?: -1
get() = coefficients.entries.maxOfOrNull { (degs, c) -> degs.values.sum().toInt() } ?: -1
/**
* Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents
* in which they are appeared in the polynomial.
@ -642,8 +585,8 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
public override val LabeledPolynomial<C>.degrees: Map<Symbol, UInt>
get() =
buildMap {
coefficients.entries.forEach { (degs, c) ->
if (c.isNotZero()) degs.mapValuesTo(this) { (variable, deg) ->
coefficients.entries.forEach { (degs, _) ->
degs.mapValuesTo(this) { (variable, deg) ->
max(getOrElse(variable) { 0u }, deg)
}
}
@ -652,55 +595,25 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Counts degree of the polynomial by the specified [variable].
*/
public override fun LabeledPolynomial<C>.degreeBy(variable: Symbol): UInt =
coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.getOrElse(variable) { 0u } } ?: 0u
coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u
/**
* Counts degree of the polynomial by the specified [variables].
*/
public override fun LabeledPolynomial<C>.degreeBy(variables: Collection<Symbol>): UInt =
coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.filterKeys { it in variables }.values.sum() } ?: 0u
coefficients.entries.maxOfOrNull { (degs, _) -> degs.filterKeys { it in variables }.values.sum() } ?: 0u
/**
* Set of all variables that appear in the polynomial in positive exponents.
*/
public override val LabeledPolynomial<C>.variables: Set<Symbol>
get() =
buildSet {
coefficients.entries.forEach { (degs, c) -> if (c.isNotZero()) addAll(degs.keys) }
coefficients.entries.forEach { (degs, _) -> addAll(degs.keys) }
}
/**
* Count of all variables that appear in the polynomial in positive exponents.
*/
public override val LabeledPolynomial<C>.countOfVariables: Int get() = variables.size
/**
* Checks if the instant is constant polynomial (of degree no more than 0) over considered ring.
*/
override fun LabeledPolynomial<C>.isConstant(): Boolean =
coefficients.all { (degs, c) -> degs.isEmpty() || c.isZero() }
/**
* Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring.
*/
override fun LabeledPolynomial<C>.isNonZeroConstant(): Boolean =
with(coefficients) {
var foundAbsoluteTermAndItIsNotZero = false
for ((degs, c) in this) {
if (degs.isNotEmpty()) if (c.isNotZero()) return@with false
else {
if (c.isZero()) return@with false
else foundAbsoluteTermAndItIsNotZero = true
}
}
foundAbsoluteTermAndItIsNotZero
}
/**
* If polynomial is a constant polynomial represents and returns it as constant.
* Otherwise, (when the polynomial is not constant polynomial) returns `null`.
*/
override fun LabeledPolynomial<C>.asConstantOrNull(): C? =
with(coefficients) {
if(isConstant()) getOrElse(emptyMap()) { constantZero }
else null
}
// @Suppress("NOTHING_TO_INLINE")
// public inline fun LabeledPolynomial<C>.substitute(argument: Map<Symbol, C>): LabeledPolynomial<C> = this.substitute(ring, argument)
// @Suppress("NOTHING_TO_INLINE")
@ -719,33 +632,4 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
// @Suppress("NOTHING_TO_INLINE")
// @JvmName("invokePolynomial")
// public inline operator fun LabeledPolynomial<C>.invoke(argument: Map<Symbol, LabeledPolynomial<C>>): LabeledPolynomial<C> = this.substitute(ring, argument)
// TODO: Move to other internal utilities with context receiver
@JvmName("applyAndRemoveZerosInternal")
internal fun MutableMap<Map<Symbol, UInt>, C>.applyAndRemoveZeros(block: MutableMap<Map<Symbol, UInt>, C>.() -> Unit) : MutableMap<Map<Symbol, UInt>, C> {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
for ((degs, c) in this) if (c.isZero()) this.remove(degs)
return this
}
internal fun Map<Map<Symbol, UInt>, C>.applyAndRemoveZeros(block: MutableMap<Map<Symbol, UInt>, C>.() -> Unit) : Map<Map<Symbol, UInt>, C> =
toMutableMap().applyAndRemoveZeros(block)
@OptIn(ExperimentalTypeInference::class)
internal inline fun buildCoefficients(@BuilderInference builderAction: MutableMap<Map<Symbol, UInt>, C>.() -> Unit): Map<Map<Symbol, UInt>, C> {
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
return buildMap {
builderAction()
for ((degs, c) in this) if (c.isZero()) this.remove(degs)
}
}
@OptIn(ExperimentalTypeInference::class)
internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableMap<Map<Symbol, UInt>, C>.() -> Unit): Map<Map<Symbol, UInt>, C> {
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
return buildMap(capacity) {
builderAction()
for ((degs, c) in this) if (c.isZero()) this.remove(degs)
}
}
}

View File

@ -19,45 +19,35 @@ public class LabeledRationalFunction<C>(
// Waiting for context receivers :( TODO: Replace with context receivers when they will be available
@Suppress("FunctionName")
internal fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledRationalFunction(numerator: LabeledPolynomial<C>, denominator: LabeledPolynomial<C>): LabeledRationalFunction<C> =
if (denominator.isZero()) throw ArithmeticException("/ by zero")
else LabeledRationalFunction<C>(numerator, denominator)
@Suppress("FunctionName")
internal fun <C, A: Ring<C>> A.LabeledRationalFunction(numerator: LabeledPolynomial<C>, denominator: LabeledPolynomial<C>): LabeledRationalFunction<C> =
if (denominator.coefficients.values.all { it == zero }) throw ArithmeticException("/ by zero")
else LabeledRationalFunction<C>(numerator, denominator)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>, denominatorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> =
if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero")
else LabeledRationalFunction<C>(
LabeledPolynomial(numeratorCoefficients),
LabeledPolynomial(denominatorCoefficients)
LabeledRationalFunction<C>(
LabeledPolynomial(numeratorCoefficients, toCheckInput = true),
LabeledPolynomial(denominatorCoefficients, toCheckInput = true)
)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> A.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>, denominatorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> =
if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero")
else LabeledRationalFunction<C>(
LabeledPolynomial(numeratorCoefficients),
LabeledPolynomial(denominatorCoefficients)
LabeledRationalFunction<C>(
LabeledPolynomial(numeratorCoefficients, toCheckInput = true),
LabeledPolynomial(denominatorCoefficients, toCheckInput = true)
)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledRationalFunction(numerator: LabeledPolynomial<C>): LabeledRationalFunction<C> =
LabeledRationalFunction<C>(numerator, polynomialOne)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> A.LabeledRationalFunction(numerator: LabeledPolynomial<C>): LabeledRationalFunction<C> =
LabeledRationalFunction<C>(numerator, LabeledPolynomial(mapOf(emptyMap<Symbol, UInt>() to one)))
LabeledRationalFunction<C>(numerator, LabeledPolynomial(mapOf(emptyMap<Symbol, UInt>() to one), toCheckInput = false))
@Suppress("FunctionName")
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> =
LabeledRationalFunction<C>(
LabeledPolynomial(numeratorCoefficients),
LabeledPolynomial(numeratorCoefficients, toCheckInput = true),
polynomialOne
)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> A.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> =
LabeledRationalFunction<C>(
LabeledPolynomial(numeratorCoefficients),
LabeledPolynomial(mapOf(emptyMap<Symbol, UInt>() to one))
LabeledPolynomial(numeratorCoefficients, toCheckInput = true),
LabeledPolynomial(mapOf(emptyMap<Symbol, UInt>() to one), toCheckInput = false)
)
public class LabeledRationalFunctionSpace<C, A: Ring<C>>(
@ -82,38 +72,16 @@ public class LabeledRationalFunctionSpace<C, A: Ring<C>>(
numerator: LabeledPolynomial<C>,
denominator: LabeledPolynomial<C>
): LabeledRationalFunction<C> =
LabeledRationalFunction(numerator, denominator)
LabeledRationalFunction<C>(numerator, denominator)
/**
* Instance of zero rational function (zero of the rational functions ring).
*/
public override val zero: LabeledRationalFunction<C> = LabeledRationalFunction(polynomialZero, polynomialOne)
public override val zero: LabeledRationalFunction<C> = LabeledRationalFunction<C>(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.
*/
public override infix fun LabeledRationalFunction<C>.equalsTo(other: LabeledRationalFunction<C>): Boolean {
if (this === other) return true
if (numerator.isZero() != 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
}
public override val one: LabeledRationalFunction<C> = LabeledRationalFunction<C>(polynomialOne, polynomialOne)
// TODO: Разобрать

View File

@ -91,13 +91,9 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
.toMutableList()
.apply {
val result = getOrElse(0) { constantZero } + other
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
if(size == 0) add(result)
else this[0] = result
}
)
/**
@ -113,13 +109,9 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
.toMutableList()
.apply {
val result = getOrElse(0) { constantZero } - other
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
if(size == 0) add(result)
else this[0] = result
}
)
/**
@ -131,7 +123,8 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
if (other == 0) zero
else ListPolynomial(
coefficients
.applyAndRemoveZeros {
.toMutableList()
.apply {
for (deg in indices) this[deg] = this[deg] * other
}
)
@ -149,13 +142,9 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
.toMutableList()
.apply {
val result = this@plus + getOrElse(0) { constantZero }
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
if(size == 0) add(result)
else this[0] = result
}
)
/**
@ -173,13 +162,9 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
forEachIndexed { index, c -> if (index != 0) this[index] = -c }
val result = this@minus - getOrElse(0) { constantZero }
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
if(size == 0) add(result)
else this[0] = result
}
)
/**
@ -191,7 +176,8 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
if (this == 0) zero
else ListPolynomial(
other.coefficients
.applyAndRemoveZeros {
.toMutableList()
.apply {
for (deg in indices) this[deg] = this@times * this[deg]
}
)
@ -205,20 +191,15 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
* Returns sum of the constant represented as polynomial and the polynomial.
*/
public override operator fun C.plus(other: ListPolynomial<C>): ListPolynomial<C> =
if (this.isZero()) other
else with(other.coefficients) {
with(other.coefficients) {
if (isEmpty()) ListPolynomial(listOf(this@plus))
else ListPolynomial(
toMutableList()
.apply {
val result = if (size == 0) this@plus else this@plus + get(0)
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
if(size == 0) add(result)
else this[0] = result
}
)
}
@ -226,8 +207,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
* Returns difference between the constant represented as polynomial and the polynomial.
*/
public override operator fun C.minus(other: ListPolynomial<C>): ListPolynomial<C> =
if (this.isZero()) other
else with(other.coefficients) {
with(other.coefficients) {
if (isEmpty()) ListPolynomial(listOf(this@minus))
else ListPolynomial(
toMutableList()
@ -235,13 +215,9 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
forEachIndexed { index, c -> if (index != 0) this[index] = -c }
val result = if (size == 0) this@minus else this@minus - get(0)
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
if(size == 0) add(result)
else this[0] = result
}
)
}
@ -249,10 +225,10 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
* Returns product of the constant represented as polynomial and the polynomial.
*/
public override operator fun C.times(other: ListPolynomial<C>): ListPolynomial<C> =
if (this.isZero()) other
else ListPolynomial(
ListPolynomial(
other.coefficients
.applyAndRemoveZeros {
.toMutableList()
.apply {
for (deg in indices) this[deg] = this@times * this[deg]
}
)
@ -261,20 +237,15 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
* Returns sum of the constant represented as polynomial and the polynomial.
*/
public override operator fun ListPolynomial<C>.plus(other: C): ListPolynomial<C> =
if (other.isZero()) this
else with(coefficients) {
with(coefficients) {
if (isEmpty()) ListPolynomial(listOf(other))
else ListPolynomial(
toMutableList()
.apply {
val result = if (size == 0) other else get(0) + other
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
if(size == 0) add(result)
else this[0] = result
}
)
}
@ -282,20 +253,15 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
* Returns difference between the constant represented as polynomial and the polynomial.
*/
public override operator fun ListPolynomial<C>.minus(other: C): ListPolynomial<C> =
if (other.isZero()) this
else with(coefficients) {
with(coefficients) {
if (isEmpty()) ListPolynomial(listOf(-other))
else ListPolynomial(
toMutableList()
.apply {
val result = if (size == 0) other else get(0) - other
val isResultZero = result.isZero()
when {
size == 0 && !isResultZero -> add(result)
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
if(size == 0) add(result)
else this[0] = result
}
)
}
@ -303,10 +269,10 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
* Returns product of the constant represented as polynomial and the polynomial.
*/
public override operator fun ListPolynomial<C>.times(other: C): ListPolynomial<C> =
if (other.isZero()) this
else ListPolynomial(
ListPolynomial(
coefficients
.applyAndRemoveZeros {
.toMutableList()
.apply {
for (deg in indices) this[deg] = this[deg] * other
}
)
@ -314,9 +280,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
/**
* Converts the constant [value] to polynomial.
*/
public override fun number(value: C): ListPolynomial<C> =
if (value.isZero()) zero
else ListPolynomial(value)
public override fun number(value: C): ListPolynomial<C> = ListPolynomial(value)
/**
* Returns negation of the polynomial.
@ -330,7 +294,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
val thisDegree = degree
val otherDegree = other.degree
return ListPolynomial(
Coefficients(max(thisDegree, otherDegree) + 1) {
List(max(thisDegree, otherDegree) + 1) {
when {
it > thisDegree -> other.coefficients[it]
it > otherDegree -> coefficients[it]
@ -346,7 +310,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
val thisDegree = degree
val otherDegree = other.degree
return ListPolynomial(
Coefficients(max(thisDegree, otherDegree) + 1) {
List(max(thisDegree, otherDegree) + 1) {
when {
it > thisDegree -> -other.coefficients[it]
it > otherDegree -> coefficients[it]
@ -361,38 +325,14 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
public override operator fun ListPolynomial<C>.times(other: ListPolynomial<C>): ListPolynomial<C> {
val thisDegree = degree
val otherDegree = other.degree
return when {
thisDegree == -1 -> zero
otherDegree == -1 -> zero
else ->
ListPolynomial(
Coefficients(thisDegree + otherDegree + 1) { d ->
return ListPolynomial(
List(thisDegree + otherDegree + 1) { d ->
(max(0, d - otherDegree)..min(thisDegree, d))
.map { coefficients[it] * other.coefficients[d - it] }
.reduce { acc, rational -> acc + rational }
}
)
}
}
/**
* Check if the instant is zero polynomial.
*/
public override fun ListPolynomial<C>.isZero(): Boolean = coefficients.all { it.isZero() }
/**
* Check if the instant is unit polynomial.
*/
public override fun ListPolynomial<C>.isOne(): Boolean =
with(coefficients) {
isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isOne() else c.isZero() }
}
/**
* Check if the instant is minus unit polynomial.
*/
public override fun ListPolynomial<C>.isMinusOne(): Boolean =
with(coefficients) {
isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() }
}
/**
* Instance of zero polynomial (zero of the polynomial ring).
@ -403,34 +343,11 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
*/
override val one: ListPolynomial<C> = ListPolynomial(listOf(constantOne))
/**
* Checks equality of the polynomials.
*/
public override infix fun ListPolynomial<C>.equalsTo(other: ListPolynomial<C>): Boolean =
when {
this === other -> true
this.degree == other.degree -> (0..degree).all { coefficients[it] == other.coefficients[it] }
else -> false
}
/**
* Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1.
*/
public override val ListPolynomial<C>.degree: Int get() = coefficients.indexOfLast { it != constantZero }
/**
* If polynomial is a constant polynomial represents and returns it as constant.
* Otherwise, (when the polynomial is not constant polynomial) returns `null`.
*/
public override fun ListPolynomial<C>.asConstantOrNull(): C? =
with(coefficients) {
when {
isEmpty() -> constantZero
withIndex().all { (index, c) -> index == 0 || c.isZero() } -> first()
else -> null
}
}
public override val ListPolynomial<C>.degree: Int get() = coefficients.lastIndex
@Suppress("NOTHING_TO_INLINE")
public inline fun ListPolynomial<C>.substitute(argument: C): C = this.substitute(ring, argument)
@ -451,44 +368,6 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
public inline operator fun ListPolynomial<C>.invoke(argument: C): C = this.substitute(ring, argument)
@Suppress("NOTHING_TO_INLINE")
public inline operator fun ListPolynomial<C>.invoke(argument: ListPolynomial<C>): ListPolynomial<C> = this.substitute(ring, argument)
// TODO: Move to other internal utilities with context receiver
@JvmName("applyAndRemoveZerosInternal")
internal inline fun MutableList<C>.applyAndRemoveZeros(block: MutableList<C>.() -> Unit) : MutableList<C> {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex)
return this
}
internal inline fun List<C>.applyAndRemoveZeros(block: MutableList<C>.() -> Unit) : List<C> =
toMutableList().applyAndRemoveZeros(block)
@Suppress("FunctionName")
internal inline fun MutableCoefficients(size: Int, init: (index: Int) -> C): MutableList<C> {
val list = ArrayList<C>(size)
repeat(size) { index -> list.add(init(index)) }
with(list) { while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) }
return list
}
@Suppress("FunctionName")
internal inline fun Coefficients(size: Int, init: (index: Int) -> C): List<C> = MutableCoefficients(size, init)
@OptIn(ExperimentalTypeInference::class)
internal inline fun buildCoefficients(@BuilderInference builderAction: MutableList<C>.() -> Unit): List<C> {
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
return buildList {
builderAction()
while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex)
}
}
@OptIn(ExperimentalTypeInference::class)
internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableList<C>.() -> Unit): List<C> {
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
return buildList(capacity) {
builderAction()
while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex)
}
}
}
/**

View File

@ -8,7 +8,7 @@ package space.kscience.kmath.functions
import space.kscience.kmath.operations.Ring
public data class ListRationalFunction<C> internal constructor (
public data class ListRationalFunction<C>(
public override val numerator: ListPolynomial<C>,
public override val denominator: ListPolynomial<C>
) : RationalFunction<C, ListPolynomial<C>> {
@ -17,25 +17,15 @@ public data class ListRationalFunction<C> internal constructor (
// Waiting for context receivers :( TODO: Replace with context receivers when they will be available
@Suppress("FunctionName")
internal fun <C, A: Ring<C>> ListRationalFunctionSpace<C, A>.ListRationalFunction(numerator: ListPolynomial<C>, denominator: ListPolynomial<C>): ListRationalFunction<C> =
if (denominator.isZero()) throw ArithmeticException("/ by zero")
else ListRationalFunction<C>(numerator, denominator)
@Suppress("FunctionName")
internal fun <C, A: Ring<C>> A.ListRationalFunction(numerator: ListPolynomial<C>, denominator: ListPolynomial<C>): ListRationalFunction<C> =
if (denominator.coefficients.all { it == zero }) throw ArithmeticException("/ by zero")
else ListRationalFunction<C>(numerator, denominator)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> ListRationalFunctionSpace<C, A>.ListRationalFunction(numeratorCoefficients: List<C>, denominatorCoefficients: List<C>, reverse: Boolean = false): ListRationalFunction<C> =
if (denominatorCoefficients.all { it == zero }) throw ArithmeticException("/ by zero")
else ListRationalFunction<C>(
ListRationalFunction<C>(
ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ),
ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } )
)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> A.ListRationalFunction(numeratorCoefficients: List<C>, denominatorCoefficients: List<C>, reverse: Boolean = false): ListRationalFunction<C> =
if (denominatorCoefficients.all { it == zero }) throw ArithmeticException("/ by zero")
else ListRationalFunction<C>(
ListRationalFunction<C>(
ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ),
ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } )
)

View File

@ -58,6 +58,8 @@ internal fun List<UInt>.cleanUp() = subList(0, indexOfLast { it != 0U } + 1)
@Suppress("FunctionName", "NOTHING_TO_INLINE")
internal inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(coefs: Map<List<UInt>, C>, toCheckInput: Boolean = true) : NumberedPolynomial<C> = ring.NumberedPolynomial(coefs, toCheckInput)
@Suppress("FunctionName", "NOTHING_TO_INLINE")
internal inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(coefs: Map<List<UInt>, C>, toCheckInput: Boolean = true) : NumberedPolynomial<C> = ring.NumberedPolynomial(coefs, toCheckInput)
@Suppress("FunctionName")
internal fun <C, A: Ring<C>> A.NumberedPolynomial(coefs: Map<List<UInt>, C>, toCheckInput: Boolean = true) : NumberedPolynomial<C> {
if (!toCheckInput) return NumberedPolynomial<C>(coefs)
@ -70,13 +72,13 @@ internal fun <C, A: Ring<C>> A.NumberedPolynomial(coefs: Map<List<UInt>, C>, toC
fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value
}
return NumberedPolynomial<C>(
fixedCoefs.filterValues { it != zero }
)
return NumberedPolynomial<C>(fixedCoefs)
}
@Suppress("FunctionName", "NOTHING_TO_INLINE")
internal inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>, toCheckInput: Boolean = true) : NumberedPolynomial<C> = ring.NumberedPolynomial(pairs, toCheckInput)
@Suppress("FunctionName", "NOTHING_TO_INLINE")
internal inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>, toCheckInput: Boolean = true) : NumberedPolynomial<C> = ring.NumberedPolynomial(pairs, toCheckInput)
@Suppress("FunctionName")
internal fun <C, A: Ring<C>> A.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>, toCheckInput: Boolean = true) : NumberedPolynomial<C> {
if (!toCheckInput) return NumberedPolynomial<C>(pairs.toMap())
@ -89,13 +91,13 @@ internal fun <C, A: Ring<C>> A.NumberedPolynomial(pairs: Collection<Pair<List<UI
fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value
}
return NumberedPolynomial<C>(
fixedCoefs.filterValues { it != zero }
)
return NumberedPolynomial<C>(fixedCoefs)
}
@Suppress("FunctionName", "NOTHING_TO_INLINE")
internal inline fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>, toCheckInput: Boolean = true) : NumberedPolynomial<C> = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput)
@Suppress("FunctionName", "NOTHING_TO_INLINE")
internal inline fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>, toCheckInput: Boolean = true) : NumberedPolynomial<C> = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput)
@Suppress("FunctionName")
internal fun <C, A: Ring<C>> A.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>, toCheckInput: Boolean = true) : NumberedPolynomial<C> {
if (!toCheckInput) return NumberedPolynomial<C>(pairs.toMap())
@ -108,25 +110,29 @@ internal fun <C, A: Ring<C>> A.NumberedPolynomial(vararg pairs: Pair<List<UInt>,
fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value
}
return NumberedPolynomial<C>(
fixedCoefs.filterValues { it != zero }
)
return NumberedPolynomial<C>(fixedCoefs)
}
@Suppress("FunctionName")
public fun <C, A: Ring<C>> A.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> A.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial(pairs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial(pairs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial(pairs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> A.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(*pairs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(*pairs, toCheckInput = true)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(*pairs, toCheckInput = true)
//context(A)
//public fun <C, A: Ring<C>> Symbol.asNumberedPolynomial() : NumberedPolynomial<C> = NumberedPolynomial<C>(mapOf(mapOf(this to 1u) to one))
@ -211,10 +217,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyList<UInt>()
val result = getOrElse(degs) { constantZero } + other
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = getOrElse(degs) { constantZero } + other
}
)
/**
@ -231,10 +234,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyList<UInt>()
val result = getOrElse(degs) { constantZero } - other
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = getOrElse(degs) { constantZero } - other
}
)
/**
@ -246,7 +246,8 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
if (other == 0) zero
else NumberedPolynomial<C>(
coefficients
.applyAndRemoveZeros {
.toMutableMap()
.apply {
for (degs in keys) this[degs] = this[degs]!! * other
}
)
@ -265,10 +266,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyList<UInt>()
val result = this@plus + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = this@plus + getOrElse(degs) { constantZero }
}
)
/**
@ -285,10 +283,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
.apply {
val degs = emptyList<UInt>()
val result = this@minus - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = this@minus - getOrElse(degs) { constantZero }
}
)
/**
@ -300,7 +295,8 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
if (this == 0) zero
else NumberedPolynomial(
other.coefficients
.applyAndRemoveZeros {
.toMutableMap()
.apply {
for (degs in keys) this[degs] = this@times * this[degs]!!
}
)
@ -314,18 +310,14 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
* Returns sum of the constant represented as polynomial and the polynomial.
*/
override operator fun C.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
if (this.isZero()) other
else with(other.coefficients) {
with(other.coefficients) {
if (isEmpty()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to this@plus))
else NumberedPolynomial<C>(
toMutableMap()
.apply {
val degs = emptyList<UInt>()
val result = this@plus + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = this@plus + getOrElse(degs) { constantZero }
}
)
}
@ -333,8 +325,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
* Returns difference between the constant represented as polynomial and the polynomial.
*/
override operator fun C.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
if (this.isZero()) -other
else with(other.coefficients) {
with(other.coefficients) {
if (isEmpty()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to this@minus))
else NumberedPolynomial<C>(
toMutableMap()
@ -343,10 +334,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
val degs = emptyList<UInt>()
val result = this@minus - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = this@minus - getOrElse(degs) { constantZero }
}
)
}
@ -354,10 +342,10 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
* Returns product of the constant represented as polynomial and the polynomial.
*/
override operator fun C.times(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
if (this.isZero()) zero
else NumberedPolynomial<C>(
NumberedPolynomial<C>(
other.coefficients
.applyAndRemoveZeros {
.toMutableMap()
.apply {
for (degs in keys) this[degs] = this@times * this[degs]!!
}
)
@ -366,18 +354,14 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
* Returns sum of the constant represented as polynomial and the polynomial.
*/
override operator fun NumberedPolynomial<C>.plus(other: C): NumberedPolynomial<C> =
if (other.isZero()) this
else with(coefficients) {
with(coefficients) {
if (isEmpty()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to other))
else NumberedPolynomial<C>(
toMutableMap()
.apply {
val degs = emptyList<UInt>()
val result = getOrElse(degs) { constantZero } + other
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = getOrElse(degs) { constantZero } + other
}
)
}
@ -385,18 +369,14 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
* Returns difference between the constant represented as polynomial and the polynomial.
*/
override operator fun NumberedPolynomial<C>.minus(other: C): NumberedPolynomial<C> =
if (other.isZero()) this
else with(coefficients) {
with(coefficients) {
if (isEmpty()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to other))
else NumberedPolynomial<C>(
toMutableMap()
.apply {
val degs = emptyList<UInt>()
val result = getOrElse(degs) { constantZero } - other
if (result.isZero()) remove(degs)
else this[degs] = result
this[degs] = getOrElse(degs) { constantZero } - other
}
)
}
@ -404,10 +384,10 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
* Returns product of the constant represented as polynomial and the polynomial.
*/
override operator fun NumberedPolynomial<C>.times(other: C): NumberedPolynomial<C> =
if (other.isZero()) zero
else NumberedPolynomial<C>(
NumberedPolynomial<C>(
coefficients
.applyAndRemoveZeros {
.toMutableMap()
.apply {
for (degs in keys) this[degs] = this[degs]!! * other
}
)
@ -416,8 +396,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
* Converts the constant [value] to polynomial.
*/
public override fun number(value: C): NumberedPolynomial<C> =
if (value == 0) zero
else NumberedPolynomial(mapOf(emptyList<UInt>() to value))
NumberedPolynomial(mapOf(emptyList<UInt>() to value))
/**
* Returns negation of the polynomial.
@ -431,7 +410,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
*/
override operator fun NumberedPolynomial<C>.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
NumberedPolynomial<C>(
buildCoefficients(coefficients.size + other.coefficients.size) {
buildMap(coefficients.size + other.coefficients.size) {
other.coefficients.mapValuesTo(this) { it.value }
other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value }
}
@ -441,7 +420,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
*/
override operator fun NumberedPolynomial<C>.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
NumberedPolynomial<C>(
buildCoefficients(coefficients.size + other.coefficients.size) {
buildMap(coefficients.size + other.coefficients.size) {
other.coefficients.mapValuesTo(this) { it.value }
other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value }
}
@ -450,12 +429,8 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
* Returns product of the polynomials.
*/
override operator fun NumberedPolynomial<C>.times(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
when {
isZero() -> zero
other.isZero() -> zero
else ->
NumberedPolynomial<C>(
buildCoefficients(coefficients.size * other.coefficients.size) {
buildMap(coefficients.size * other.coefficients.size) {
for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) {
val degs =
(0..max(degs1.lastIndex, degs2.lastIndex))
@ -465,42 +440,6 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
}
}
)
}
/**
* Check if the instant is zero polynomial.
*/
public override fun NumberedPolynomial<C>.isZero(): Boolean = coefficients.values.all { it.isZero() }
/**
* Check if the instant is unit polynomial.
*/
public override fun NumberedPolynomial<C>.isOne(): Boolean =
with(coefficients) {
var foundAbsoluteTermAndItIsOne = false
for ((degs, c) in this) {
if (degs.isNotEmpty()) if (c.isNotZero()) return@with false
else {
if (c.isNotOne()) return@with false
else foundAbsoluteTermAndItIsOne = true
}
}
foundAbsoluteTermAndItIsOne
}
/**
* Check if the instant is minus unit polynomial.
*/
public override fun NumberedPolynomial<C>.isMinusOne(): Boolean =
with(coefficients) {
var foundAbsoluteTermAndItIsMinusOne = false
for ((degs, c) in this) {
if (degs.isNotEmpty()) if (c.isNotZero()) return@with false
else {
if (c.isNotMinusOne()) return@with false
else foundAbsoluteTermAndItIsMinusOne = true
}
}
foundAbsoluteTermAndItIsMinusOne
}
/**
* Instance of zero polynomial (zero of the polynomial ring).
@ -516,28 +455,18 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
)
)
/**
* Checks equality of the polynomials.
*/
override infix fun NumberedPolynomial<C>.equalsTo(other: NumberedPolynomial<C>): Boolean =
when {
this === other -> true
else -> coefficients.size == other.coefficients.size &&
coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } }
}
/**
* Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable,
* the result is `-1`.
*/
public val NumberedPolynomial<C>.lastVariable: Int
get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.lastIndex } ?: -1
get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.lastIndex } ?: -1
/**
* Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1.
*/
override val NumberedPolynomial<C>.degree: Int
get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.sum().toInt() } ?: -1
get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.sum().toInt() } ?: -1
/**
* 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.
@ -548,8 +477,8 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
public val NumberedPolynomial<C>.degrees: List<UInt>
get() =
MutableList(lastVariable + 1) { 0u }.apply {
coefficients.entries.forEach { (degs, c) ->
if (c.isNotZero()) degs.forEachIndexed { index, deg ->
coefficients.entries.forEach { (degs, _) ->
degs.forEachIndexed { index, deg ->
this[index] = max(this[index], deg)
}
}
@ -558,13 +487,13 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
* Counts degree of the polynomial by the specified [variable].
*/
public fun NumberedPolynomial<C>.degreeBy(variable: Int): UInt =
coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.getOrElse(variable) { 0u } } ?: 0u
coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u
/**
* Counts degree of the polynomial by the specified [variables].
*/
public fun NumberedPolynomial<C>.degreeBy(variables: Collection<Int>): UInt =
coefficients.entries.maxOfOrNull { (degs, c) ->
if (c.isZero()) 0u else degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value }
coefficients.entries.maxOfOrNull { (degs, _) ->
degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value }
} ?: 0u
/**
* Count of variables occurring in the polynomial with positive power. If there is no such variable,
@ -573,43 +502,13 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
public val NumberedPolynomial<C>.countOfVariables: Int
get() =
MutableList(lastVariable + 1) { false }.apply {
coefficients.entries.forEach { (degs, c) ->
if (c.isNotZero()) degs.forEachIndexed { index, deg ->
coefficients.entries.forEach { (degs, _) ->
degs.forEachIndexed { index, deg ->
if (deg != 0u) this[index] = true
}
}
}.count { it }
/**
* Checks if the instant is constant polynomial (of degree no more than 0) over considered ring.
*/
override fun NumberedPolynomial<C>.isConstant(): Boolean =
coefficients.all { (degs, c) -> degs.isEmpty() || c.isZero() }
/**
* Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring.
*/
override fun NumberedPolynomial<C>.isNonZeroConstant(): Boolean =
with(coefficients) {
var foundAbsoluteTermAndItIsNotZero = false
for ((degs, c) in this) {
if (degs.isNotEmpty()) if (c.isNotZero()) return@with false
else {
if (c.isZero()) return@with false
else foundAbsoluteTermAndItIsNotZero = true
}
}
foundAbsoluteTermAndItIsNotZero
}
/**
* If polynomial is a constant polynomial represents and returns it as constant.
* Otherwise, (when the polynomial is not constant polynomial) returns `null`.
*/
override fun NumberedPolynomial<C>.asConstantOrNull(): C? =
with(coefficients) {
if(isConstant()) getOrElse(emptyList()) { constantZero }
else null
}
@Suppress("NOTHING_TO_INLINE")
public inline fun NumberedPolynomial<C>.substitute(argument: Map<Int, C>): NumberedPolynomial<C> = this.substitute(ring, argument)
@Suppress("NOTHING_TO_INLINE")
@ -629,35 +528,6 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
@JvmName("invokePolynomial")
public inline operator fun NumberedPolynomial<C>.invoke(argument: Map<Int, NumberedPolynomial<C>>): NumberedPolynomial<C> = this.substitute(ring, argument)
// TODO: Move to other internal utilities with context receiver
@JvmName("applyAndRemoveZerosInternal")
internal fun MutableMap<List<UInt>, C>.applyAndRemoveZeros(block: MutableMap<List<UInt>, C>.() -> Unit) : MutableMap<List<UInt>, C> {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
for ((degs, c) in this) if (c.isZero()) this.remove(degs)
return this
}
internal fun Map<List<UInt>, C>.applyAndRemoveZeros(block: MutableMap<List<UInt>, C>.() -> Unit) : Map<List<UInt>, C> =
toMutableMap().applyAndRemoveZeros(block)
@OptIn(ExperimentalTypeInference::class)
internal inline fun buildCoefficients(@BuilderInference builderAction: MutableMap<List<UInt>, C>.() -> Unit): Map<List<UInt>, C> {
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
return buildMap {
builderAction()
for ((degs, c) in this) if (c.isZero()) this.remove(degs)
}
}
@OptIn(ExperimentalTypeInference::class)
internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableMap<List<UInt>, C>.() -> Unit): Map<List<UInt>, C> {
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
return buildMap(capacity) {
builderAction()
for ((degs, c) in this) if (c.isZero()) this.remove(degs)
}
}
// TODO: Move to other constructors with context receiver
public fun C.asNumberedPolynomial() : NumberedPolynomial<C> = NumberedPolynomial<C>(mapOf(emptyList<UInt>() to this))
}

View File

@ -19,45 +19,35 @@ public class NumberedRationalFunction<C> internal constructor(
// Waiting for context receivers :( TODO: Replace with context receivers when they will be available
@Suppress("FunctionName")
internal fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numerator: NumberedPolynomial<C>, denominator: NumberedPolynomial<C>): NumberedRationalFunction<C> =
if (denominator.isZero()) throw ArithmeticException("/ by zero")
else NumberedRationalFunction<C>(numerator, denominator)
@Suppress("FunctionName")
internal fun <C, A: Ring<C>> A.NumberedRationalFunction(numerator: NumberedPolynomial<C>, denominator: NumberedPolynomial<C>): NumberedRationalFunction<C> =
if (denominator.coefficients.values.all { it == zero }) throw ArithmeticException("/ by zero")
else NumberedRationalFunction<C>(numerator, denominator)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>, denominatorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero")
else NumberedRationalFunction<C>(
NumberedPolynomial(numeratorCoefficients),
NumberedPolynomial(denominatorCoefficients)
NumberedRationalFunction<C>(
NumberedPolynomial(numeratorCoefficients, toCheckInput = true),
NumberedPolynomial(denominatorCoefficients, toCheckInput = true)
)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> A.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>, denominatorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero")
else NumberedRationalFunction<C>(
NumberedPolynomial(numeratorCoefficients),
NumberedPolynomial(denominatorCoefficients)
NumberedRationalFunction<C>(
NumberedPolynomial(numeratorCoefficients, toCheckInput = true),
NumberedPolynomial(denominatorCoefficients, toCheckInput = true)
)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numerator: NumberedPolynomial<C>): NumberedRationalFunction<C> =
NumberedRationalFunction<C>(numerator, polynomialOne)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> A.NumberedRationalFunction(numerator: NumberedPolynomial<C>): NumberedRationalFunction<C> =
NumberedRationalFunction<C>(numerator, NumberedPolynomial(mapOf(emptyList<UInt>() to one)))
NumberedRationalFunction<C>(numerator, NumberedPolynomial(mapOf(emptyList<UInt>() to one), toCheckInput = false))
@Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
NumberedRationalFunction<C>(
NumberedPolynomial(numeratorCoefficients),
NumberedPolynomial(numeratorCoefficients, toCheckInput = true),
polynomialOne
)
@Suppress("FunctionName")
public fun <C, A: Ring<C>> A.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
NumberedRationalFunction<C>(
NumberedPolynomial(numeratorCoefficients),
NumberedPolynomial(mapOf(emptyList<UInt>() to one))
NumberedPolynomial(numeratorCoefficients, toCheckInput = true),
NumberedPolynomial(mapOf(emptyList<UInt>() to one), toCheckInput = false)
)
public class NumberedRationalFunctionSpace<C, A: Ring<C>> (
@ -91,28 +81,6 @@ public class NumberedRationalFunctionSpace<C, A: Ring<C>> (
*/
public override val one: NumberedRationalFunction<C> = NumberedRationalFunction(polynomialOne, polynomialOne)
/**
* Checks equality of the rational functions.
*/
public override infix fun NumberedRationalFunction<C>.equalsTo(other: NumberedRationalFunction<C>): Boolean {
if (this === other) return true
if (numerator.isZero() != other.numerator.isZero()) return false
val countOfVariables = max(this.lastVariable, other.lastVariable)
val thisNumeratorDegrees = this.numerator.degrees
val thisDenominatorDegrees = this.denominator.degrees
val otherNumeratorDegrees = other.numerator.degrees
val otherDenominatorDegrees = other.denominator.degrees
for (variable in 0 .. 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
}
/**
* Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable,
* the result is `-1`.
@ -152,13 +120,13 @@ public class NumberedRationalFunctionSpace<C, A: Ring<C>> (
public val NumberedRationalFunction<C>.countOfVariables: Int
get() =
MutableList(lastVariable + 1) { false }.apply {
numerator.coefficients.entries.forEach { (degs, c) ->
if (c.isNotZero()) degs.forEachIndexed { index, deg ->
numerator.coefficients.entries.forEach { (degs, _) ->
degs.forEachIndexed { index, deg ->
if (deg != 0u) this[index] = true
}
}
denominator.coefficients.entries.forEach { (degs, c) ->
if (c.isNotZero()) degs.forEachIndexed { index, deg ->
denominator.coefficients.entries.forEach { (degs, _) ->
degs.forEachIndexed { index, deg ->
if (deg != 0u) this[index] = true
}
}

View File

@ -155,31 +155,6 @@ public interface PolynomialSpace<C, P: Polynomial<C>> : Ring<P> {
@JsName("constantPower")
public fun power(arg: C, exponent: UInt) : C
/**
* Check if the instant is zero constant.
*/
public fun C.isZero(): Boolean = this == constantZero
/**
* Check if the instant is NOT zero constant.
*/
public fun C.isNotZero(): Boolean = !isZero()
/**
* Check if the instant is unit constant.
*/
public fun C.isOne(): Boolean = this == constantOne
/**
* Check if the instant is NOT unit constant.
*/
public fun C.isNotOne(): Boolean = !isOne()
/**
* Check if the instant is minus unit constant.
*/
public fun C.isMinusOne(): Boolean = this == -constantOne
/**
* Check if the instant is NOT minus unit constant.
*/
public fun C.isNotMinusOne(): Boolean = !isMinusOne()
/**
* Instance of zero constant (zero of the underlying ring).
*/
@ -249,31 +224,6 @@ public interface PolynomialSpace<C, P: Polynomial<C>> : Ring<P> {
*/
public override fun power(arg: P, exponent: UInt) : P = exponentiationBySquaring(arg, exponent)
/**
* Check if the instant is zero polynomial.
*/
public fun P.isZero(): Boolean = this equalsTo zero
/**
* Check if the instant is NOT zero polynomial.
*/
public fun P.isNotZero(): Boolean = !isZero()
/**
* Check if the instant is unit polynomial.
*/
public fun P.isOne(): Boolean = this equalsTo one
/**
* Check if the instant is NOT unit polynomial.
*/
public fun P.isNotOne(): Boolean = !isOne()
/**
* Check if the instant is minus unit polynomial.
*/
public fun P.isMinusOne(): Boolean = this equalsTo -one
/**
* Check if the instant is NOT minus unit polynomial.
*/
public fun P.isNotMinusOne(): Boolean = !isMinusOne()
/**
* Instance of zero polynomial (zero of the polynomial ring).
*/
@ -283,48 +233,12 @@ public interface PolynomialSpace<C, P: Polynomial<C>> : Ring<P> {
*/
public override val one: P
/**
* Checks equality of the polynomials.
*/
public infix fun P.equalsTo(other: P): Boolean
/**
* Checks NOT equality of the polynomials.
*/
public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other)
/**
* Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1.
*/
public val P.degree: Int
/**
* Checks if the instant is constant polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isConstant(): Boolean = degree <= 0
/**
* Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isNotConstant(): Boolean = !isConstant()
/**
* Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isNonZeroConstant(): Boolean = degree == 0
/**
* Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant()
/**
* If polynomial is a constant polynomial represents and returns it as constant.
* Otherwise, (when the polynomial is not constant polynomial) returns `null`.
*/
public fun P.asConstantOrNull(): C?
/**
* If polynomial is a constant polynomial represents and returns it as constant.
* Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception.
*/
public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" }
override fun add(left: P, right: P): P = left + right
override fun multiply(left: P, right: P): P = left * right
}

View File

@ -222,31 +222,6 @@ public interface RationalFunctionalSpace<C, P: Polynomial<C>, R: RationalFunctio
@JsName("constantPower")
public fun power(arg: C, exponent: UInt) : C
/**
* Check if the instant is zero constant.
*/
public fun C.isZero(): Boolean = this == constantZero
/**
* Check if the instant is NOT zero constant.
*/
public fun C.isNotZero(): Boolean = !isZero()
/**
* Check if the instant is unit constant.
*/
public fun C.isOne(): Boolean = this == constantOne
/**
* Check if the instant is NOT unit constant.
*/
public fun C.isNotOne(): Boolean = !isOne()
/**
* Check if the instant is minus unit constant.
*/
public fun C.isMinusOne(): Boolean = this == -constantOne
/**
* Check if the instant is NOT minus unit constant.
*/
public fun C.isNotMinusOne(): Boolean = !isMinusOne()
/**
* Instance of zero constant (zero of the underlying ring).
*/
@ -320,31 +295,6 @@ public interface RationalFunctionalSpace<C, P: Polynomial<C>, R: RationalFunctio
*/
public fun power(arg: P, exponent: UInt) : P
/**
* Check if the instant is zero polynomial.
*/
public fun P.isZero(): Boolean = this equalsTo polynomialZero
/**
* Check if the instant is NOT zero polynomial.
*/
public fun P.isNotZero(): Boolean = !isZero()
/**
* Check if the instant is unit polynomial.
*/
public fun P.isOne(): Boolean = this equalsTo polynomialOne
/**
* Check if the instant is NOT unit polynomial.
*/
public fun P.isNotOne(): Boolean = !isOne()
/**
* Check if the instant is minus unit polynomial.
*/
public fun P.isMinusOne(): Boolean = this equalsTo -polynomialOne
/**
* Check if the instant is NOT minus unit polynomial.
*/
public fun P.isNotMinusOne(): Boolean = !isMinusOne()
/**
* Instance of zero polynomial (zero of the polynomial ring).
*/
@ -354,15 +304,6 @@ public interface RationalFunctionalSpace<C, P: Polynomial<C>, R: RationalFunctio
*/
public val polynomialOne: P
/**
* Checks equality of the polynomials.
*/
public infix fun P.equalsTo(other: P): Boolean
/**
* Checks NOT equality of the polynomials.
*/
public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other)
/**
* Returns sum of the constant represented as rational function and the rational function.
*/
@ -478,31 +419,6 @@ public interface RationalFunctionalSpace<C, P: Polynomial<C>, R: RationalFunctio
*/
public override fun power(arg: R, exponent: UInt) : R = exponentiationBySquaring(arg, exponent)
/**
* Check if the instant is zero rational function.
*/
public fun R.isZero(): Boolean = numerator equalsTo polynomialZero
/**
* Check if the instant is NOT zero rational function.
*/
public fun R.isNotZero(): Boolean = !isZero()
/**
* Check if the instant is unit rational function.
*/
public fun R.isOne(): Boolean = numerator equalsTo denominator
/**
* Check if the instant is NOT unit rational function.
*/
public fun R.isNotOne(): Boolean = !isOne()
/**
* Check if the instant is minus unit rational function.
*/
public fun R.isMinusOne(): Boolean = (numerator + denominator).isZero()
/**
* Check if the instant is NOT minus unit rational function.
*/
public fun R.isNotMinusOne(): Boolean = !isMinusOne()
/**
* Instance of zero rational function (zero of the rational functions ring).
*/
@ -512,54 +428,12 @@ public interface RationalFunctionalSpace<C, P: Polynomial<C>, R: RationalFunctio
*/
public override val one: R
/**
* Checks equality of the rational functions.
*/
public infix fun R.equalsTo(other: R): Boolean =
when {
this === other -> true
numerator.isZero() != other.numerator.isZero() -> false
numeratorDegree - denominatorDegree != with(other) { numeratorDegree - denominatorDegree } -> false
else -> numerator * other.denominator equalsTo other.numerator * denominator
}
/**
* Checks NOT equality of the polynomials.
*/
public infix fun R.notEqualsTo(other: R): Boolean = !(this equalsTo other)
/**
* Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1.
*/
public val P.degree: Int
/**
* Checks if the instant is constant polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isConstant(): Boolean = degree <= 0
/**
* Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isNotConstant(): Boolean = !isConstant()
/**
* Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isNonZeroConstant(): Boolean = degree == 0
/**
* Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring.
*/
public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant()
/**
* If polynomial is a constant polynomial represents and returns it as constant.
* Otherwise, (when the polynomial is not constant polynomial) returns `null`.
*/
public fun P.asConstantOrNull(): C?
/**
* If polynomial is a constant polynomial represents and returns it as constant.
* Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception.
*/
public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" }
/**
* Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1.
@ -813,31 +687,6 @@ public interface RationalFunctionalSpaceOverPolynomialSpace<
@JvmName("constantPower")
public override fun power(arg: C, exponent: UInt) : C = polynomialRing { power(arg, exponent) }
/**
* Check if the instant is zero constant.
*/
public override fun C.isZero(): Boolean = polynomialRing { this@isZero.isZero() }
/**
* Check if the instant is NOT zero constant.
*/
public override fun C.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() }
/**
* Check if the instant is unit constant.
*/
public override fun C.isOne(): Boolean = polynomialRing { this@isOne.isOne() }
/**
* Check if the instant is NOT unit constant.
*/
public override fun C.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() }
/**
* Check if the instant is minus unit constant.
*/
public override fun C.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() }
/**
* Check if the instant is NOT minus unit constant.
*/
public override fun C.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() }
/**
* Instance of zero constant (zero of the underlying ring).
*/
@ -907,31 +756,6 @@ public interface RationalFunctionalSpaceOverPolynomialSpace<
*/
public override fun power(arg: P, exponent: UInt) : P = polynomialRing { power(arg, exponent) }
/**
* Check if the instant is zero polynomial.
*/
public override fun P.isZero(): Boolean = polynomialRing { this@isZero.isZero() }
/**
* Check if the instant is NOT zero polynomial.
*/
public override fun P.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() }
/**
* Check if the instant is unit polynomial.
*/
public override fun P.isOne(): Boolean = polynomialRing { this@isOne.isOne() }
/**
* Check if the instant is NOT unit polynomial.
*/
public override fun P.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() }
/**
* Check if the instant is minus unit polynomial.
*/
public override fun P.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() }
/**
* Check if the instant is NOT minus unit polynomial.
*/
public override fun P.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() }
/**
* Instance of zero polynomial (zero of the polynomial ring).
*/
@ -941,47 +765,11 @@ public interface RationalFunctionalSpaceOverPolynomialSpace<
*/
public override val polynomialOne: P get() = polynomialRing.one
/**
* Checks equality of the polynomials.
*/
public override infix fun P.equalsTo(other: P): Boolean = polynomialRing { this@equalsTo equalsTo other }
/**
* Checks NOT equality of the polynomials.
*/
public override infix fun P.notEqualsTo(other: P): Boolean = polynomialRing { this@notEqualsTo notEqualsTo other }
/**
* Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1.
*/
public override val P.degree: Int get() = polynomialRing { this@degree.degree }
/**
* Checks if the instant is constant polynomial (of degree no more than 0) over considered ring.
*/
public override fun P.isConstant(): Boolean = polynomialRing { this@isConstant.isConstant() }
/**
* Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring.
*/
public override fun P.isNotConstant(): Boolean = polynomialRing { this@isNotConstant.isNotConstant() }
/**
* Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring.
*/
public override fun P.isNonZeroConstant(): Boolean = polynomialRing { this@isNonZeroConstant.isNonZeroConstant() }
/**
* Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring.
*/
public override fun P.isNotNonZeroConstant(): Boolean = polynomialRing { this@isNotNonZeroConstant.isNotNonZeroConstant() }
/**
* If polynomial is a constant polynomial represents and returns it as constant.
* Otherwise, (when the polynomial is not constant polynomial) returns `null`.
*/
public override fun P.asConstantOrNull(): C? = polynomialRing { this@asConstantOrNull.asConstantOrNull() }
/**
* If polynomial is a constant polynomial represents and returns it as constant.
* Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception.
*/
public override fun P.asConstant(): C = polynomialRing { this@asConstant.asConstant() }
}
/**
@ -1032,18 +820,11 @@ public abstract class PolynomialSpaceOfFractions<
denominator
)
public override operator fun R.div(other: Int): R {
val otherAsConstant = constantNumber(other)
require(otherAsConstant.isNotZero()) { "/ by zero." }
return constructRationalFunction(
public override operator fun R.div(other: Int): R =
constructRationalFunction(
numerator,
(denominator * other).also {
check(it.isNotZero()) {
"Got zero denominator during division of rational functions to constant. It means underlying ring of polynomials is not integral domain."
}
}
denominator * other
)
}
/**
* Returns sum of the integer represented as rational function and the rational function.
@ -1076,13 +857,11 @@ public abstract class PolynomialSpaceOfFractions<
other.denominator
)
public override operator fun Int.div(other: R): R {
require(other.numerator.isNotZero()) { "/ by zero." }
return constructRationalFunction(
public override operator fun Int.div(other: R): R =
constructRationalFunction(
this * other.denominator,
other.numerator
)
}
/**
* Converts the integer [value] to rational function.
@ -1119,13 +898,11 @@ public abstract class PolynomialSpaceOfFractions<
other.denominator
)
public override operator fun C.div(other: R): R {
require(other.numerator.isNotZero()) { "/ by zero." }
return constructRationalFunction(
public override operator fun C.div(other: R): R =
constructRationalFunction(
this * other.denominator,
other.numerator
)
}
/**
* Returns sum of the constant represented as rational function and the rational function.
@ -1152,17 +929,11 @@ public abstract class PolynomialSpaceOfFractions<
denominator
)
public override operator fun R.div(other: C): R {
require(other.isNotZero()) { "/ by zero." }
return constructRationalFunction(
public override operator fun R.div(other: C): R =
constructRationalFunction(
numerator,
(denominator * other).also {
check(it.isNotZero()) {
"Got zero denominator during division of rational functions to constant. It means underlying ring of polynomials is not integral domain."
}
}
denominator * other
)
}
/**
* Converts the constant [value] to rational function.
@ -1194,13 +965,11 @@ public abstract class PolynomialSpaceOfFractions<
other.denominator
)
public override operator fun P.div(other: R): R {
require(other.numerator.isNotZero()) { "/ by zero." }
return constructRationalFunction(
public override operator fun P.div(other: R): R =
constructRationalFunction(
this * other.denominator,
other.numerator
)
}
/**
* Returns sum of the polynomial represented as rational function and the rational function.
@ -1227,17 +996,11 @@ public abstract class PolynomialSpaceOfFractions<
denominator
)
public override operator fun R.div(other: P): R {
require(other.isNotZero()) { "/ by zero." }
return constructRationalFunction(
public override operator fun R.div(other: P): R =
constructRationalFunction(
numerator,
(denominator * other).also {
require(it.isNotZero()) {
"Got zero denominator during division of rational functions to polynomial. It means underlying ring of polynomials is not integral domain."
}
}
denominator * other
)
}
/**
* Converts the polynomial [value] to rational function.
@ -1254,11 +1017,7 @@ public abstract class PolynomialSpaceOfFractions<
public override operator fun R.plus(other: R): R =
constructRationalFunction(
numerator * other.denominator + denominator * other.numerator,
(denominator * other.denominator).also {
check(it.isNotZero()) {
"Got zero denominator during addition of rational functions. It means underlying ring of polynomials is not integral domain."
}
}
denominator * other.denominator
)
/**
* Returns difference of the rational functions.
@ -1266,11 +1025,7 @@ public abstract class PolynomialSpaceOfFractions<
public override operator fun R.minus(other: R): R =
constructRationalFunction(
numerator * other.denominator - denominator * other.numerator,
(denominator * other.denominator).also {
check(it.isNotZero()) {
"Got zero denominator during subtraction of rational functions. It means underlying ring of polynomials is not integral domain."
}
}
denominator * other.denominator
)
/**
* Returns product of the rational functions.
@ -1278,24 +1033,14 @@ public abstract class PolynomialSpaceOfFractions<
public override operator fun R.times(other: R): R =
constructRationalFunction(
numerator * other.numerator,
(denominator * other.denominator).also {
check(it.isNotZero()) {
"Got zero denominator during multiplication of rational functions. It means underlying ring of polynomials is not integral domain."
}
}
denominator * other.denominator
)
public override operator fun R.div(other: R): R {
require(other.isNotZero()) { "/ by zero." }
return constructRationalFunction(
public override operator fun R.div(other: R): R =
constructRationalFunction(
numerator * other.denominator,
(denominator * other.numerator).also {
check(it.isNotZero()) {
"Got zero denominator during division of rational functions. It means underlying ring of polynomials is not integral domain."
}
}
denominator * other.numerator
)
}
/**
* Instance of zero rational function (zero of the rational functions ring).

View File

@ -121,9 +121,9 @@ public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: C): C = ring {
public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: ListPolynomial<C>) : ListPolynomial<C> = ring {
if (coefficients.isEmpty()) return ListPolynomial(emptyList())
val thisDegree = coefficients.indexOfLast { it != zero }
val thisDegree = coefficients.lastIndex
if (thisDegree == -1) return ListPolynomial(emptyList())
val argDegree = arg.coefficients.indexOfLast { it != zero }
val argDegree = arg.coefficients.lastIndex
if (argDegree == -1) return coefficients[0].asListPolynomial()
val constantZero = zero
val resultCoefs: MutableList<C> = MutableList(thisDegree * argDegree + 1) { constantZero }
@ -144,7 +144,6 @@ public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: ListPolynomial<C
resultDegree += argDegree
}
with(resultCoefs) { while (isNotEmpty() && elementAt(lastIndex) == constantZero) removeAt(lastIndex) }
return ListPolynomial<C>(resultCoefs)
}
@ -168,7 +167,6 @@ public fun <C, A> ListPolynomial<C>.derivative(
ListPolynomial(
buildList(max(0, coefficients.size - 1)) {
for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg])
while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex)
}
)
}
@ -186,7 +184,6 @@ public fun <C, A> ListPolynomial<C>.nthDerivative(
buildList(max(0, coefficients.size - order)) {
for (deg in order.. coefficients.lastIndex)
add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) })
while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex)
}
)
}
@ -202,7 +199,6 @@ public fun <C, A> ListPolynomial<C>.antiderivative(
buildList(coefficients.size + 1) {
add(zero)
coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) }
while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex)
}
)
}
@ -220,7 +216,6 @@ public fun <C, A> ListPolynomial<C>.nthAntiderivative(
buildList(coefficients.size + order) {
repeat(order) { add(zero) }
coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } }
while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex)
}
)
}

View File

@ -55,11 +55,11 @@ public fun <C> ListRationalFunction<C>.substitute(ring: Field<C>, arg: C): C = r
internal fun <C> ListPolynomial<C>.substituteRationalFunctionTakeNumerator(ring: Ring<C>, arg: ListRationalFunction<C>): ListPolynomial<C> = ring {
if (coefficients.isEmpty()) return ListPolynomial(emptyList())
val thisDegree = coefficients.indexOfLast { it != zero }
val thisDegree = coefficients.lastIndex
if (thisDegree == -1) return ListPolynomial(emptyList())
val thisDegreeLog2 = 31 - thisDegree.countLeadingZeroBits()
val numeratorDegree = arg.numerator.coefficients.indexOfLast { it != zero }
val denominatorDegree = arg.denominator.coefficients.indexOfLast { it != zero }
val numeratorDegree = arg.numerator.coefficients.lastIndex
val denominatorDegree = arg.denominator.coefficients.lastIndex
val argDegree = max(numeratorDegree, denominatorDegree)
val constantZero = zero
val powersOf2 = buildList<Int>(thisDegreeLog2 + 1) {

View File

@ -9,7 +9,7 @@ import space.kscience.kmath.test.misc.*
import kotlin.test.*
class ListPolynomialTest {
class ListPolynomialTest { // TODO: Adapt tests to changes
@Test
fun test_Polynomial_Int_plus() {
RationalField.listPolynomial {
@ -489,94 +489,6 @@ class ListPolynomialTest {
}
}
@Test
fun test_Polynomial_isZero() {
RationalField.listPolynomial {
assertTrue("test 1") { ListPolynomial<Rational>().isZero() }
assertTrue("test 2") { ListPolynomial<Rational>(Rational(0)).isZero() }
assertTrue("test 3") { ListPolynomial<Rational>(Rational(0), Rational(0)).isZero() }
assertTrue("test 4") { ListPolynomial<Rational>(Rational(0), Rational(0), Rational(0))
.isZero() }
assertFalse("test 5") { ListPolynomial<Rational>(Rational(3, 5)).isZero() }
assertFalse("test 6") { ListPolynomial<Rational>(Rational(3, 5), Rational(0))
.isZero() }
assertFalse("test 7") { ListPolynomial<Rational>(Rational(0), Rational(3, 5), Rational(0))
.isZero() }
}
}
@Test
fun test_Polynomial_isOne() {
RationalField.listPolynomial {
assertFalse("test 1") { ListPolynomial<Rational>().isOne() }
assertFalse("test 2") { ListPolynomial(Rational(0)).isOne() }
assertFalse("test 3") { ListPolynomial(Rational(0), Rational(0)).isOne() }
assertFalse("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0))
.isOne() }
assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isOne() }
assertTrue("test 6") { ListPolynomial(Rational(5, 5)).isOne() }
assertFalse("test 7") { ListPolynomial(Rational(3, 5), Rational(0)).isOne() }
assertTrue("test 8") { ListPolynomial(Rational(3, 3), Rational(0)).isOne() }
assertFalse("test 9") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0))
.isOne() }
assertFalse("test 10") { ListPolynomial(Rational(0), Rational(5, 5), Rational(0))
.isOne() }
assertFalse("test 11") { ListPolynomial(Rational(1), Rational(3, 5), Rational(0))
.isOne() }
assertFalse("test 12") { ListPolynomial(Rational(1), Rational(5, 5), Rational(0))
.isOne() }
}
}
@Test
fun test_Polynomial_isMinusOne() {
RationalField.listPolynomial {
assertFalse("test 1") { ListPolynomial<Rational>().isMinusOne() }
assertFalse("test 2") { ListPolynomial(Rational(0)).isMinusOne() }
assertFalse("test 3") { ListPolynomial(Rational(0), Rational(0)).isMinusOne() }
assertFalse("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0))
.isMinusOne() }
assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isMinusOne() }
assertTrue("test 6") { ListPolynomial(Rational(-5, 5)).isMinusOne() }
assertFalse("test 7") { ListPolynomial(Rational(3, 5), Rational(0)).isMinusOne() }
assertTrue("test 8") { ListPolynomial(Rational(-3, 3), Rational(0)).isMinusOne() }
assertFalse("test 9") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0))
.isMinusOne() }
assertFalse("test 10") { ListPolynomial(Rational(0), Rational(5, -5), Rational(0))
.isMinusOne() }
assertFalse("test 11") { ListPolynomial(Rational(-1), Rational(3, 5), Rational(0))
.isMinusOne() }
assertFalse("test 12") { ListPolynomial(Rational(-1), Rational(5, -5), Rational(0))
.isMinusOne() }
}
}
@Test
fun test_Polynomial_Polynomial_equalsTo() {
RationalField.listPolynomial {
assertTrue("test 1") {
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) equalsTo
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7))
}
assertTrue("test 2") {
ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) equalsTo
ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7))
}
assertTrue("test 3") {
ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo
ListPolynomial(Rational(0), Rational(0), Rational(-8, 7))
}
assertFalse("test 4") {
ListPolynomial(Rational(5, 9), Rational(5, 7), Rational(-8, 7)) equalsTo
ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7))
}
assertFalse("test 5") {
ListPolynomial(Rational(8, 3), Rational(0), Rational(-8, 7)) equalsTo
ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7))
}
assertFalse("test 6") {
ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo
ListPolynomial(Rational(0), Rational(0), Rational(8, 7))
}
}
}
@Test
fun test_Polynomial_degree() {
RationalField.listPolynomial {
assertEquals(
@ -636,70 +548,4 @@ class ListPolynomialTest {
)
}
}
@Test
fun test_Polynomial_asConstantOrNull() {
RationalField.listPolynomial {
assertEquals(
Rational(0),
ListPolynomial<Rational>().asConstantOrNull(),
"test 1"
)
assertEquals(
Rational(0),
ListPolynomial(Rational(0)).asConstantOrNull(),
"test 2"
)
assertEquals(
Rational(0),
ListPolynomial(Rational(0), Rational(0)).asConstantOrNull(),
"test 3"
)
assertEquals(
Rational(0),
ListPolynomial(Rational(0), Rational(0), Rational(0)).asConstantOrNull(),
"test 4"
)
assertEquals(
Rational(-7, 9),
ListPolynomial(Rational(-7, 9)).asConstantOrNull(),
"test 5"
)
assertEquals(
Rational(-7, 9),
ListPolynomial(Rational(-7, 9), Rational(0)).asConstantOrNull(),
"test 6"
)
assertEquals(
Rational(-7, 9),
ListPolynomial(Rational(-7, 9), Rational(0), Rational(0)).asConstantOrNull(),
"test 7"
)
assertEquals(
null,
ListPolynomial(Rational(0), Rational(-7, 9)).asConstantOrNull(),
"test 8"
)
assertEquals(
null,
ListPolynomial(Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(),
"test 9"
)
assertEquals(
null,
ListPolynomial(Rational(0), Rational(0), Rational(-7, 9)).asConstantOrNull(),
"test 10"
)
assertEquals(
null,
ListPolynomial(Rational(4, 15), Rational(0), Rational(-7, 9)).asConstantOrNull(),
"test 11"
)
assertEquals(
null,
ListPolynomial(Rational(4, 15), Rational(0), Rational(-7, 9), Rational(0))
.asConstantOrNull(),
"test 12"
)
}
}
}

View File

@ -12,7 +12,7 @@ import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class ListPolynomialUtilTest {
class ListPolynomialUtilTest { // TODO: Adapt tests to changes
@Test
fun test_substitute_Double() {
assertEquals(