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") @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) 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") @Suppress("FunctionName")
internal fun <C, A: Ring<C>> A.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>, toCheckInput: Boolean = true) : LabeledPolynomial<C> { 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) 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 fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value
} }
return LabeledPolynomial<C>( return LabeledPolynomial<C>(fixedCoefs)
fixedCoefs.filterValues { it != zero }
)
} }
@Suppress("FunctionName", "NOTHING_TO_INLINE") @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) 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") @Suppress("FunctionName")
internal fun <C, A: Ring<C>> A.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>, toCheckInput: Boolean = true) : LabeledPolynomial<C> { 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()) 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 fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value
} }
return LabeledPolynomial<C>( return LabeledPolynomial<C>(fixedCoefs)
fixedCoefs.filterValues { it != zero }
)
} }
@Suppress("FunctionName", "NOTHING_TO_INLINE") @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) 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") @Suppress("FunctionName")
internal fun <C, A: Ring<C>> A.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>, toCheckInput: Boolean = true) : LabeledPolynomial<C> { 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()) 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 fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value
} }
return LabeledPolynomial<C>( return LabeledPolynomial<C>(fixedCoefs)
fixedCoefs.filterValues { it != zero }
)
} }
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> A.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(coefs, toCheckInput = true) public fun <C, A: Ring<C>> A.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(coefs, toCheckInput = true)
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> LabeledPolynomialSpace<C, A>.LabeledPolynomial(coefs: Map<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(coefs, toCheckInput = true) 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") @Suppress("FunctionName")
public fun <C, A: Ring<C>> A.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>) : LabeledPolynomial<C> = LabeledPolynomial(pairs, toCheckInput = true) public fun <C, A: Ring<C>> A.LabeledPolynomial(pairs: Collection<Pair<Map<Symbol, UInt>, C>>) : LabeledPolynomial<C> = LabeledPolynomial(pairs, toCheckInput = true)
@Suppress("FunctionName") @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) 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") @Suppress("FunctionName")
public fun <C, A: Ring<C>> A.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(*pairs, toCheckInput = true) public fun <C, A: Ring<C>> A.LabeledPolynomial(vararg pairs: Pair<Map<Symbol, UInt>, C>) : LabeledPolynomial<C> = LabeledPolynomial(*pairs, toCheckInput = true)
@Suppress("FunctionName") @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) 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) //context(A)
//public fun <C, A: Ring<C>> Symbol.asLabeledPolynomial() : LabeledPolynomial<C> = LabeledPolynomial<C>(mapOf(mapOf(this to 1u) to one)) //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> = public override operator fun LabeledPolynomial<C>.plus(other: Int): LabeledPolynomial<C> =
if (other == 0) this if (other == 0) this
else else with(coefficients) {
LabeledPolynomial( if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to other.asConstant()))
coefficients else LabeledPolynomial<C>(
.toMutableMap() toMutableMap()
.apply { .apply {
val degs = emptyMap<Symbol, UInt>() val degs = emptyMap<Symbol, UInt>()
val result = getOrElse(degs) { constantZero } + other this[degs] = getOrElse(degs) { constantZero } + other
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
}
/** /**
* Returns difference between the polynomial and the integer represented as polynomial. * 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> = public override operator fun LabeledPolynomial<C>.minus(other: Int): LabeledPolynomial<C> =
if (other == 0) this if (other == 0) this
else else with(coefficients) {
LabeledPolynomial( if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to (-other).asConstant()))
coefficients else LabeledPolynomial<C>(
.toMutableMap() toMutableMap()
.apply { .apply {
val degs = emptyMap<Symbol, UInt>() val degs = emptyMap<Symbol, UInt>()
val result = getOrElse(degs) { constantZero } - other this[degs] = getOrElse(degs) { constantZero } - other
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
}
/** /**
* Returns product of the polynomial and the integer represented as polynomial. * 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 if (other == 0) zero
else LabeledPolynomial( else LabeledPolynomial(
coefficients coefficients
.applyAndRemoveZeros { .toMutableMap()
.apply {
for (degs in keys) this[degs] = this[degs]!! * other 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> = public override operator fun Int.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
if (this == 0) other if (this == 0) other
else else with(other.coefficients) {
LabeledPolynomial( if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this@plus.asConstant()))
other.coefficients else LabeledPolynomial<C>(
.toMutableMap() toMutableMap()
.apply { .apply {
val degs = emptyMap<Symbol, UInt>() val degs = emptyMap<Symbol, UInt>()
val result = this@plus + getOrElse(degs) { constantZero } this[degs] = this@plus + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
}
/** /**
* Returns difference between the integer represented as polynomial and the polynomial. * 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> = public override operator fun Int.minus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
if (this == 0) other if (this == 0) other
else else with(other.coefficients) {
LabeledPolynomial( if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this@minus.asConstant()))
other.coefficients else LabeledPolynomial<C>(
.toMutableMap() toMutableMap()
.apply { .apply {
val degs = emptyMap<Symbol, UInt>() val degs = emptyMap<Symbol, UInt>()
val result = this@minus - getOrElse(degs) { constantZero } this[degs] = this@minus - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
}
/** /**
* Returns product of the integer represented as polynomial and the polynomial. * 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 if (this == 0) zero
else LabeledPolynomial( else LabeledPolynomial(
other.coefficients other.coefficients
.applyAndRemoveZeros { .toMutableMap()
.apply {
for (degs in keys) this[degs] = this@times * this[degs]!! 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 fun number(value: Int): LabeledPolynomial<C> = number(constantNumber(value))
public override operator fun C.plus(other: Symbol): LabeledPolynomial<C> = public override operator fun C.plus(other: Symbol): LabeledPolynomial<C> =
if (isZero()) LabeledPolynomial<C>(mapOf( LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to constantOne,
))
else LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to constantOne, mapOf(other to 1U) to constantOne,
emptyMap<Symbol, UInt>() to this@plus, emptyMap<Symbol, UInt>() to this@plus,
)) ))
public override operator fun C.minus(other: Symbol): LabeledPolynomial<C> = public override operator fun C.minus(other: Symbol): LabeledPolynomial<C> =
if (isZero()) LabeledPolynomial<C>(mapOf( LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to -constantOne,
))
else LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to -constantOne, mapOf(other to 1U) to -constantOne,
emptyMap<Symbol, UInt>() to this@minus, emptyMap<Symbol, UInt>() to this@minus,
)) ))
public override operator fun C.times(other: Symbol): LabeledPolynomial<C> = public override operator fun C.times(other: Symbol): LabeledPolynomial<C> =
if (isZero()) zero LabeledPolynomial<C>(mapOf(
else LabeledPolynomial<C>(mapOf(
mapOf(other to 1U) to this@times, mapOf(other to 1U) to this@times,
)) ))
public override operator fun Symbol.plus(other: C): LabeledPolynomial<C> = public override operator fun Symbol.plus(other: C): LabeledPolynomial<C> =
if (other.isZero()) LabeledPolynomial<C>(mapOf( LabeledPolynomial<C>(mapOf(
mapOf(this@plus to 1U) to constantOne,
))
else LabeledPolynomial<C>(mapOf(
mapOf(this@plus to 1U) to constantOne, mapOf(this@plus to 1U) to constantOne,
emptyMap<Symbol, UInt>() to other, emptyMap<Symbol, UInt>() to other,
)) ))
public override operator fun Symbol.minus(other: C): LabeledPolynomial<C> = public override operator fun Symbol.minus(other: C): LabeledPolynomial<C> =
if (other.isZero()) LabeledPolynomial<C>(mapOf( LabeledPolynomial<C>(mapOf(
mapOf(this@minus to 1U) to -constantOne,
))
else LabeledPolynomial<C>(mapOf(
mapOf(this@minus to 1U) to -constantOne, mapOf(this@minus to 1U) to -constantOne,
emptyMap<Symbol, UInt>() to other, emptyMap<Symbol, UInt>() to other,
)) ))
public override operator fun Symbol.times(other: C): LabeledPolynomial<C> = public override operator fun Symbol.times(other: C): LabeledPolynomial<C> =
if (other.isZero()) zero LabeledPolynomial<C>(mapOf(
else LabeledPolynomial<C>(mapOf(
mapOf(this@times to 1U) to other, 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. * Returns sum of the constant represented as polynomial and the polynomial.
*/ */
override operator fun C.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> = override operator fun C.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
if (this.isZero()) other with(other.coefficients) {
else with(other.coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this@plus)) if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this@plus))
else LabeledPolynomial<C>( else LabeledPolynomial<C>(
toMutableMap() toMutableMap()
.apply { .apply {
val degs = emptyMap<Symbol, UInt>() val degs = emptyMap<Symbol, UInt>()
val result = this@plus + getOrElse(degs) { constantZero } this[degs] = this@plus + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
} }
@ -369,8 +351,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns difference between the constant represented as polynomial and the polynomial. * Returns difference between the constant represented as polynomial and the polynomial.
*/ */
override operator fun C.minus(other: LabeledPolynomial<C>): LabeledPolynomial<C> = override operator fun C.minus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
if (this.isZero()) other with(other.coefficients) {
else with(other.coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this@minus)) if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to this@minus))
else LabeledPolynomial<C>( else LabeledPolynomial<C>(
toMutableMap() toMutableMap()
@ -379,10 +360,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
val degs = emptyMap<Symbol, UInt>() val degs = emptyMap<Symbol, UInt>()
val result = this@minus - getOrElse(degs) { constantZero } this[degs] = this@minus - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
} }
@ -390,10 +368,10 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns product of the constant represented as polynomial and the polynomial. * Returns product of the constant represented as polynomial and the polynomial.
*/ */
override operator fun C.times(other: LabeledPolynomial<C>): LabeledPolynomial<C> = override operator fun C.times(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
if (this.isZero()) zero LabeledPolynomial<C>(
else LabeledPolynomial<C>(
other.coefficients other.coefficients
.applyAndRemoveZeros { .toMutableMap()
.apply {
for (degs in keys) this[degs] = this@times * this[degs]!! 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. * Returns sum of the constant represented as polynomial and the polynomial.
*/ */
override operator fun LabeledPolynomial<C>.plus(other: C): LabeledPolynomial<C> = override operator fun LabeledPolynomial<C>.plus(other: C): LabeledPolynomial<C> =
if (other.isZero()) this with(coefficients) {
else with(coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to other)) if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to other))
else LabeledPolynomial<C>( else LabeledPolynomial<C>(
toMutableMap() toMutableMap()
.apply { .apply {
val degs = emptyMap<Symbol, UInt>() val degs = emptyMap<Symbol, UInt>()
val result = getOrElse(degs) { constantZero } + other this[degs] = getOrElse(degs) { constantZero } + other
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
} }
@ -421,8 +395,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns difference between the constant represented as polynomial and the polynomial. * Returns difference between the constant represented as polynomial and the polynomial.
*/ */
override operator fun LabeledPolynomial<C>.minus(other: C): LabeledPolynomial<C> = override operator fun LabeledPolynomial<C>.minus(other: C): LabeledPolynomial<C> =
if (other.isZero()) this with(coefficients) {
else with(coefficients) {
if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to other)) if (isEmpty()) LabeledPolynomial<C>(mapOf(emptyMap<Symbol, UInt>() to other))
else LabeledPolynomial<C>( else LabeledPolynomial<C>(
toMutableMap() toMutableMap()
@ -431,10 +404,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
val degs = emptyMap<Symbol, UInt>() val degs = emptyMap<Symbol, UInt>()
val result = getOrElse(degs) { constantZero } - other this[degs] = getOrElse(degs) { constantZero } - other
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
} }
@ -442,10 +412,10 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns product of the constant represented as polynomial and the polynomial. * Returns product of the constant represented as polynomial and the polynomial.
*/ */
override operator fun LabeledPolynomial<C>.times(other: C): LabeledPolynomial<C> = override operator fun LabeledPolynomial<C>.times(other: C): LabeledPolynomial<C> =
if (other.isZero()) zero LabeledPolynomial<C>(
else LabeledPolynomial<C>(
coefficients coefficients
.applyAndRemoveZeros { .toMutableMap()
.apply {
for (degs in keys) this[degs] = this[degs]!! * other 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. * Converts the constant [value] to polynomial.
*/ */
public override fun number(value: C): LabeledPolynomial<C> = public override fun number(value: C): LabeledPolynomial<C> =
if (value == 0) zero LabeledPolynomial(mapOf(emptyMap<Symbol, UInt>() to value))
else LabeledPolynomial(mapOf(emptyMap<Symbol, UInt>() to value))
public override operator fun Symbol.unaryPlus(): LabeledPolynomial<C> = public override operator fun Symbol.unaryPlus(): LabeledPolynomial<C> =
LabeledPolynomial<C>(mapOf( LabeledPolynomial<C>(mapOf(
@ -495,10 +464,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
.apply { .apply {
val degs = mapOf(this@plus to 1U) val degs = mapOf(this@plus to 1U)
val result = constantOne + getOrElse(degs) { constantZero } this[degs] = constantOne + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
} }
@ -512,10 +478,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
val degs = mapOf(this@minus to 1U) val degs = mapOf(this@minus to 1U)
val result = constantOne - getOrElse(degs) { constantZero } this[degs] = constantOne - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
} }
@ -533,10 +496,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
.apply { .apply {
val degs = mapOf(other to 1U) val degs = mapOf(other to 1U)
val result = constantOne + getOrElse(degs) { constantZero } this[degs] = constantOne + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
} }
@ -548,10 +508,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
.apply { .apply {
val degs = mapOf(other to 1U) val degs = mapOf(other to 1U)
val result = constantOne - getOrElse(degs) { constantZero } this[degs] = constantOne - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
} }
@ -573,7 +530,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
*/ */
override operator fun LabeledPolynomial<C>.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> = override operator fun LabeledPolynomial<C>.plus(other: LabeledPolynomial<C>): 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) { it.value }
other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else 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> = override operator fun LabeledPolynomial<C>.minus(other: LabeledPolynomial<C>): 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) { it.value }
other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value }
} }
@ -592,20 +549,16 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns product of the polynomials. * Returns product of the polynomials.
*/ */
override operator fun LabeledPolynomial<C>.times(other: LabeledPolynomial<C>): LabeledPolynomial<C> = override operator fun LabeledPolynomial<C>.times(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
when { LabeledPolynomial<C>(
isZero() -> zero buildMap(coefficients.size * other.coefficients.size) {
other.isZero() -> zero for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) {
else -> LabeledPolynomial<C>( val degs = degs1.toMutableMap()
buildCoefficients(coefficients.size * other.coefficients.size) { degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg }
for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { val c = c1 * c2
val degs = degs1.toMutableMap() this[degs] = if (degs in this) this[degs]!! + c else c
degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg }
val c = c1 * c2
this[degs] = if (degs in this) this[degs]!! + c else c
}
} }
) }
} )
/** /**
* Instance of zero polynomial (zero of the polynomial ring). * 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)) 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 * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1. * zero, degree is -1.
*/ */
override val LabeledPolynomial<C>.degree: Int 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 * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents
* in which they are appeared in the polynomial. * 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> public override val LabeledPolynomial<C>.degrees: Map<Symbol, UInt>
get() = get() =
buildMap { buildMap {
coefficients.entries.forEach { (degs, c) -> coefficients.entries.forEach { (degs, _) ->
if (c.isNotZero()) degs.mapValuesTo(this) { (variable, deg) -> degs.mapValuesTo(this) { (variable, deg) ->
max(getOrElse(variable) { 0u }, 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]. * Counts degree of the polynomial by the specified [variable].
*/ */
public override fun LabeledPolynomial<C>.degreeBy(variable: Symbol): UInt = 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]. * Counts degree of the polynomial by the specified [variables].
*/ */
public override fun LabeledPolynomial<C>.degreeBy(variables: Collection<Symbol>): UInt = 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. * Set of all variables that appear in the polynomial in positive exponents.
*/ */
public override val LabeledPolynomial<C>.variables: Set<Symbol> public override val LabeledPolynomial<C>.variables: Set<Symbol>
get() = get() =
buildSet { 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. * Count of all variables that appear in the polynomial in positive exponents.
*/ */
public override val LabeledPolynomial<C>.countOfVariables: Int get() = variables.size 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") // @Suppress("NOTHING_TO_INLINE")
// public inline fun LabeledPolynomial<C>.substitute(argument: Map<Symbol, C>): LabeledPolynomial<C> = this.substitute(ring, argument) // public inline fun LabeledPolynomial<C>.substitute(argument: Map<Symbol, C>): LabeledPolynomial<C> = this.substitute(ring, argument)
// @Suppress("NOTHING_TO_INLINE") // @Suppress("NOTHING_TO_INLINE")
@ -719,33 +632,4 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
// @Suppress("NOTHING_TO_INLINE") // @Suppress("NOTHING_TO_INLINE")
// @JvmName("invokePolynomial") // @JvmName("invokePolynomial")
// public inline operator fun LabeledPolynomial<C>.invoke(argument: Map<Symbol, LabeledPolynomial<C>>): LabeledPolynomial<C> = this.substitute(ring, argument) // 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 // 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") @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> = 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") LabeledRationalFunction<C>(
else LabeledRationalFunction<C>( LabeledPolynomial(numeratorCoefficients, toCheckInput = true),
LabeledPolynomial(numeratorCoefficients), LabeledPolynomial(denominatorCoefficients, toCheckInput = true)
LabeledPolynomial(denominatorCoefficients)
) )
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> A.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>, denominatorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> = 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") LabeledRationalFunction<C>(
else LabeledRationalFunction<C>( LabeledPolynomial(numeratorCoefficients, toCheckInput = true),
LabeledPolynomial(numeratorCoefficients), LabeledPolynomial(denominatorCoefficients, toCheckInput = true)
LabeledPolynomial(denominatorCoefficients)
) )
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledRationalFunction(numerator: LabeledPolynomial<C>): LabeledRationalFunction<C> = public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledRationalFunction(numerator: LabeledPolynomial<C>): LabeledRationalFunction<C> =
LabeledRationalFunction<C>(numerator, polynomialOne) LabeledRationalFunction<C>(numerator, polynomialOne)
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> A.LabeledRationalFunction(numerator: LabeledPolynomial<C>): LabeledRationalFunction<C> = 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") @Suppress("FunctionName")
public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> = public fun <C, A: Ring<C>> LabeledRationalFunctionSpace<C, A>.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> =
LabeledRationalFunction<C>( LabeledRationalFunction<C>(
LabeledPolynomial(numeratorCoefficients), LabeledPolynomial(numeratorCoefficients, toCheckInput = true),
polynomialOne polynomialOne
) )
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> A.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> = public fun <C, A: Ring<C>> A.LabeledRationalFunction(numeratorCoefficients: Map<Map<Symbol, UInt>, C>): LabeledRationalFunction<C> =
LabeledRationalFunction<C>( LabeledRationalFunction<C>(
LabeledPolynomial(numeratorCoefficients), LabeledPolynomial(numeratorCoefficients, toCheckInput = true),
LabeledPolynomial(mapOf(emptyMap<Symbol, UInt>() to one)) LabeledPolynomial(mapOf(emptyMap<Symbol, UInt>() to one), toCheckInput = false)
) )
public class LabeledRationalFunctionSpace<C, A: Ring<C>>( public class LabeledRationalFunctionSpace<C, A: Ring<C>>(
@ -82,38 +72,16 @@ public class LabeledRationalFunctionSpace<C, A: Ring<C>>(
numerator: LabeledPolynomial<C>, numerator: LabeledPolynomial<C>,
denominator: LabeledPolynomial<C> denominator: LabeledPolynomial<C>
): LabeledRationalFunction<C> = ): LabeledRationalFunction<C> =
LabeledRationalFunction(numerator, denominator) LabeledRationalFunction<C>(numerator, denominator)
/** /**
* Instance of zero rational function (zero of the rational functions ring). * 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). * Instance of unit polynomial (unit of the rational functions ring).
*/ */
public override val one: LabeledRationalFunction<C> = LabeledRationalFunction(polynomialOne, polynomialOne) public override val one: LabeledRationalFunction<C> = LabeledRationalFunction<C>(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
}
// TODO: Разобрать // TODO: Разобрать

View File

@ -91,13 +91,9 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
.toMutableList() .toMutableList()
.apply { .apply {
val result = getOrElse(0) { constantZero } + other val result = getOrElse(0) { constantZero } + other
val isResultZero = result.isZero()
when { if(size == 0) add(result)
size == 0 && !isResultZero -> add(result) else this[0] = result
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
} }
) )
/** /**
@ -113,13 +109,9 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
.toMutableList() .toMutableList()
.apply { .apply {
val result = getOrElse(0) { constantZero } - other val result = getOrElse(0) { constantZero } - other
val isResultZero = result.isZero()
when { if(size == 0) add(result)
size == 0 && !isResultZero -> add(result) else this[0] = result
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
} }
) )
/** /**
@ -131,7 +123,8 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
if (other == 0) zero if (other == 0) zero
else ListPolynomial( else ListPolynomial(
coefficients coefficients
.applyAndRemoveZeros { .toMutableList()
.apply {
for (deg in indices) this[deg] = this[deg] * other for (deg in indices) this[deg] = this[deg] * other
} }
) )
@ -149,13 +142,9 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
.toMutableList() .toMutableList()
.apply { .apply {
val result = this@plus + getOrElse(0) { constantZero } val result = this@plus + getOrElse(0) { constantZero }
val isResultZero = result.isZero()
when { if(size == 0) add(result)
size == 0 && !isResultZero -> add(result) else this[0] = result
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
} }
) )
/** /**
@ -173,13 +162,9 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
forEachIndexed { index, c -> if (index != 0) this[index] = -c } forEachIndexed { index, c -> if (index != 0) this[index] = -c }
val result = this@minus - getOrElse(0) { constantZero } val result = this@minus - getOrElse(0) { constantZero }
val isResultZero = result.isZero()
when { if(size == 0) add(result)
size == 0 && !isResultZero -> add(result) else this[0] = result
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
} }
) )
/** /**
@ -191,7 +176,8 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
if (this == 0) zero if (this == 0) zero
else ListPolynomial( else ListPolynomial(
other.coefficients other.coefficients
.applyAndRemoveZeros { .toMutableList()
.apply {
for (deg in indices) this[deg] = this@times * this[deg] 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. * Returns sum of the constant represented as polynomial and the polynomial.
*/ */
public override operator fun C.plus(other: ListPolynomial<C>): ListPolynomial<C> = public override operator fun C.plus(other: ListPolynomial<C>): ListPolynomial<C> =
if (this.isZero()) other with(other.coefficients) {
else with(other.coefficients) {
if (isEmpty()) ListPolynomial(listOf(this@plus)) if (isEmpty()) ListPolynomial(listOf(this@plus))
else ListPolynomial( else ListPolynomial(
toMutableList() toMutableList()
.apply { .apply {
val result = if (size == 0) this@plus else this@plus + get(0) val result = if (size == 0) this@plus else this@plus + get(0)
val isResultZero = result.isZero()
when { if(size == 0) add(result)
size == 0 && !isResultZero -> add(result) else this[0] = result
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
} }
) )
} }
@ -226,8 +207,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
* Returns difference between the constant represented as polynomial and the polynomial. * Returns difference between the constant represented as polynomial and the polynomial.
*/ */
public override operator fun C.minus(other: ListPolynomial<C>): ListPolynomial<C> = public override operator fun C.minus(other: ListPolynomial<C>): ListPolynomial<C> =
if (this.isZero()) other with(other.coefficients) {
else with(other.coefficients) {
if (isEmpty()) ListPolynomial(listOf(this@minus)) if (isEmpty()) ListPolynomial(listOf(this@minus))
else ListPolynomial( else ListPolynomial(
toMutableList() toMutableList()
@ -235,13 +215,9 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
forEachIndexed { index, c -> if (index != 0) this[index] = -c } forEachIndexed { index, c -> if (index != 0) this[index] = -c }
val result = if (size == 0) this@minus else this@minus - get(0) val result = if (size == 0) this@minus else this@minus - get(0)
val isResultZero = result.isZero()
when { if(size == 0) add(result)
size == 0 && !isResultZero -> add(result) else this[0] = result
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
} }
) )
} }
@ -249,10 +225,10 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
* Returns product of the constant represented as polynomial and the polynomial. * Returns product of the constant represented as polynomial and the polynomial.
*/ */
public override operator fun C.times(other: ListPolynomial<C>): ListPolynomial<C> = public override operator fun C.times(other: ListPolynomial<C>): ListPolynomial<C> =
if (this.isZero()) other ListPolynomial(
else ListPolynomial(
other.coefficients other.coefficients
.applyAndRemoveZeros { .toMutableList()
.apply {
for (deg in indices) this[deg] = this@times * this[deg] 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. * Returns sum of the constant represented as polynomial and the polynomial.
*/ */
public override operator fun ListPolynomial<C>.plus(other: C): ListPolynomial<C> = public override operator fun ListPolynomial<C>.plus(other: C): ListPolynomial<C> =
if (other.isZero()) this with(coefficients) {
else with(coefficients) {
if (isEmpty()) ListPolynomial(listOf(other)) if (isEmpty()) ListPolynomial(listOf(other))
else ListPolynomial( else ListPolynomial(
toMutableList() toMutableList()
.apply { .apply {
val result = if (size == 0) other else get(0) + other val result = if (size == 0) other else get(0) + other
val isResultZero = result.isZero()
when { if(size == 0) add(result)
size == 0 && !isResultZero -> add(result) else this[0] = result
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
} }
) )
} }
@ -282,20 +253,15 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
* Returns difference between the constant represented as polynomial and the polynomial. * Returns difference between the constant represented as polynomial and the polynomial.
*/ */
public override operator fun ListPolynomial<C>.minus(other: C): ListPolynomial<C> = public override operator fun ListPolynomial<C>.minus(other: C): ListPolynomial<C> =
if (other.isZero()) this with(coefficients) {
else with(coefficients) {
if (isEmpty()) ListPolynomial(listOf(-other)) if (isEmpty()) ListPolynomial(listOf(-other))
else ListPolynomial( else ListPolynomial(
toMutableList() toMutableList()
.apply { .apply {
val result = if (size == 0) other else get(0) - other val result = if (size == 0) other else get(0) - other
val isResultZero = result.isZero()
when { if(size == 0) add(result)
size == 0 && !isResultZero -> add(result) else this[0] = result
size > 1 || !isResultZero -> this[0] = result
else -> clear()
}
} }
) )
} }
@ -303,10 +269,10 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
* Returns product of the constant represented as polynomial and the polynomial. * Returns product of the constant represented as polynomial and the polynomial.
*/ */
public override operator fun ListPolynomial<C>.times(other: C): ListPolynomial<C> = public override operator fun ListPolynomial<C>.times(other: C): ListPolynomial<C> =
if (other.isZero()) this ListPolynomial(
else ListPolynomial(
coefficients coefficients
.applyAndRemoveZeros { .toMutableList()
.apply {
for (deg in indices) this[deg] = this[deg] * other 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. * Converts the constant [value] to polynomial.
*/ */
public override fun number(value: C): ListPolynomial<C> = public override fun number(value: C): ListPolynomial<C> = ListPolynomial(value)
if (value.isZero()) zero
else ListPolynomial(value)
/** /**
* Returns negation of the polynomial. * Returns negation of the polynomial.
@ -330,7 +294,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
val thisDegree = degree val thisDegree = degree
val otherDegree = other.degree val otherDegree = other.degree
return ListPolynomial( return ListPolynomial(
Coefficients(max(thisDegree, otherDegree) + 1) { List(max(thisDegree, otherDegree) + 1) {
when { when {
it > thisDegree -> other.coefficients[it] it > thisDegree -> other.coefficients[it]
it > otherDegree -> coefficients[it] it > otherDegree -> coefficients[it]
@ -346,7 +310,7 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
val thisDegree = degree val thisDegree = degree
val otherDegree = other.degree val otherDegree = other.degree
return ListPolynomial( return ListPolynomial(
Coefficients(max(thisDegree, otherDegree) + 1) { List(max(thisDegree, otherDegree) + 1) {
when { when {
it > thisDegree -> -other.coefficients[it] it > thisDegree -> -other.coefficients[it]
it > otherDegree -> coefficients[it] it > otherDegree -> coefficients[it]
@ -361,39 +325,15 @@ public open class ListPolynomialSpace<C, A : Ring<C>>(
public override operator fun ListPolynomial<C>.times(other: ListPolynomial<C>): ListPolynomial<C> { public override operator fun ListPolynomial<C>.times(other: ListPolynomial<C>): ListPolynomial<C> {
val thisDegree = degree val thisDegree = degree
val otherDegree = other.degree val otherDegree = other.degree
return when { return ListPolynomial(
thisDegree == -1 -> zero List(thisDegree + otherDegree + 1) { d ->
otherDegree == -1 -> zero (max(0, d - otherDegree)..min(thisDegree, d))
else -> .map { coefficients[it] * other.coefficients[d - it] }
ListPolynomial( .reduce { acc, rational -> acc + rational }
Coefficients(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). * 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)) 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 * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1. * zero, degree is -1.
*/ */
public override val ListPolynomial<C>.degree: Int get() = coefficients.indexOfLast { it != constantZero } public override val ListPolynomial<C>.degree: Int get() = coefficients.lastIndex
/**
* 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
}
}
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
public inline fun ListPolynomial<C>.substitute(argument: C): C = this.substitute(ring, argument) 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) public inline operator fun ListPolynomial<C>.invoke(argument: C): C = this.substitute(ring, argument)
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
public inline operator fun ListPolynomial<C>.invoke(argument: ListPolynomial<C>): ListPolynomial<C> = this.substitute(ring, argument) 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 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 numerator: ListPolynomial<C>,
public override val denominator: ListPolynomial<C> public override val denominator: ListPolynomial<C>
) : RationalFunction<C, 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 // 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") @Suppress("FunctionName")
public fun <C, A: Ring<C>> ListRationalFunctionSpace<C, A>.ListRationalFunction(numeratorCoefficients: List<C>, denominatorCoefficients: List<C>, reverse: Boolean = false): ListRationalFunction<C> = 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") ListRationalFunction<C>(
else ListRationalFunction<C>(
ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ),
ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } )
) )
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> A.ListRationalFunction(numeratorCoefficients: List<C>, denominatorCoefficients: List<C>, reverse: Boolean = false): ListRationalFunction<C> = 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") ListRationalFunction<C>(
else ListRationalFunction<C>(
ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ),
ListPolynomial( with(denominatorCoefficients) { 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") @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) 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") @Suppress("FunctionName")
internal fun <C, A: Ring<C>> A.NumberedPolynomial(coefs: Map<List<UInt>, C>, toCheckInput: Boolean = true) : NumberedPolynomial<C> { internal fun <C, A: Ring<C>> A.NumberedPolynomial(coefs: Map<List<UInt>, C>, toCheckInput: Boolean = true) : NumberedPolynomial<C> {
if (!toCheckInput) return NumberedPolynomial<C>(coefs) 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 fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value
} }
return NumberedPolynomial<C>( return NumberedPolynomial<C>(fixedCoefs)
fixedCoefs.filterValues { it != zero }
)
} }
@Suppress("FunctionName", "NOTHING_TO_INLINE") @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) 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") @Suppress("FunctionName")
internal fun <C, A: Ring<C>> A.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>, toCheckInput: Boolean = true) : NumberedPolynomial<C> { 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()) 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 fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value
} }
return NumberedPolynomial<C>( return NumberedPolynomial<C>(fixedCoefs)
fixedCoefs.filterValues { it != zero }
)
} }
@Suppress("FunctionName", "NOTHING_TO_INLINE") @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) 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") @Suppress("FunctionName")
internal fun <C, A: Ring<C>> A.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>, toCheckInput: Boolean = true) : NumberedPolynomial<C> { 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()) 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 fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value
} }
return NumberedPolynomial<C>( return NumberedPolynomial<C>(fixedCoefs)
fixedCoefs.filterValues { it != zero }
)
} }
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> A.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs, toCheckInput = true) public fun <C, A: Ring<C>> A.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs, toCheckInput = true)
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(coefs: Map<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(coefs, toCheckInput = true) 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") @Suppress("FunctionName")
public fun <C, A: Ring<C>> A.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial(pairs, toCheckInput = true) public fun <C, A: Ring<C>> A.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial(pairs, toCheckInput = true)
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(pairs: Collection<Pair<List<UInt>, C>>) : NumberedPolynomial<C> = NumberedPolynomial(pairs, toCheckInput = true) 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") @Suppress("FunctionName")
public fun <C, A: Ring<C>> A.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(*pairs, toCheckInput = true) public fun <C, A: Ring<C>> A.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(*pairs, toCheckInput = true)
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedPolynomialSpace<C, A>.NumberedPolynomial(vararg pairs: Pair<List<UInt>, C>) : NumberedPolynomial<C> = NumberedPolynomial(*pairs, toCheckInput = true) 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) //context(A)
//public fun <C, A: Ring<C>> Symbol.asNumberedPolynomial() : NumberedPolynomial<C> = NumberedPolynomial<C>(mapOf(mapOf(this to 1u) to one)) //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 { .apply {
val degs = emptyList<UInt>() val degs = emptyList<UInt>()
val result = getOrElse(degs) { constantZero } + other this[degs] = getOrElse(degs) { constantZero } + other
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
/** /**
@ -231,10 +234,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
.apply { .apply {
val degs = emptyList<UInt>() val degs = emptyList<UInt>()
val result = getOrElse(degs) { constantZero } - other this[degs] = getOrElse(degs) { constantZero } - other
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
/** /**
@ -246,7 +246,8 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
if (other == 0) zero if (other == 0) zero
else NumberedPolynomial<C>( else NumberedPolynomial<C>(
coefficients coefficients
.applyAndRemoveZeros { .toMutableMap()
.apply {
for (degs in keys) this[degs] = this[degs]!! * other for (degs in keys) this[degs] = this[degs]!! * other
} }
) )
@ -265,10 +266,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
.apply { .apply {
val degs = emptyList<UInt>() val degs = emptyList<UInt>()
val result = this@plus + getOrElse(degs) { constantZero } this[degs] = this@plus + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
/** /**
@ -285,10 +283,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
.apply { .apply {
val degs = emptyList<UInt>() val degs = emptyList<UInt>()
val result = this@minus - getOrElse(degs) { constantZero } this[degs] = this@minus - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
/** /**
@ -300,7 +295,8 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
if (this == 0) zero if (this == 0) zero
else NumberedPolynomial( else NumberedPolynomial(
other.coefficients other.coefficients
.applyAndRemoveZeros { .toMutableMap()
.apply {
for (degs in keys) this[degs] = this@times * this[degs]!! 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. * Returns sum of the constant represented as polynomial and the polynomial.
*/ */
override operator fun C.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> = override operator fun C.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
if (this.isZero()) other with(other.coefficients) {
else with(other.coefficients) {
if (isEmpty()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to this@plus)) if (isEmpty()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to this@plus))
else NumberedPolynomial<C>( else NumberedPolynomial<C>(
toMutableMap() toMutableMap()
.apply { .apply {
val degs = emptyList<UInt>() val degs = emptyList<UInt>()
val result = this@plus + getOrElse(degs) { constantZero } this[degs] = this@plus + getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
} }
@ -333,8 +325,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
* Returns difference between the constant represented as polynomial and the polynomial. * Returns difference between the constant represented as polynomial and the polynomial.
*/ */
override operator fun C.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> = override operator fun C.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
if (this.isZero()) -other with(other.coefficients) {
else with(other.coefficients) {
if (isEmpty()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to this@minus)) if (isEmpty()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to this@minus))
else NumberedPolynomial<C>( else NumberedPolynomial<C>(
toMutableMap() toMutableMap()
@ -343,10 +334,7 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
val degs = emptyList<UInt>() val degs = emptyList<UInt>()
val result = this@minus - getOrElse(degs) { constantZero } this[degs] = this@minus - getOrElse(degs) { constantZero }
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
} }
@ -354,10 +342,10 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
* Returns product of the constant represented as polynomial and the polynomial. * Returns product of the constant represented as polynomial and the polynomial.
*/ */
override operator fun C.times(other: NumberedPolynomial<C>): NumberedPolynomial<C> = override operator fun C.times(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
if (this.isZero()) zero NumberedPolynomial<C>(
else NumberedPolynomial<C>(
other.coefficients other.coefficients
.applyAndRemoveZeros { .toMutableMap()
.apply {
for (degs in keys) this[degs] = this@times * this[degs]!! 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. * Returns sum of the constant represented as polynomial and the polynomial.
*/ */
override operator fun NumberedPolynomial<C>.plus(other: C): NumberedPolynomial<C> = override operator fun NumberedPolynomial<C>.plus(other: C): NumberedPolynomial<C> =
if (other.isZero()) this with(coefficients) {
else with(coefficients) {
if (isEmpty()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to other)) if (isEmpty()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to other))
else NumberedPolynomial<C>( else NumberedPolynomial<C>(
toMutableMap() toMutableMap()
.apply { .apply {
val degs = emptyList<UInt>() val degs = emptyList<UInt>()
val result = getOrElse(degs) { constantZero } + other this[degs] = getOrElse(degs) { constantZero } + other
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
} }
@ -385,18 +369,14 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
* Returns difference between the constant represented as polynomial and the polynomial. * Returns difference between the constant represented as polynomial and the polynomial.
*/ */
override operator fun NumberedPolynomial<C>.minus(other: C): NumberedPolynomial<C> = override operator fun NumberedPolynomial<C>.minus(other: C): NumberedPolynomial<C> =
if (other.isZero()) this with(coefficients) {
else with(coefficients) {
if (isEmpty()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to other)) if (isEmpty()) NumberedPolynomial<C>(mapOf(emptyList<UInt>() to other))
else NumberedPolynomial<C>( else NumberedPolynomial<C>(
toMutableMap() toMutableMap()
.apply { .apply {
val degs = emptyList<UInt>() val degs = emptyList<UInt>()
val result = getOrElse(degs) { constantZero } - other this[degs] = getOrElse(degs) { constantZero } - other
if (result.isZero()) remove(degs)
else this[degs] = result
} }
) )
} }
@ -404,10 +384,10 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
* Returns product of the constant represented as polynomial and the polynomial. * Returns product of the constant represented as polynomial and the polynomial.
*/ */
override operator fun NumberedPolynomial<C>.times(other: C): NumberedPolynomial<C> = override operator fun NumberedPolynomial<C>.times(other: C): NumberedPolynomial<C> =
if (other.isZero()) zero NumberedPolynomial<C>(
else NumberedPolynomial<C>(
coefficients coefficients
.applyAndRemoveZeros { .toMutableMap()
.apply {
for (degs in keys) this[degs] = this[degs]!! * other 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. * Converts the constant [value] to polynomial.
*/ */
public override fun number(value: C): NumberedPolynomial<C> = public override fun number(value: C): NumberedPolynomial<C> =
if (value == 0) zero NumberedPolynomial(mapOf(emptyList<UInt>() to value))
else NumberedPolynomial(mapOf(emptyList<UInt>() to value))
/** /**
* Returns negation of the polynomial. * 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> = override operator fun NumberedPolynomial<C>.plus(other: NumberedPolynomial<C>): 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) { it.value }
other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else 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> = override operator fun NumberedPolynomial<C>.minus(other: NumberedPolynomial<C>): 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) { it.value }
other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value }
} }
@ -450,57 +429,17 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
* Returns product of the polynomials. * Returns product of the polynomials.
*/ */
override operator fun NumberedPolynomial<C>.times(other: NumberedPolynomial<C>): NumberedPolynomial<C> = override operator fun NumberedPolynomial<C>.times(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
when { NumberedPolynomial<C>(
isZero() -> zero buildMap(coefficients.size * other.coefficients.size) {
other.isZero() -> zero for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) {
else -> val degs =
NumberedPolynomial<C>( (0..max(degs1.lastIndex, degs2.lastIndex))
buildCoefficients(coefficients.size * other.coefficients.size) { .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } }
for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { val c = c1 * c2
val degs = this[degs] = if (degs in this) this[degs]!! + c else c
(0..max(degs1.lastIndex, degs2.lastIndex))
.map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } }
val c = c1 * c2
this[degs] = if (degs in this) this[degs]!! + c else 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). * 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, * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable,
* the result is `-1`. * the result is `-1`.
*/ */
public val NumberedPolynomial<C>.lastVariable: Int 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 * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1. * zero, degree is -1.
*/ */
override val NumberedPolynomial<C>.degree: Int 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 * 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. * 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> public val NumberedPolynomial<C>.degrees: List<UInt>
get() = get() =
MutableList(lastVariable + 1) { 0u }.apply { MutableList(lastVariable + 1) { 0u }.apply {
coefficients.entries.forEach { (degs, c) -> coefficients.entries.forEach { (degs, _) ->
if (c.isNotZero()) degs.forEachIndexed { index, deg -> degs.forEachIndexed { index, deg ->
this[index] = max(this[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]. * Counts degree of the polynomial by the specified [variable].
*/ */
public fun NumberedPolynomial<C>.degreeBy(variable: Int): UInt = 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]. * Counts degree of the polynomial by the specified [variables].
*/ */
public fun NumberedPolynomial<C>.degreeBy(variables: Collection<Int>): UInt = public fun NumberedPolynomial<C>.degreeBy(variables: Collection<Int>): UInt =
coefficients.entries.maxOfOrNull { (degs, c) -> coefficients.entries.maxOfOrNull { (degs, _) ->
if (c.isZero()) 0u else degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value }
} ?: 0u } ?: 0u
/** /**
* Count of variables occurring in the polynomial with positive power. If there is no such variable, * 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 public val NumberedPolynomial<C>.countOfVariables: Int
get() = get() =
MutableList(lastVariable + 1) { false }.apply { MutableList(lastVariable + 1) { false }.apply {
coefficients.entries.forEach { (degs, c) -> coefficients.entries.forEach { (degs, _) ->
if (c.isNotZero()) degs.forEachIndexed { index, deg -> degs.forEachIndexed { index, deg ->
if (deg != 0u) this[index] = true if (deg != 0u) this[index] = true
} }
} }
}.count { it } }.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") @Suppress("NOTHING_TO_INLINE")
public inline fun NumberedPolynomial<C>.substitute(argument: Map<Int, C>): NumberedPolynomial<C> = this.substitute(ring, argument) public inline fun NumberedPolynomial<C>.substitute(argument: Map<Int, C>): NumberedPolynomial<C> = this.substitute(ring, argument)
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
@ -629,35 +528,6 @@ public open class NumberedPolynomialSpace<C, A : Ring<C>>(
@JvmName("invokePolynomial") @JvmName("invokePolynomial")
public inline operator fun NumberedPolynomial<C>.invoke(argument: Map<Int, NumberedPolynomial<C>>): NumberedPolynomial<C> = this.substitute(ring, argument) 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 // TODO: Move to other constructors with context receiver
public fun C.asNumberedPolynomial() : NumberedPolynomial<C> = NumberedPolynomial<C>(mapOf(emptyList<UInt>() to this)) 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 // 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") @Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>, denominatorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> = 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") NumberedRationalFunction<C>(
else NumberedRationalFunction<C>( NumberedPolynomial(numeratorCoefficients, toCheckInput = true),
NumberedPolynomial(numeratorCoefficients), NumberedPolynomial(denominatorCoefficients, toCheckInput = true)
NumberedPolynomial(denominatorCoefficients)
) )
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> A.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>, denominatorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> = 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") NumberedRationalFunction<C>(
else NumberedRationalFunction<C>( NumberedPolynomial(numeratorCoefficients, toCheckInput = true),
NumberedPolynomial(numeratorCoefficients), NumberedPolynomial(denominatorCoefficients, toCheckInput = true)
NumberedPolynomial(denominatorCoefficients)
) )
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numerator: NumberedPolynomial<C>): NumberedRationalFunction<C> = public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numerator: NumberedPolynomial<C>): NumberedRationalFunction<C> =
NumberedRationalFunction<C>(numerator, polynomialOne) NumberedRationalFunction<C>(numerator, polynomialOne)
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> A.NumberedRationalFunction(numerator: NumberedPolynomial<C>): NumberedRationalFunction<C> = 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") @Suppress("FunctionName")
public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> = public fun <C, A: Ring<C>> NumberedRationalFunctionSpace<C, A>.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
NumberedRationalFunction<C>( NumberedRationalFunction<C>(
NumberedPolynomial(numeratorCoefficients), NumberedPolynomial(numeratorCoefficients, toCheckInput = true),
polynomialOne polynomialOne
) )
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <C, A: Ring<C>> A.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> = public fun <C, A: Ring<C>> A.NumberedRationalFunction(numeratorCoefficients: Map<List<UInt>, C>): NumberedRationalFunction<C> =
NumberedRationalFunction<C>( NumberedRationalFunction<C>(
NumberedPolynomial(numeratorCoefficients), NumberedPolynomial(numeratorCoefficients, toCheckInput = true),
NumberedPolynomial(mapOf(emptyList<UInt>() to one)) NumberedPolynomial(mapOf(emptyList<UInt>() to one), toCheckInput = false)
) )
public class NumberedRationalFunctionSpace<C, A: Ring<C>> ( 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) 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, * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable,
* the result is `-1`. * the result is `-1`.
@ -152,13 +120,13 @@ public class NumberedRationalFunctionSpace<C, A: Ring<C>> (
public val NumberedRationalFunction<C>.countOfVariables: Int public val NumberedRationalFunction<C>.countOfVariables: Int
get() = get() =
MutableList(lastVariable + 1) { false }.apply { MutableList(lastVariable + 1) { false }.apply {
numerator.coefficients.entries.forEach { (degs, c) -> numerator.coefficients.entries.forEach { (degs, _) ->
if (c.isNotZero()) degs.forEachIndexed { index, deg -> degs.forEachIndexed { index, deg ->
if (deg != 0u) this[index] = true if (deg != 0u) this[index] = true
} }
} }
denominator.coefficients.entries.forEach { (degs, c) -> denominator.coefficients.entries.forEach { (degs, _) ->
if (c.isNotZero()) degs.forEachIndexed { index, deg -> degs.forEachIndexed { index, deg ->
if (deg != 0u) this[index] = true if (deg != 0u) this[index] = true
} }
} }

View File

@ -155,31 +155,6 @@ public interface PolynomialSpace<C, P: Polynomial<C>> : Ring<P> {
@JsName("constantPower") @JsName("constantPower")
public fun power(arg: C, exponent: UInt) : C 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). * 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) 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). * 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 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 * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1. * zero, degree is -1.
*/ */
public val P.degree: Int 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 add(left: P, right: P): P = left + right
override fun multiply(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") @JsName("constantPower")
public fun power(arg: C, exponent: UInt) : C 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). * 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 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). * 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 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. * 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) 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). * 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 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 * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1. * zero, degree is -1.
*/ */
public val P.degree: Int 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 * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1. * zero, degree is -1.
@ -813,31 +687,6 @@ public interface RationalFunctionalSpaceOverPolynomialSpace<
@JvmName("constantPower") @JvmName("constantPower")
public override fun power(arg: C, exponent: UInt) : C = polynomialRing { power(arg, exponent) } 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). * 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) } 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). * Instance of zero polynomial (zero of the polynomial ring).
*/ */
@ -941,47 +765,11 @@ public interface RationalFunctionalSpaceOverPolynomialSpace<
*/ */
public override val polynomialOne: P get() = polynomialRing.one 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 * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is
* zero, degree is -1. * zero, degree is -1.
*/ */
public override val P.degree: Int get() = polynomialRing { this@degree.degree } 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 denominator
) )
public override operator fun R.div(other: Int): R { public override operator fun R.div(other: Int): R =
val otherAsConstant = constantNumber(other) constructRationalFunction(
require(otherAsConstant.isNotZero()) { "/ by zero." }
return constructRationalFunction(
numerator, numerator,
(denominator * other).also { denominator * other
check(it.isNotZero()) {
"Got zero denominator during division of rational functions to constant. It means underlying ring of polynomials is not integral domain."
}
}
) )
}
/** /**
* Returns sum of the integer represented as rational function and the rational function. * Returns sum of the integer represented as rational function and the rational function.
@ -1076,13 +857,11 @@ public abstract class PolynomialSpaceOfFractions<
other.denominator other.denominator
) )
public override operator fun Int.div(other: R): R { public override operator fun Int.div(other: R): R =
require(other.numerator.isNotZero()) { "/ by zero." } constructRationalFunction(
return constructRationalFunction(
this * other.denominator, this * other.denominator,
other.numerator other.numerator
) )
}
/** /**
* Converts the integer [value] to rational function. * Converts the integer [value] to rational function.
@ -1119,13 +898,11 @@ public abstract class PolynomialSpaceOfFractions<
other.denominator other.denominator
) )
public override operator fun C.div(other: R): R { public override operator fun C.div(other: R): R =
require(other.numerator.isNotZero()) { "/ by zero." } constructRationalFunction(
return constructRationalFunction(
this * other.denominator, this * other.denominator,
other.numerator other.numerator
) )
}
/** /**
* Returns sum of the constant represented as rational function and the rational function. * Returns sum of the constant represented as rational function and the rational function.
@ -1152,17 +929,11 @@ public abstract class PolynomialSpaceOfFractions<
denominator denominator
) )
public override operator fun R.div(other: C): R { public override operator fun R.div(other: C): R =
require(other.isNotZero()) { "/ by zero." } constructRationalFunction(
return constructRationalFunction(
numerator, numerator,
(denominator * other).also { denominator * other
check(it.isNotZero()) {
"Got zero denominator during division of rational functions to constant. It means underlying ring of polynomials is not integral domain."
}
}
) )
}
/** /**
* Converts the constant [value] to rational function. * Converts the constant [value] to rational function.
@ -1194,13 +965,11 @@ public abstract class PolynomialSpaceOfFractions<
other.denominator other.denominator
) )
public override operator fun P.div(other: R): R { public override operator fun P.div(other: R): R =
require(other.numerator.isNotZero()) { "/ by zero." } constructRationalFunction(
return constructRationalFunction(
this * other.denominator, this * other.denominator,
other.numerator other.numerator
) )
}
/** /**
* Returns sum of the polynomial represented as rational function and the rational function. * Returns sum of the polynomial represented as rational function and the rational function.
@ -1227,17 +996,11 @@ public abstract class PolynomialSpaceOfFractions<
denominator denominator
) )
public override operator fun R.div(other: P): R { public override operator fun R.div(other: P): R =
require(other.isNotZero()) { "/ by zero." } constructRationalFunction(
return constructRationalFunction(
numerator, numerator,
(denominator * other).also { denominator * other
require(it.isNotZero()) {
"Got zero denominator during division of rational functions to polynomial. It means underlying ring of polynomials is not integral domain."
}
}
) )
}
/** /**
* Converts the polynomial [value] to rational function. * Converts the polynomial [value] to rational function.
@ -1254,11 +1017,7 @@ public abstract class PolynomialSpaceOfFractions<
public override operator fun R.plus(other: R): R = public override operator fun R.plus(other: R): R =
constructRationalFunction( constructRationalFunction(
numerator * other.denominator + denominator * other.numerator, numerator * other.denominator + denominator * other.numerator,
(denominator * other.denominator).also { denominator * other.denominator
check(it.isNotZero()) {
"Got zero denominator during addition of rational functions. It means underlying ring of polynomials is not integral domain."
}
}
) )
/** /**
* Returns difference of the rational functions. * Returns difference of the rational functions.
@ -1266,11 +1025,7 @@ public abstract class PolynomialSpaceOfFractions<
public override operator fun R.minus(other: R): R = public override operator fun R.minus(other: R): R =
constructRationalFunction( constructRationalFunction(
numerator * other.denominator - denominator * other.numerator, numerator * other.denominator - denominator * other.numerator,
(denominator * other.denominator).also { denominator * other.denominator
check(it.isNotZero()) {
"Got zero denominator during subtraction of rational functions. It means underlying ring of polynomials is not integral domain."
}
}
) )
/** /**
* Returns product of the rational functions. * Returns product of the rational functions.
@ -1278,24 +1033,14 @@ public abstract class PolynomialSpaceOfFractions<
public override operator fun R.times(other: R): R = public override operator fun R.times(other: R): R =
constructRationalFunction( constructRationalFunction(
numerator * other.numerator, numerator * other.numerator,
(denominator * other.denominator).also { denominator * other.denominator
check(it.isNotZero()) {
"Got zero denominator during multiplication of rational functions. It means underlying ring of polynomials is not integral domain."
}
}
) )
public override operator fun R.div(other: R): R { public override operator fun R.div(other: R): R =
require(other.isNotZero()) { "/ by zero." } constructRationalFunction(
return constructRationalFunction(
numerator * other.denominator, numerator * other.denominator,
(denominator * other.numerator).also { denominator * other.numerator
check(it.isNotZero()) {
"Got zero denominator during division of rational functions. It means underlying ring of polynomials is not integral domain."
}
}
) )
}
/** /**
* Instance of zero rational function (zero of the rational functions ring). * 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 { public fun <C> ListPolynomial<C>.substitute(ring: Ring<C>, arg: ListPolynomial<C>) : ListPolynomial<C> = ring {
if (coefficients.isEmpty()) return ListPolynomial(emptyList()) if (coefficients.isEmpty()) return ListPolynomial(emptyList())
val thisDegree = coefficients.indexOfLast { it != zero } val thisDegree = coefficients.lastIndex
if (thisDegree == -1) return ListPolynomial(emptyList()) 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() if (argDegree == -1) return coefficients[0].asListPolynomial()
val constantZero = zero val constantZero = zero
val resultCoefs: MutableList<C> = MutableList(thisDegree * argDegree + 1) { constantZero } 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 resultDegree += argDegree
} }
with(resultCoefs) { while (isNotEmpty() && elementAt(lastIndex) == constantZero) removeAt(lastIndex) }
return ListPolynomial<C>(resultCoefs) return ListPolynomial<C>(resultCoefs)
} }
@ -168,7 +167,6 @@ public fun <C, A> ListPolynomial<C>.derivative(
ListPolynomial( ListPolynomial(
buildList(max(0, coefficients.size - 1)) { buildList(max(0, coefficients.size - 1)) {
for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) 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)) { buildList(max(0, coefficients.size - order)) {
for (deg in order.. coefficients.lastIndex) for (deg in order.. coefficients.lastIndex)
add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) 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) { buildList(coefficients.size + 1) {
add(zero) add(zero)
coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } 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) { buildList(coefficients.size + order) {
repeat(order) { add(zero) } repeat(order) { add(zero) }
coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } 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 { internal fun <C> ListPolynomial<C>.substituteRationalFunctionTakeNumerator(ring: Ring<C>, arg: ListRationalFunction<C>): ListPolynomial<C> = ring {
if (coefficients.isEmpty()) return ListPolynomial(emptyList()) if (coefficients.isEmpty()) return ListPolynomial(emptyList())
val thisDegree = coefficients.indexOfLast { it != zero } val thisDegree = coefficients.lastIndex
if (thisDegree == -1) return ListPolynomial(emptyList()) if (thisDegree == -1) return ListPolynomial(emptyList())
val thisDegreeLog2 = 31 - thisDegree.countLeadingZeroBits() val thisDegreeLog2 = 31 - thisDegree.countLeadingZeroBits()
val numeratorDegree = arg.numerator.coefficients.indexOfLast { it != zero } val numeratorDegree = arg.numerator.coefficients.lastIndex
val denominatorDegree = arg.denominator.coefficients.indexOfLast { it != zero } val denominatorDegree = arg.denominator.coefficients.lastIndex
val argDegree = max(numeratorDegree, denominatorDegree) val argDegree = max(numeratorDegree, denominatorDegree)
val constantZero = zero val constantZero = zero
val powersOf2 = buildList<Int>(thisDegreeLog2 + 1) { val powersOf2 = buildList<Int>(thisDegreeLog2 + 1) {

View File

@ -9,7 +9,7 @@ import space.kscience.kmath.test.misc.*
import kotlin.test.* import kotlin.test.*
class ListPolynomialTest { class ListPolynomialTest { // TODO: Adapt tests to changes
@Test @Test
fun test_Polynomial_Int_plus() { fun test_Polynomial_Int_plus() {
RationalField.listPolynomial { RationalField.listPolynomial {
@ -489,94 +489,6 @@ class ListPolynomialTest {
} }
} }
@Test @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() { fun test_Polynomial_degree() {
RationalField.listPolynomial { RationalField.listPolynomial {
assertEquals( 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 import kotlin.test.assertFailsWith
class ListPolynomialUtilTest { class ListPolynomialUtilTest { // TODO: Adapt tests to changes
@Test @Test
fun test_substitute_Double() { fun test_substitute_Double() {
assertEquals( assertEquals(