Feature: Polynomials and rational functions #469

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

View File

@ -87,7 +87,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
)
else LabeledPolynomialAsIs(
mapOf(this@plus to 1U) to constantOne,
emptyMap<Symbol, UInt>() to constantOne * other,
emptyMap<Symbol, UInt>() to other.asConstant(),
)
/**
* Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial.
@ -98,7 +98,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
)
else LabeledPolynomialAsIs(
mapOf(this@minus to 1U) to constantOne,
emptyMap<Symbol, UInt>() to constantOne * -other,
emptyMap<Symbol, UInt>() to (-other).asConstant(),
)
/**
* Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial.
@ -106,7 +106,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
public override operator fun Symbol.times(other: Int): LabeledPolynomial<C> =
if (other == 0) zero
else LabeledPolynomialAsIs(
mapOf(this to 1U) to constantOne * other,
mapOf(this to 1U) to other.asConstant(),
)
/**
@ -118,7 +118,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
)
else LabeledPolynomialAsIs(
mapOf(other to 1U) to constantOne,
emptyMap<Symbol, UInt>() to constantOne * this@plus,
emptyMap<Symbol, UInt>() to this@plus.asConstant(),
)
/**
* Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial.
@ -137,7 +137,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
public override operator fun Int.times(other: Symbol): LabeledPolynomial<C> =
if (this == 0) zero
else LabeledPolynomialAsIs(
mapOf(other to 1U) to constantOne * this@times,
mapOf(other to 1U) to this@times.asConstant(),
)
/**
@ -146,11 +146,11 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
*/
public override operator fun LabeledPolynomial<C>.plus(other: Int): LabeledPolynomial<C> =
if (other == 0) this
else with(coefficients) {
if (isEmpty()) other.asPolynomial()
else LabeledPolynomialAsIs(
withPutOrChanged(emptyMap(), other.asConstant()) { it -> it + other }
when {
other == 0 -> this
coefficients.isEmpty() -> other.asPolynomial()
else -> LabeledPolynomialAsIs(
coefficients.withPutOrChanged(emptyMap(), other.asConstant()) { it -> it + other }
)
}
/**
@ -159,11 +159,11 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
*/
public override operator fun LabeledPolynomial<C>.minus(other: Int): LabeledPolynomial<C> =
if (other == 0) this
else with(coefficients) {
if (isEmpty()) (-other).asPolynomial()
else LabeledPolynomialAsIs(
withPutOrChanged(emptyMap(), (-other).asConstant()) { it -> it - other }
when {
other == 0 -> this
coefficients.isEmpty() -> other.asPolynomial()
else -> LabeledPolynomialAsIs(
coefficients.withPutOrChanged(emptyMap(), (-other).asConstant()) { it -> it - other }
)
}
/**
@ -186,11 +186,11 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
*/
public override operator fun Int.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
if (this == 0) other
else with(other.coefficients) {
if (isEmpty()) this@plus.asPolynomial()
else LabeledPolynomialAsIs(
withPutOrChanged(emptyMap(), this@plus.asConstant()) { it -> this@plus + it }
when {
this == 0 -> other
other.coefficients.isEmpty() -> this@plus.asPolynomial()
else -> LabeledPolynomialAsIs(
other.coefficients.withPutOrChanged(emptyMap(), this@plus.asConstant()) { it -> this@plus + it }
)
}
/**
@ -275,12 +275,10 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns sum of the constant represented as a polynomial and the polynomial.
*/
override operator fun C.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
with(other.coefficients) {
if (isEmpty()) this@plus.asLabeledPolynomial()
else LabeledPolynomialAsIs(
withPutOrChanged(emptyMap(), this@plus) { it -> this@plus + it }
)
}
if (other.coefficients.isEmpty()) this@plus.asLabeledPolynomial()
else LabeledPolynomialAsIs(
other.coefficients.withPutOrChanged(emptyMap(), this@plus) { it -> this@plus + it }
)
/**
* Returns difference between the constant represented as a polynomial and the polynomial.
*/
@ -304,22 +302,18 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns sum of the constant represented as a polynomial and the polynomial.
*/
override operator fun LabeledPolynomial<C>.plus(other: C): LabeledPolynomial<C> =
with(coefficients) {
if (isEmpty()) other.asLabeledPolynomial()
else LabeledPolynomialAsIs(
withPutOrChanged(emptyMap(), other) { it -> it + other }
)
}
if (coefficients.isEmpty()) other.asLabeledPolynomial()
else LabeledPolynomialAsIs(
coefficients.withPutOrChanged(emptyMap(), other) { it -> it + other }
)
/**
* Returns difference between the constant represented as a polynomial and the polynomial.
*/
override operator fun LabeledPolynomial<C>.minus(other: C): LabeledPolynomial<C> =
with(coefficients) {
if (isEmpty()) other.asLabeledPolynomial()
else LabeledPolynomialAsIs(
withPutOrChanged(emptyMap(), -other) { it -> it - other }
)
}
if (coefficients.isEmpty()) other.asLabeledPolynomial()
else LabeledPolynomialAsIs(
coefficients.withPutOrChanged(emptyMap(), -other) { it -> it - other }
)
/**
* Returns product of the constant represented as a polynomial and the polynomial.
*/
@ -382,12 +376,10 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns sum of the variable represented as a monic monomial and the polynomial.
*/
public override operator fun Symbol.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
with(other.coefficients) {
if (isEmpty()) this@plus.asPolynomial()
else LabeledPolynomialAsIs(
withPutOrChanged(mapOf(this@plus to 1U), constantOne) { it -> constantOne + it }
)
}
if (other.coefficients.isEmpty()) this@plus.asPolynomial()
else LabeledPolynomialAsIs(
other.coefficients.withPutOrChanged(mapOf(this@plus to 1U), constantOne) { it -> constantOne + it }
)
/**
* Returns difference between the variable represented as a monic monomial and the polynomial.
*/
@ -412,22 +404,18 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* Returns sum of the polynomial and the variable represented as a monic monomial.
*/
public override operator fun LabeledPolynomial<C>.plus(other: Symbol): LabeledPolynomial<C> =
with(coefficients) {
if (isEmpty()) other.asPolynomial()
else LabeledPolynomialAsIs(
withPutOrChanged(mapOf(other to 1U), constantOne) { it -> it + constantOne }
)
}
if (coefficients.isEmpty()) other.asPolynomial()
else LabeledPolynomialAsIs(
coefficients.withPutOrChanged(mapOf(other to 1U), constantOne) { it -> it + constantOne }
)
/**
* Returns difference between the polynomial and the variable represented as a monic monomial.
*/
public override operator fun LabeledPolynomial<C>.minus(other: Symbol): LabeledPolynomial<C> =
with(coefficients) {
if (isEmpty()) other.asPolynomial()
else LabeledPolynomialAsIs(
withPutOrChanged(mapOf(other to 1U), -constantOne) { it -> it - constantOne }
)
}
if (coefficients.isEmpty()) other.asPolynomial()
else LabeledPolynomialAsIs(
coefficients.withPutOrChanged(mapOf(other to 1U), -constantOne) { it -> it - constantOne }
)
/**
* Returns product of the polynomial and the variable represented as a monic monomial.
*/

View File

@ -69,10 +69,9 @@ public class NumberedPolynomialSpace<C, A : Ring<C>>(
*/
public override operator fun NumberedPolynomial<C>.plus(other: Int): NumberedPolynomial<C> =
if (other == 0) this
else
NumberedPolynomialAsIs(
coefficients.withPutOrChanged(emptyList(), other.asConstant()) { it -> it + other }
)
else NumberedPolynomialAsIs(
coefficients.withPutOrChanged(emptyList(), other.asConstant()) { it -> it + other }
)
/**
* Returns difference between the polynomial and the integer represented as a polynomial.
*
@ -80,10 +79,9 @@ public class NumberedPolynomialSpace<C, A : Ring<C>>(
*/
public override operator fun NumberedPolynomial<C>.minus(other: Int): NumberedPolynomial<C> =
if (other == 0) this
else
NumberedPolynomialAsIs(
coefficients.withPutOrChanged(emptyList(), (-other).asConstant()) { it -> it - other }
)
else NumberedPolynomialAsIs(
coefficients.withPutOrChanged(emptyList(), (-other).asConstant()) { it -> it - other }
)
/**
* Returns product of the polynomial and the integer represented as a polynomial.
*
@ -105,31 +103,25 @@ public class NumberedPolynomialSpace<C, A : Ring<C>>(
*/
public override operator fun Int.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
if (this == 0) other
else
NumberedPolynomialAsIs(
other.coefficients.withPutOrChanged(emptyList(), this@plus.asConstant()) { it -> this@plus + it }
)
else NumberedPolynomialAsIs(
other.coefficients.withPutOrChanged(emptyList(), this@plus.asConstant()) { it -> this@plus + it }
)
/**
* Returns difference between the integer represented as a polynomial and the polynomial.
*
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
*/
public override operator fun Int.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
NumberedPolynomialAsIs(
other.coefficients
.toMutableMap()
.apply {
if (this@minus == 0) {
forEach { (key, value) -> this[key] = -value }
} else {
forEach { (key, value) -> if (key.isNotEmpty()) this[key] = -value }
val degs = emptyList<UInt>()
this[degs] = this@minus - getOrElse(degs) { constantZero }
}
when {
this == 0 -> -other
other.coefficients.isEmpty() -> this.asPolynomial()
else -> NumberedPolynomialAsIs(
buildMap(other.coefficients.size + 1) {
put(emptyList(), other.coefficients.computeOnOrElse(emptyList(), { this@minus.asConstant() }, { it -> this@minus - it}))
other.coefficients.copyMapToBy(this, { _, c -> -c }) { currentC, _ -> currentC }
}
)
}
/**
* Returns product of the integer represented as a polynomial and the polynomial.
*
@ -148,29 +140,21 @@ public class NumberedPolynomialSpace<C, A : Ring<C>>(
* Returns sum of the constant represented as a polynomial and the polynomial.
*/
override operator fun C.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
with(other.coefficients) {
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to this@plus))
else NumberedPolynomialAsIs(
withPutOrChanged(emptyList(), this@plus) { it -> this@plus + it }
)
}
if (other.coefficients.isEmpty()) this@plus.asPolynomial()
else NumberedPolynomialAsIs(
other.coefficients.withPutOrChanged(emptyList(), this@plus) { it -> this@plus + it }
)
/**
* Returns difference between the constant represented as a polynomial and the polynomial.
*/
override operator fun C.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
with(other.coefficients) {
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to this@minus))
else NumberedPolynomialAsIs(
toMutableMap()
.apply {
forEach { (degs, c) -> if (degs.isNotEmpty()) this[degs] = -c }
val degs = emptyList<UInt>()
this[degs] = this@minus - getOrElse(degs) { constantZero }
}
)
}
if (other.coefficients.isEmpty()) this@minus.asPolynomial()
else NumberedPolynomialAsIs(
buildMap(other.coefficients.size) {
put(emptyList(), other.coefficients.computeOnOrElse(emptyList(), this@minus) { it -> this@minus - it })
other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, _ -> currentC })
}
)
/**
* Returns product of the constant represented as a polynomial and the polynomial.
*/
@ -183,22 +167,18 @@ public class NumberedPolynomialSpace<C, A : Ring<C>>(
* Returns sum of the constant represented as a polynomial and the polynomial.
*/
override operator fun NumberedPolynomial<C>.plus(other: C): NumberedPolynomial<C> =
with(coefficients) {
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to other))
else NumberedPolynomialAsIs(
withPutOrChanged(emptyList(), other) { it -> it + other }
)
}
if (coefficients.isEmpty()) other.asPolynomial()
else NumberedPolynomialAsIs(
coefficients.withPutOrChanged(emptyList(), other) { it -> it + other }
)
/**
* Returns difference between the constant represented as a polynomial and the polynomial.
*/
override operator fun NumberedPolynomial<C>.minus(other: C): NumberedPolynomial<C> =
with(coefficients) {
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to other))
else NumberedPolynomialAsIs(
withPutOrChanged(emptyList(), -other) { it -> it - other }
)
}
if (coefficients.isEmpty()) other.asPolynomial()
else NumberedPolynomialAsIs(
coefficients.withPutOrChanged(emptyList(), -other) { it -> it - other }
)
/**
* Returns product of the constant represented as a polynomial and the polynomial.
*/
@ -264,13 +244,7 @@ public class NumberedPolynomialSpace<C, A : Ring<C>>(
/**
* Instance of unit polynomial (unit of the polynomial ring).
*/
override val one: NumberedPolynomial<C> by lazy {
NumberedPolynomialAsIs(
mapOf(
emptyList<UInt>() to constantOne // 1 * x_1^0 * x_2^0 * ...
)
)
}
override val one: NumberedPolynomial<C> by lazy { NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to constantOne)) }
/**
* Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable,

View File

@ -9,6 +9,40 @@ import kotlin.contracts.InvocationKind.*
import kotlin.contracts.contract
// TODO: Docs
internal inline fun <K, V, R> Map<in K, V>.computeOn(key: K, compute: (V?) -> R): R {
contract {
callsInPlace(compute, EXACTLY_ONCE)
}
return compute(get(key))
}
// TODO: Docs
internal inline fun <K, V, R> Map<K, V>.computeOnOrElse(key: K, defaultResult: () -> R, compute: (value: V) -> R): R {
contract {
callsInPlace(defaultResult, AT_MOST_ONCE)
callsInPlace(compute, AT_MOST_ONCE)
}
@Suppress("UNCHECKED_CAST")
return (if (key !in this) defaultResult() else compute(get(key) as V))
}
// TODO: Docs
internal inline fun <K, V, R> Map<K, V>.computeOnOrElse(key: K, defaultResult: R, compute: (value: V) -> R): R {
contract {
callsInPlace(compute, AT_MOST_ONCE)
}
return computeOnOrElse(key, { defaultResult }, compute)
}
// TODO: Docs
internal inline fun <K, V, R> Map<K, V>.computeOnOrElse(key: K, defaultResult: R, compute: (key: K, value: V) -> R): R {
contract {
callsInPlace(compute, AT_MOST_ONCE)
}
return computeOnOrElse(key, { defaultResult }, { it -> compute(key, it) })
}
/**
* Applies the [transformation][transform] to the value corresponding to the given [key] or null instead if it's not
* present.
@ -21,7 +55,7 @@ internal inline fun <K, V> MutableMap<in K, V>.applyToKey(key: K, transform: (cu
contract {
callsInPlace(transform, EXACTLY_ONCE)
}
return transform(get(key)).also { this[key] = it }
return computeOn(key, transform).also { this[key] = it }
}
/**
@ -39,8 +73,7 @@ internal inline fun <K, V> MutableMap<K, V>.putOrChange(key: K, valueOnPut: () -
callsInPlace(valueOnPut, AT_MOST_ONCE)
callsInPlace(transformOnChange, AT_MOST_ONCE)
}
@Suppress("UNCHECKED_CAST")
return (if (key !in this) valueOnPut() else transformOnChange(get(key) as V)).also { this[key] = it }
return computeOnOrElse(key, valueOnPut, transformOnChange).also { this[key] = it }
}
/**