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( else LabeledPolynomialAsIs(
mapOf(this@plus to 1U) to constantOne, 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. * 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( else LabeledPolynomialAsIs(
mapOf(this@minus to 1U) to constantOne, 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. * 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> = public override operator fun Symbol.times(other: Int): LabeledPolynomial<C> =
if (other == 0) zero if (other == 0) zero
else LabeledPolynomialAsIs( 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( else LabeledPolynomialAsIs(
mapOf(other to 1U) to constantOne, 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. * 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> = public override operator fun Int.times(other: Symbol): LabeledPolynomial<C> =
if (this == 0) zero if (this == 0) zero
else LabeledPolynomialAsIs( 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]. * The operation is equivalent to adding [other] copies of unit polynomial to [this].
*/ */
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 when {
else with(coefficients) { other == 0 -> this
if (isEmpty()) other.asPolynomial() coefficients.isEmpty() -> other.asPolynomial()
else LabeledPolynomialAsIs( else -> LabeledPolynomialAsIs(
withPutOrChanged(emptyMap(), other.asConstant()) { it -> it + other } 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]. * The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
*/ */
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 when {
else with(coefficients) { other == 0 -> this
if (isEmpty()) (-other).asPolynomial() coefficients.isEmpty() -> other.asPolynomial()
else LabeledPolynomialAsIs( else -> LabeledPolynomialAsIs(
withPutOrChanged(emptyMap(), (-other).asConstant()) { it -> it - other } 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]. * The operation is equivalent to adding [this] copies of unit polynomial to [other].
*/ */
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 when {
else with(other.coefficients) { this == 0 -> other
if (isEmpty()) this@plus.asPolynomial() other.coefficients.isEmpty() -> this@plus.asPolynomial()
else LabeledPolynomialAsIs( else -> LabeledPolynomialAsIs(
withPutOrChanged(emptyMap(), this@plus.asConstant()) { it -> this@plus + it } 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. * Returns sum of the constant represented as a polynomial and the polynomial.
*/ */
override operator fun C.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> = override operator fun C.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
with(other.coefficients) { if (other.coefficients.isEmpty()) this@plus.asLabeledPolynomial()
if (isEmpty()) this@plus.asLabeledPolynomial()
else LabeledPolynomialAsIs( else LabeledPolynomialAsIs(
withPutOrChanged(emptyMap(), this@plus) { it -> this@plus + it } other.coefficients.withPutOrChanged(emptyMap(), this@plus) { it -> this@plus + it }
) )
}
/** /**
* Returns difference between the constant represented as a polynomial and the polynomial. * 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. * Returns sum of the constant represented as a polynomial and the polynomial.
*/ */
override operator fun LabeledPolynomial<C>.plus(other: C): LabeledPolynomial<C> = override operator fun LabeledPolynomial<C>.plus(other: C): LabeledPolynomial<C> =
with(coefficients) { if (coefficients.isEmpty()) other.asLabeledPolynomial()
if (isEmpty()) other.asLabeledPolynomial()
else LabeledPolynomialAsIs( else LabeledPolynomialAsIs(
withPutOrChanged(emptyMap(), other) { it -> it + other } coefficients.withPutOrChanged(emptyMap(), other) { it -> it + other }
) )
}
/** /**
* Returns difference between the constant represented as a polynomial and the polynomial. * Returns difference between the constant represented as a polynomial and the polynomial.
*/ */
override operator fun LabeledPolynomial<C>.minus(other: C): LabeledPolynomial<C> = override operator fun LabeledPolynomial<C>.minus(other: C): LabeledPolynomial<C> =
with(coefficients) { if (coefficients.isEmpty()) other.asLabeledPolynomial()
if (isEmpty()) other.asLabeledPolynomial()
else LabeledPolynomialAsIs( else LabeledPolynomialAsIs(
withPutOrChanged(emptyMap(), -other) { it -> it - other } coefficients.withPutOrChanged(emptyMap(), -other) { it -> it - other }
) )
}
/** /**
* Returns product of the constant represented as a polynomial and the polynomial. * 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. * Returns sum of the variable represented as a monic monomial and the polynomial.
*/ */
public override operator fun Symbol.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> = public override operator fun Symbol.plus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
with(other.coefficients) { if (other.coefficients.isEmpty()) this@plus.asPolynomial()
if (isEmpty()) this@plus.asPolynomial()
else LabeledPolynomialAsIs( else LabeledPolynomialAsIs(
withPutOrChanged(mapOf(this@plus to 1U), constantOne) { it -> constantOne + it } 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. * 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. * Returns sum of the polynomial and the variable represented as a monic monomial.
*/ */
public override operator fun LabeledPolynomial<C>.plus(other: Symbol): LabeledPolynomial<C> = public override operator fun LabeledPolynomial<C>.plus(other: Symbol): LabeledPolynomial<C> =
with(coefficients) { if (coefficients.isEmpty()) other.asPolynomial()
if (isEmpty()) other.asPolynomial()
else LabeledPolynomialAsIs( else LabeledPolynomialAsIs(
withPutOrChanged(mapOf(other to 1U), constantOne) { it -> it + constantOne } coefficients.withPutOrChanged(mapOf(other to 1U), constantOne) { it -> it + constantOne }
) )
}
/** /**
* Returns difference between the polynomial and the variable represented as a monic monomial. * Returns difference between the polynomial and the variable represented as a monic monomial.
*/ */
public override operator fun LabeledPolynomial<C>.minus(other: Symbol): LabeledPolynomial<C> = public override operator fun LabeledPolynomial<C>.minus(other: Symbol): LabeledPolynomial<C> =
with(coefficients) { if (coefficients.isEmpty()) other.asPolynomial()
if (isEmpty()) other.asPolynomial()
else LabeledPolynomialAsIs( else LabeledPolynomialAsIs(
withPutOrChanged(mapOf(other to 1U), -constantOne) { it -> it - constantOne } coefficients.withPutOrChanged(mapOf(other to 1U), -constantOne) { it -> it - constantOne }
) )
}
/** /**
* Returns product of the polynomial and the variable represented as a monic monomial. * Returns product of the polynomial and the variable represented as a monic monomial.
*/ */

View File

@ -69,8 +69,7 @@ public class NumberedPolynomialSpace<C, A : Ring<C>>(
*/ */
public override operator fun NumberedPolynomial<C>.plus(other: Int): NumberedPolynomial<C> = public override operator fun NumberedPolynomial<C>.plus(other: Int): NumberedPolynomial<C> =
if (other == 0) this if (other == 0) this
else else NumberedPolynomialAsIs(
NumberedPolynomialAsIs(
coefficients.withPutOrChanged(emptyList(), other.asConstant()) { it -> it + other } coefficients.withPutOrChanged(emptyList(), other.asConstant()) { it -> it + other }
) )
/** /**
@ -80,8 +79,7 @@ public class NumberedPolynomialSpace<C, A : Ring<C>>(
*/ */
public override operator fun NumberedPolynomial<C>.minus(other: Int): NumberedPolynomial<C> = public override operator fun NumberedPolynomial<C>.minus(other: Int): NumberedPolynomial<C> =
if (other == 0) this if (other == 0) this
else else NumberedPolynomialAsIs(
NumberedPolynomialAsIs(
coefficients.withPutOrChanged(emptyList(), (-other).asConstant()) { it -> it - other } coefficients.withPutOrChanged(emptyList(), (-other).asConstant()) { it -> it - other }
) )
/** /**
@ -105,8 +103,7 @@ public class NumberedPolynomialSpace<C, A : Ring<C>>(
*/ */
public override operator fun Int.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> = public override operator fun Int.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
if (this == 0) other if (this == 0) other
else else NumberedPolynomialAsIs(
NumberedPolynomialAsIs(
other.coefficients.withPutOrChanged(emptyList(), this@plus.asConstant()) { it -> this@plus + it } other.coefficients.withPutOrChanged(emptyList(), this@plus.asConstant()) { it -> this@plus + it }
) )
/** /**
@ -115,21 +112,16 @@ public class NumberedPolynomialSpace<C, A : Ring<C>>(
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. * The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
*/ */
public override operator fun Int.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> = public override operator fun Int.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
NumberedPolynomialAsIs( when {
other.coefficients this == 0 -> -other
.toMutableMap() other.coefficients.isEmpty() -> this.asPolynomial()
.apply { else -> NumberedPolynomialAsIs(
if (this@minus == 0) { buildMap(other.coefficients.size + 1) {
forEach { (key, value) -> this[key] = -value } put(emptyList(), other.coefficients.computeOnOrElse(emptyList(), { this@minus.asConstant() }, { it -> this@minus - it}))
} else { other.coefficients.copyMapToBy(this, { _, c -> -c }) { currentC, _ -> currentC }
forEach { (key, value) -> if (key.isNotEmpty()) this[key] = -value }
val degs = emptyList<UInt>()
this[degs] = this@minus - getOrElse(degs) { constantZero }
}
} }
) )
}
/** /**
* Returns product of the integer represented as a polynomial and the polynomial. * 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. * Returns sum of the constant represented as a polynomial and the polynomial.
*/ */
override operator fun C.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> = override operator fun C.plus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
with(other.coefficients) { if (other.coefficients.isEmpty()) this@plus.asPolynomial()
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to this@plus))
else NumberedPolynomialAsIs( else NumberedPolynomialAsIs(
withPutOrChanged(emptyList(), this@plus) { it -> this@plus + it } other.coefficients.withPutOrChanged(emptyList(), this@plus) { it -> this@plus + it }
) )
}
/** /**
* Returns difference between the constant represented as a polynomial and the polynomial. * Returns difference between the constant represented as a polynomial and the polynomial.
*/ */
override operator fun C.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> = override operator fun C.minus(other: NumberedPolynomial<C>): NumberedPolynomial<C> =
with(other.coefficients) { if (other.coefficients.isEmpty()) this@minus.asPolynomial()
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to this@minus))
else NumberedPolynomialAsIs( else NumberedPolynomialAsIs(
toMutableMap() buildMap(other.coefficients.size) {
.apply { put(emptyList(), other.coefficients.computeOnOrElse(emptyList(), this@minus) { it -> this@minus - it })
forEach { (degs, c) -> if (degs.isNotEmpty()) this[degs] = -c } other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, _ -> currentC })
val degs = emptyList<UInt>()
this[degs] = this@minus - getOrElse(degs) { constantZero }
} }
) )
}
/** /**
* Returns product of the constant represented as a polynomial and the polynomial. * 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. * Returns sum of the constant represented as a polynomial and the polynomial.
*/ */
override operator fun NumberedPolynomial<C>.plus(other: C): NumberedPolynomial<C> = override operator fun NumberedPolynomial<C>.plus(other: C): NumberedPolynomial<C> =
with(coefficients) { if (coefficients.isEmpty()) other.asPolynomial()
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to other))
else NumberedPolynomialAsIs( else NumberedPolynomialAsIs(
withPutOrChanged(emptyList(), other) { it -> it + other } coefficients.withPutOrChanged(emptyList(), other) { it -> it + other }
) )
}
/** /**
* Returns difference between the constant represented as a polynomial and the polynomial. * Returns difference between the constant represented as a polynomial and the polynomial.
*/ */
override operator fun NumberedPolynomial<C>.minus(other: C): NumberedPolynomial<C> = override operator fun NumberedPolynomial<C>.minus(other: C): NumberedPolynomial<C> =
with(coefficients) { if (coefficients.isEmpty()) other.asPolynomial()
if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to other))
else NumberedPolynomialAsIs( else NumberedPolynomialAsIs(
withPutOrChanged(emptyList(), -other) { it -> it - other } coefficients.withPutOrChanged(emptyList(), -other) { it -> it - other }
) )
}
/** /**
* Returns product of the constant represented as a polynomial and the polynomial. * 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). * Instance of unit polynomial (unit of the polynomial ring).
*/ */
override val one: NumberedPolynomial<C> by lazy { override val one: NumberedPolynomial<C> by lazy { NumberedPolynomialAsIs(mapOf(emptyList<UInt>() to constantOne)) }
NumberedPolynomialAsIs(
mapOf(
emptyList<UInt>() to constantOne // 1 * x_1^0 * x_2^0 * ...
)
)
}
/** /**
* 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,

View File

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