forked from kscience/kmath
Added support of power
function to abstract structures.
Implemented exponentiation by squaring as default implementation of `power`. Updated docs in algebraicStub.kt and updated realisations in it.
This commit is contained in:
parent
9aa131a9c6
commit
24944cdb16
@ -71,19 +71,19 @@ public interface AbstractPolynomialSpace<C, P: AbstractPolynomial<C>> : Ring<P>
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
|
||||
*/
|
||||
public operator fun P.plus(other: Int): P = optimizedAddMultiplied(this, one, other)
|
||||
public operator fun P.plus(other: Int): P = addMultipliedBySquaring(this, one, other)
|
||||
/**
|
||||
* Returns difference between the polynomial and the integer represented as polynomial.
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
|
||||
*/
|
||||
public operator fun P.minus(other: Int): P = optimizedAddMultiplied(this, one, -other)
|
||||
public operator fun P.minus(other: Int): P = addMultipliedBySquaring(this, one, -other)
|
||||
/**
|
||||
* Returns product of the polynomial and the integer represented as polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
public operator fun P.times(other: Int): P = optimizedMultiply(this, other)
|
||||
public operator fun P.times(other: Int): P = multiplyBySquaring(this, other)
|
||||
// endregion
|
||||
|
||||
// region Integer-polynomial relation
|
||||
@ -92,19 +92,19 @@ public interface AbstractPolynomialSpace<C, P: AbstractPolynomial<C>> : Ring<P>
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
|
||||
*/
|
||||
public operator fun Int.plus(other: P): P = optimizedAddMultiplied(other, one, this)
|
||||
public operator fun Int.plus(other: P): P = addMultipliedBySquaring(other, one, this)
|
||||
/**
|
||||
* Returns difference between the integer represented as polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
|
||||
*/
|
||||
public operator fun Int.minus(other: P): P = optimizedAddMultiplied(-other, one, this)
|
||||
public operator fun Int.minus(other: P): P = addMultipliedBySquaring(-other, one, this)
|
||||
/**
|
||||
* Returns product of the integer represented as polynomial and the polynomial.
|
||||
*
|
||||
* The operation is equivalent to sum of [this] copies of [other].
|
||||
*/
|
||||
public operator fun Int.times(other: P): P = optimizedMultiply(other, this)
|
||||
public operator fun Int.times(other: P): P = multiplyBySquaring(other, this)
|
||||
// endregion
|
||||
|
||||
// region Constant-constant relation
|
||||
@ -138,6 +138,12 @@ public interface AbstractPolynomialSpace<C, P: AbstractPolynomial<C>> : Ring<P>
|
||||
@JvmName("constantTimes")
|
||||
@JsName("constantTimes")
|
||||
public operator fun C.times(other: C): C
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/
|
||||
@JvmName("constantPower")
|
||||
@JsName("constantPower")
|
||||
public fun power(arg: C, exponent: UInt) : C
|
||||
|
||||
/**
|
||||
* Check if the instant is zero constant.
|
||||
@ -225,6 +231,10 @@ public interface AbstractPolynomialSpace<C, P: AbstractPolynomial<C>> : Ring<P>
|
||||
* Returns product of the polynomials.
|
||||
*/
|
||||
public override operator fun P.times(other: P): P
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/
|
||||
public override fun power(arg: P, exponent: UInt) : P = exponentiationBySquaring(arg, exponent)
|
||||
|
||||
/**
|
||||
* Check if the instant is zero polynomial.
|
||||
@ -331,19 +341,19 @@ public interface AbstractPolynomialSpaceOverRing<C, P: AbstractPolynomial<C>, A:
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit of underlying ring to [this].
|
||||
*/
|
||||
public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) }
|
||||
public override operator fun C.plus(other: Int): C = ring { addMultipliedBySquaring(this@plus, one, other) }
|
||||
/**
|
||||
* Returns difference between the constant and the integer represented as constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this].
|
||||
*/
|
||||
public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) }
|
||||
public override operator fun C.minus(other: Int): C = ring { addMultipliedBySquaring(this@minus, one, -other) }
|
||||
/**
|
||||
* Returns product of the constant and the integer represented as constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) }
|
||||
public override operator fun C.times(other: Int): C = ring { multiplyBySquaring(this@times, other) }
|
||||
// endregion
|
||||
|
||||
// region Integer-constant relation
|
||||
@ -352,19 +362,19 @@ public interface AbstractPolynomialSpaceOverRing<C, P: AbstractPolynomial<C>, A:
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit of underlying ring to [other].
|
||||
*/
|
||||
public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) }
|
||||
public override operator fun Int.plus(other: C): C = ring { addMultipliedBySquaring(other, one, this@plus) }
|
||||
/**
|
||||
* Returns difference between the integer represented as constant (member of underlying ring) and the constant.
|
||||
*
|
||||
* The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other].
|
||||
*/
|
||||
public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) }
|
||||
public override operator fun Int.minus(other: C): C = ring { addMultipliedBySquaring(-other, one, this@minus) }
|
||||
/**
|
||||
* Returns product of the integer represented as constant (member of underlying ring) and the constant.
|
||||
*
|
||||
* The operation is equivalent to sum of [this] copies of [other].
|
||||
*/
|
||||
public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) }
|
||||
public override operator fun Int.times(other: C): C = ring { multiplyBySquaring(other, this@times) }
|
||||
// endregion
|
||||
|
||||
// region Constant-constant relation
|
||||
@ -388,6 +398,11 @@ public interface AbstractPolynomialSpaceOverRing<C, P: AbstractPolynomial<C>, A:
|
||||
*/
|
||||
@JvmName("constantTimes")
|
||||
public override operator fun C.times(other: C): C = ring { this@times * other }
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/
|
||||
@JvmName("constantPower")
|
||||
override fun power(arg: C, exponent: UInt): C = ring { power(arg, exponent) }
|
||||
|
||||
/**
|
||||
* Instance of zero constant (zero of the underlying ring).
|
||||
|
@ -120,19 +120,19 @@ public interface AbstractRationalFunctionalSpace<C, P: AbstractPolynomial<C>, R:
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit polynomial to [this].
|
||||
*/
|
||||
public operator fun R.plus(other: Int): R = optimizedAddMultiplied(this, one, other)
|
||||
public operator fun R.plus(other: Int): R = addMultipliedBySquaring(this, one, other)
|
||||
/**
|
||||
* Returns difference between the rational function and the integer represented as rational function.
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit polynomial from [this].
|
||||
*/
|
||||
public operator fun R.minus(other: Int): R = optimizedAddMultiplied(this, one, -other)
|
||||
public operator fun R.minus(other: Int): R = addMultipliedBySquaring(this, one, -other)
|
||||
/**
|
||||
* Returns product of the rational function and the integer represented as rational function.
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
public operator fun R.times(other: Int): R = optimizedMultiply(this, other)
|
||||
public operator fun R.times(other: Int): R = multiplyBySquaring(this, other)
|
||||
// endregion
|
||||
|
||||
// region Integer-Rational relation
|
||||
@ -141,19 +141,19 @@ public interface AbstractRationalFunctionalSpace<C, P: AbstractPolynomial<C>, R:
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit polynomial to [other].
|
||||
*/
|
||||
public operator fun Int.plus(other: R): R = optimizedAddMultiplied(other, one, this)
|
||||
public operator fun Int.plus(other: R): R = addMultipliedBySquaring(other, one, this)
|
||||
/**
|
||||
* Returns difference between the integer represented as rational function and the rational function.
|
||||
*
|
||||
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
|
||||
*/
|
||||
public operator fun Int.minus(other: R): R = optimizedAddMultiplied(-other, one, this)
|
||||
public operator fun Int.minus(other: R): R = addMultipliedBySquaring(-other, one, this)
|
||||
/**
|
||||
* Returns product of the integer represented as rational function and the rational function.
|
||||
*
|
||||
* The operation is equivalent to sum of [this] copies of [other].
|
||||
*/
|
||||
public operator fun Int.times(other: R): R = optimizedMultiply(other, this)
|
||||
public operator fun Int.times(other: R): R = multiplyBySquaring(other, this)
|
||||
// endregion
|
||||
|
||||
// region Constant-constant relation
|
||||
@ -187,6 +187,12 @@ public interface AbstractRationalFunctionalSpace<C, P: AbstractPolynomial<C>, R:
|
||||
@JvmName("constantTimes")
|
||||
@JsName("constantTimes")
|
||||
public operator fun C.times(other: C): C
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/
|
||||
@JvmName("constantPower")
|
||||
@JsName("constantPower")
|
||||
public fun power(arg: C, exponent: UInt) : C
|
||||
|
||||
/**
|
||||
* Check if the instant is zero constant.
|
||||
@ -274,6 +280,10 @@ public interface AbstractRationalFunctionalSpace<C, P: AbstractPolynomial<C>, R:
|
||||
* Returns product of the polynomials.
|
||||
*/
|
||||
public operator fun P.times(other: P): P
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/
|
||||
public fun power(arg: P, exponent: UInt) : P
|
||||
|
||||
/**
|
||||
* Check if the instant is zero polynomial.
|
||||
@ -400,6 +410,10 @@ public interface AbstractRationalFunctionalSpace<C, P: AbstractPolynomial<C>, R:
|
||||
* Returns product of the rational functions.
|
||||
*/
|
||||
public override operator fun R.times(other: R): R
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/
|
||||
public override fun power(arg: R, exponent: UInt) : R = exponentiationBySquaring(arg, exponent)
|
||||
|
||||
/**
|
||||
* Check if the instant is zero rational function.
|
||||
@ -536,19 +550,19 @@ public interface AbstractRationalFunctionalSpaceOverRing<C, P: AbstractPolynomia
|
||||
*
|
||||
* The operation is equivalent to adding [other] copies of unit of underlying ring to [this].
|
||||
*/
|
||||
public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) }
|
||||
public override operator fun C.plus(other: Int): C = ring { addMultipliedBySquaring(this@plus, one, other) }
|
||||
/**
|
||||
* Returns difference between the constant and the integer represented as constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this].
|
||||
*/
|
||||
public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) }
|
||||
public override operator fun C.minus(other: Int): C = ring { addMultipliedBySquaring(this@minus, one, -other) }
|
||||
/**
|
||||
* Returns product of the constant and the integer represented as constant (member of underlying ring).
|
||||
*
|
||||
* The operation is equivalent to sum of [other] copies of [this].
|
||||
*/
|
||||
public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) }
|
||||
public override operator fun C.times(other: Int): C = ring { multiplyBySquaring(this@times, other) }
|
||||
// endregion
|
||||
|
||||
// region Integer-constant relation
|
||||
@ -557,19 +571,19 @@ public interface AbstractRationalFunctionalSpaceOverRing<C, P: AbstractPolynomia
|
||||
*
|
||||
* The operation is equivalent to adding [this] copies of unit of underlying ring to [other].
|
||||
*/
|
||||
public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) }
|
||||
public override operator fun Int.plus(other: C): C = ring { addMultipliedBySquaring(other, one, this@plus) }
|
||||
/**
|
||||
* Returns difference between the integer represented as constant (member of underlying ring) and the constant.
|
||||
*
|
||||
* The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other].
|
||||
*/
|
||||
public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) }
|
||||
public override operator fun Int.minus(other: C): C = ring { addMultipliedBySquaring(-other, one, this@minus) }
|
||||
/**
|
||||
* Returns product of the integer represented as constant (member of underlying ring) and the constant.
|
||||
*
|
||||
* The operation is equivalent to sum of [this] copies of [other].
|
||||
*/
|
||||
public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) }
|
||||
public override operator fun Int.times(other: C): C = ring { multiplyBySquaring(other, this@times) }
|
||||
// endregion
|
||||
|
||||
// region Constant-constant relation
|
||||
@ -598,6 +612,11 @@ public interface AbstractRationalFunctionalSpaceOverRing<C, P: AbstractPolynomia
|
||||
*/
|
||||
@JvmName("constantTimes")
|
||||
public override operator fun C.times(other: C): C = ring { this@times * other }
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/
|
||||
@JvmName("constantPower")
|
||||
public override fun power(arg: C, exponent: UInt) : C = ring { power(arg, exponent) }
|
||||
|
||||
/**
|
||||
* Instance of zero constant (zero of the underlying ring).
|
||||
@ -740,6 +759,11 @@ public interface AbstractRationalFunctionalSpaceOverPolynomialSpace<
|
||||
*/
|
||||
@JvmName("constantTimes")
|
||||
public override operator fun C.times(other: C): C = polynomialRing { this@times * other }
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/
|
||||
@JvmName("constantPower")
|
||||
public override fun power(arg: C, exponent: UInt) : C = polynomialRing { power(arg, exponent) }
|
||||
|
||||
/**
|
||||
* Check if the instant is zero constant.
|
||||
@ -827,6 +851,10 @@ public interface AbstractRationalFunctionalSpaceOverPolynomialSpace<
|
||||
* Returns product of the polynomials.
|
||||
*/
|
||||
public override operator fun P.times(other: P): P = polynomialRing { this@times * other }
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*/
|
||||
public override fun power(arg: P, exponent: UInt) : P = polynomialRing { power(arg, exponent) }
|
||||
|
||||
/**
|
||||
* Check if the instant is zero polynomial.
|
||||
|
@ -5,53 +5,54 @@
|
||||
|
||||
package space.kscience.kmath.functions
|
||||
|
||||
import space.kscience.kmath.operations.Group
|
||||
import space.kscience.kmath.operations.*
|
||||
|
||||
|
||||
// TODO: All of this should be moved to algebraic structures' place for utilities
|
||||
// TODO: Move receiver to context receiver
|
||||
/**
|
||||
* Multiplication of element and integer.
|
||||
* Returns product of [arg] and integer [multiplier].
|
||||
*
|
||||
* @receiver the multiplicand.
|
||||
* @param other the multiplier.
|
||||
* @return the difference.
|
||||
* @param arg the multiplicand.
|
||||
* @param multiplier the integer multiplier.
|
||||
* @return product of the multiplicand [arg] and the multiplier [multiplier].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal fun <C> Group<C>.optimizedMultiply(arg: C, other: Int): C =
|
||||
if (other >= 0) optimizedMultiply(arg, other.toUInt())
|
||||
else optimizedMultiply(arg, (-other).toUInt())
|
||||
internal fun <C> Group<C>.multiplyBySquaring(arg: C, multiplier: Int): C =
|
||||
if (multiplier >= 0) multiplyBySquaring(arg, multiplier.toUInt())
|
||||
else multiplyBySquaring(-arg, (-multiplier).toUInt())
|
||||
|
||||
// TODO: Move receiver to context receiver
|
||||
/**
|
||||
* Adds product of [arg] and [multiplier] to [base].
|
||||
*
|
||||
* @receiver the algebra to provide multiplication.
|
||||
* @param base the augend.
|
||||
* @param arg the multiplicand.
|
||||
* @param multiplier the multiplier.
|
||||
* @param multiplier the integer multiplier.
|
||||
* @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal fun <C> Group<C>.optimizedAddMultiplied(base: C, arg: C, multiplier: Int): C =
|
||||
if (multiplier >= 0) optimizedAddMultiplied(base, arg, multiplier.toUInt())
|
||||
else optimizedAddMultiplied(base, arg, (-multiplier).toUInt())
|
||||
internal fun <C> GroupOps<C>.addMultipliedBySquaring(base: C, arg: C, multiplier: Int): C =
|
||||
if (multiplier >= 0) addMultipliedBySquaring(base, arg, multiplier.toUInt())
|
||||
else addMultipliedBySquaring(base, -arg, (-multiplier).toUInt())
|
||||
|
||||
// TODO: Move receiver to context receiver
|
||||
/**
|
||||
* Multiplication of element and integer.
|
||||
* Returns product of [arg] and integer [multiplier].
|
||||
*
|
||||
* @receiver the multiplicand.
|
||||
* @param other the multiplier.
|
||||
* @return the difference.
|
||||
* This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)
|
||||
*
|
||||
* @param arg the multiplicand.
|
||||
* @param multiplier the integer multiplier.
|
||||
* @return product of the multiplicand [arg] and the multiplier [multiplier].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal tailrec fun <C> Group<C>.optimizedMultiply(arg: C, other: UInt): C =
|
||||
internal tailrec fun <C> Group<C>.multiplyBySquaring(arg: C, multiplier: UInt): C =
|
||||
when {
|
||||
other == 0u -> zero
|
||||
other == 1u -> arg
|
||||
other % 2u == 0u -> optimizedMultiply(arg + arg, other / 2u)
|
||||
other % 2u == 1u -> optimizedAddMultiplied(arg, arg + arg, other / 2u)
|
||||
multiplier == 0u -> zero
|
||||
multiplier == 1u -> arg
|
||||
multiplier and 1u == 0u -> multiplyBySquaring(arg + arg, multiplier shr 1)
|
||||
multiplier and 1u == 1u -> addMultipliedBySquaring(arg, arg + arg, multiplier shr 1)
|
||||
else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1")
|
||||
}
|
||||
|
||||
@ -59,18 +60,87 @@ internal tailrec fun <C> Group<C>.optimizedMultiply(arg: C, other: UInt): C =
|
||||
/**
|
||||
* Adds product of [arg] and [multiplier] to [base].
|
||||
*
|
||||
* @receiver the algebra to provide multiplication.
|
||||
* This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)
|
||||
*
|
||||
* @param base the augend.
|
||||
* @param arg the multiplicand.
|
||||
* @param multiplier the multiplier.
|
||||
* @param multiplier the integer multiplier.
|
||||
* @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal tailrec fun <C> Group<C>.optimizedAddMultiplied(base: C, arg: C, multiplier: UInt): C =
|
||||
internal tailrec fun <C> GroupOps<C>.addMultipliedBySquaring(base: C, arg: C, multiplier: UInt): C =
|
||||
when {
|
||||
multiplier == 0u -> base
|
||||
multiplier == 1u -> base + arg
|
||||
multiplier % 2u == 0u -> optimizedAddMultiplied(base, arg + arg, multiplier / 2u)
|
||||
multiplier % 2u == 1u -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2u)
|
||||
multiplier and 1u == 0u -> addMultipliedBySquaring(base, arg + arg, multiplier shr 1)
|
||||
multiplier and 1u == 1u -> addMultipliedBySquaring(base + arg, arg + arg, multiplier shr 1)
|
||||
else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1")
|
||||
}
|
||||
|
||||
// TODO: Move receiver to context receiver
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*
|
||||
* @param arg the base of the power.
|
||||
* @param exponent the exponent of the power.
|
||||
* @return [arg] raised to the power [exponent].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal fun <C> Field<C>.exponentiationBySquaring(arg: C, exponent: Int): C =
|
||||
if (exponent >= 0) exponentiationBySquaring(arg, exponent.toUInt())
|
||||
else exponentiationBySquaring(one / arg, (-exponent).toUInt())
|
||||
|
||||
// TODO: Move receiver to context receiver
|
||||
/**
|
||||
* Multiplies [base] and [arg] raised to the integer power [exponent].
|
||||
*
|
||||
* @param base the multiplicand.
|
||||
* @param arg the base of the power.
|
||||
* @param exponent the exponent of the power.
|
||||
* @return product of [base] and [arg] raised to the power [exponent].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal fun <C> Field<C>.multiplyExponentiationBySquaring(base: C, arg: C, exponent: Int): C =
|
||||
if (exponent >= 0) multiplyExponentiationBySquaring(base, arg, exponent.toUInt())
|
||||
else multiplyExponentiationBySquaring(base, one / arg, (-exponent).toUInt())
|
||||
|
||||
// TODO: Move receiver to context receiver
|
||||
/**
|
||||
* Raises [arg] to the integer power [exponent].
|
||||
*
|
||||
* This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)
|
||||
*
|
||||
* @param arg the base of the power.
|
||||
* @param exponent the exponent of the power.
|
||||
* @return [arg] raised to the power [exponent].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal tailrec fun <C> Ring<C>.exponentiationBySquaring(arg: C, exponent: UInt): C =
|
||||
when {
|
||||
exponent == 0u -> zero
|
||||
exponent == 1u -> arg
|
||||
exponent and 1u == 0u -> exponentiationBySquaring(arg * arg, exponent shr 1)
|
||||
exponent and 1u == 1u -> multiplyExponentiationBySquaring(arg, arg * arg, exponent shr 1)
|
||||
else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1")
|
||||
}
|
||||
|
||||
// TODO: Move receiver to context receiver
|
||||
/**
|
||||
* Multiplies [base] and [arg] raised to the integer power [exponent].
|
||||
*
|
||||
* This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring)
|
||||
*
|
||||
* @param base the multiplicand.
|
||||
* @param arg the base of the power.
|
||||
* @param exponent the exponent of the power.
|
||||
* @return product of [base] and [arg] raised to the power [exponent].
|
||||
* @author Gleb Minaev
|
||||
*/
|
||||
internal tailrec fun <C> RingOps<C>.multiplyExponentiationBySquaring(base: C, arg: C, exponent: UInt): C =
|
||||
when {
|
||||
exponent == 0u -> base
|
||||
exponent == 1u -> base + arg
|
||||
exponent and 1u == 0u -> multiplyExponentiationBySquaring(base, arg * arg, exponent shr 1)
|
||||
exponent and 1u == 1u -> multiplyExponentiationBySquaring(base * arg, arg * arg, exponent shr 1)
|
||||
else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1")
|
||||
}
|
@ -351,7 +351,7 @@ public fun <C, A : Ring<C>> LabeledPolynomial<C>.derivativeWithRespectTo(
|
||||
}
|
||||
}
|
||||
},
|
||||
optimizedMultiply(c, degs[variable]!!)
|
||||
multiplyBySquaring(c, degs[variable]!!)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -382,7 +382,7 @@ public fun <C, A : Ring<C>> LabeledPolynomial<C>.derivativeWithRespectTo(
|
||||
}
|
||||
}
|
||||
},
|
||||
cleanedVariables.fold(c) { acc, variable -> optimizedMultiply(acc, degs[variable]!!) }
|
||||
cleanedVariables.fold(c) { acc, variable -> multiplyBySquaring(acc, degs[variable]!!) }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -415,7 +415,7 @@ public fun <C, A : Ring<C>> LabeledPolynomial<C>.nthDerivativeWithRespectTo(
|
||||
},
|
||||
degs[variable]!!.let { deg ->
|
||||
(deg downTo deg - order + 1u)
|
||||
.fold(c) { acc, ord -> optimizedMultiply(acc, ord) }
|
||||
.fold(c) { acc, ord -> multiplyBySquaring(acc, ord) }
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -451,7 +451,7 @@ public fun <C, A : Ring<C>> LabeledPolynomial<C>.nthDerivativeWithRespectTo(
|
||||
filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) ->
|
||||
degs[index]!!.let { deg ->
|
||||
(deg downTo deg - order + 1u)
|
||||
.fold(acc1) { acc2, ord -> optimizedMultiply(acc2, ord) }
|
||||
.fold(acc1) { acc2, ord -> multiplyBySquaring(acc2, ord) }
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -478,7 +478,7 @@ public fun <C, A : Field<C>> LabeledPolynomial<C>.antiderivativeWithRespectTo(
|
||||
}
|
||||
put(
|
||||
newDegs,
|
||||
c / optimizedMultiply(one, newDegs[variable]!!)
|
||||
c / multiplyBySquaring(one, newDegs[variable]!!)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -505,7 +505,7 @@ public fun <C, A : Field<C>> LabeledPolynomial<C>.antiderivativeWithRespectTo(
|
||||
}
|
||||
put(
|
||||
newDegs,
|
||||
cleanedVariables.fold(c) { acc, variable -> acc / optimizedMultiply(one, newDegs[variable]!!) }
|
||||
cleanedVariables.fold(c) { acc, variable -> acc / multiplyBySquaring(one, newDegs[variable]!!) }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -534,7 +534,7 @@ public fun <C, A : Field<C>> LabeledPolynomial<C>.nthAntiderivativeWithRespectTo
|
||||
newDegs,
|
||||
newDegs[variable]!!.let { deg ->
|
||||
(deg downTo deg - order + 1u)
|
||||
.fold(c) { acc, ord -> acc / optimizedMultiply(one, ord) }
|
||||
.fold(c) { acc, ord -> acc / multiplyBySquaring(one, ord) }
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -565,7 +565,7 @@ public fun <C, A : Field<C>> LabeledPolynomial<C>.nthAntiderivativeWithRespectTo
|
||||
filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) ->
|
||||
newDegs[index]!!.let { deg ->
|
||||
(deg downTo deg - order + 1u)
|
||||
.fold(acc1) { acc2, ord -> acc2 / optimizedMultiply(one, ord) }
|
||||
.fold(acc1) { acc2, ord -> acc2 / multiplyBySquaring(one, ord) }
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -393,7 +393,7 @@ public fun <C, A : Ring<C>> NumberedPolynomial<C>.derivativeWithRespectTo(
|
||||
else -> return@forEach
|
||||
}
|
||||
}.cleanUp(),
|
||||
optimizedMultiply(c, degs[variable])
|
||||
multiplyBySquaring(c, degs[variable])
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -424,7 +424,7 @@ public fun <C, A : Ring<C>> NumberedPolynomial<C>.derivativeWithRespectTo(
|
||||
else -> return@forEach
|
||||
}
|
||||
}.cleanUp(),
|
||||
cleanedVariables.fold(c) { acc, variable -> optimizedMultiply(acc, degs[variable]) }
|
||||
cleanedVariables.fold(c) { acc, variable -> multiplyBySquaring(acc, degs[variable]) }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -456,7 +456,7 @@ public fun <C, A : Ring<C>> NumberedPolynomial<C>.nthDerivativeWithRespectTo(
|
||||
}.cleanUp(),
|
||||
degs[variable].let { deg ->
|
||||
(deg downTo deg - order + 1u)
|
||||
.fold(c) { acc, ord -> optimizedMultiply(acc, ord) }
|
||||
.fold(c) { acc, ord -> multiplyBySquaring(acc, ord) }
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -489,7 +489,7 @@ public fun <C, A : Ring<C>> NumberedPolynomial<C>.nthDerivativeWithRespectTo(
|
||||
filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) ->
|
||||
degs[index].let { deg ->
|
||||
(deg downTo deg - order + 1u)
|
||||
.fold(acc1) { acc2, ord -> optimizedMultiply(acc2, ord) }
|
||||
.fold(acc1) { acc2, ord -> multiplyBySquaring(acc2, ord) }
|
||||
}
|
||||
}
|
||||
)
|
||||
@ -512,7 +512,7 @@ public fun <C, A : Field<C>> NumberedPolynomial<C>.antiderivativeWithRespectTo(
|
||||
.forEach { (degs, c) ->
|
||||
put(
|
||||
List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u },
|
||||
c / optimizedMultiply(one, degs[variable])
|
||||
c / multiplyBySquaring(one, degs[variable])
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -536,7 +536,7 @@ public fun <C, A : Field<C>> NumberedPolynomial<C>.antiderivativeWithRespectTo(
|
||||
.forEach { (degs, c) ->
|
||||
put(
|
||||
List(max(maxRespectedVariable + 1, degs.size)) { if (it !in variables) degs[it] else degs[it] + 1u },
|
||||
cleanedVariables.fold(c) { acc, variable -> acc / optimizedMultiply(one, degs[variable]) }
|
||||
cleanedVariables.fold(c) { acc, variable -> acc / multiplyBySquaring(one, degs[variable]) }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -561,7 +561,7 @@ public fun <C, A : Field<C>> NumberedPolynomial<C>.nthAntiderivativeWithRespectT
|
||||
List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + order },
|
||||
degs[variable].let { deg ->
|
||||
(deg downTo deg - order + 1u)
|
||||
.fold(c) { acc, ord -> acc / optimizedMultiply(one, ord) }
|
||||
.fold(c) { acc, ord -> acc / multiplyBySquaring(one, ord) }
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -589,7 +589,7 @@ public fun <C, A : Field<C>> NumberedPolynomial<C>.nthAntiderivativeWithRespectT
|
||||
filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) ->
|
||||
degs[index].let { deg ->
|
||||
(deg downTo deg - order + 1u)
|
||||
.fold(acc1) { acc2, ord -> acc2 / optimizedMultiply(one, ord) }
|
||||
.fold(acc1) { acc2, ord -> acc2 / multiplyBySquaring(one, ord) }
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -137,7 +137,7 @@ public fun <C, A> Polynomial<C>.derivative(
|
||||
public fun <C, A> Polynomial<C>.nthDerivative(
|
||||
algebra: A,
|
||||
order: UInt,
|
||||
): Polynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = algebra {
|
||||
): Polynomial<C> where A : Ring<C>, A : NumericAlgebra<C> = algebra {
|
||||
Polynomial(coefficients.drop(order.toInt()).mapIndexed { index, c -> (index + 1..index + order.toInt()).fold(c) { acc, i -> acc * number(i) } })
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user