From 630d16bbeefbd8d402732dd8410ea950c26a6ca6 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 26 Jun 2022 12:16:51 +0300 Subject: [PATCH] Added design notes. Also: - Changed `xxxPolynomialSpace()` and `xxxPolynomialSpace()` functions to `xxxPolynomialSpace` value properties. - Changed inconsistency of names `XxxRationalFunctionalSpaceYyy` and `XxxRationalFunctionSpaceYyy` in favor of second one. --- docs/polynomials.md | 172 ++++++++++++++++++ .../functions/LabeledRationalFunction.kt | 2 +- .../kmath/functions/ListRationalFunction.kt | 2 +- .../functions/NumberedRationalFunction.kt | 2 +- .../kmath/functions/RationalFunction.kt | 22 +-- .../kscience/kmath/functions/labeledUtil.kt | 8 +- .../kscience/kmath/functions/listUtil.kt | 12 +- .../kscience/kmath/functions/numberedUtil.kt | 8 +- 8 files changed, 200 insertions(+), 28 deletions(-) create mode 100644 docs/polynomials.md diff --git a/docs/polynomials.md b/docs/polynomials.md new file mode 100644 index 000000000..fe69948e5 --- /dev/null +++ b/docs/polynomials.md @@ -0,0 +1,172 @@ +# Polynomials and Rational Functions + +KMath provides a way to work with uni- and multivariate polynomials and rational functions. It includes full support of arithmetic operations of integers, **constants** (elements of ring polynomials are build over), variables (for certain multivariate implementations), polynomials and rational functions encapsulated in so-called **polynomial space** and **rational function space** and some other utilities such as algebraic differentiation and substitution. + +## Concrete realizations + +There are 3 approaches to represent polynomials: +1. For univariate polynomials one can represent and store polynomial as a list of coefficients for each power of the variable. I.e. polynomial $a_0 + \dots + a_n x^n $ can be represented as a finite sequence $(a_0; \dots; a_n)$. (Compare to sequential definition of polynomials.) +2. For multivariate polynomials one can represent and store polynomial as a matching (in programming it is called "map" or "dictionary", in math it is called [functional relation](https://en.wikipedia.org/wiki/Binary_relation#Special_types_of_binary_relations)) of each "**term signature**" (that describes what variables and in what powers appear in the term) with corresponding coefficient of the term. But there are 2 possible approaches of term signature representation: + 1. One can number all the variables, so term signature can be represented as a sequence describing powers of the variables. I.e. signature of term $c \\; x_0^{d_0} \dots x_n^{d_n} $ (for natural or zero $d_i $) can be represented as a finite sequence $(d_0; \dots; d_n)$. + 2. One can represent variables as objects ("**labels**"), so term signature can be also represented as a matching of each appeared variable with its power in the term. + +All that three approaches are implemented by "list", "numbered", and "labeled" versions of polynomials and polynomial spaces respectively. Whereas all rational functions are represented as fractions with corresponding polynomial numerator and denominator, and rational functions' spaces are implemented in the same way as usual field of rational numbers (or more precisely, as any field of fractions over integral domain) should be implemented. + +So here are a bit of details. Let `C` by type of constants. Then: +1. `ListPolynomial`, `ListPolynomialSpace`, `ListRationalFunction` and `ListRationalFunctionSpace` implement the first scenario. `ListPolynomial` stores polynomial $a_0 + \dots + a_n x^n $ as a coefficients list `listOf(a_0, ..., a_n)` (of type `List`). + + They also have variation `ScalableListPolynomialSpace` that replaces former polynomials and implements `ScaleOperations`. +2. `NumberedPolynomial`, `NumberedPolynomialSpace`, `NumberedRationalFunction` and `NumberedRationalFunctionSpace` implement second scenario. `NumberedPolynomial` stores polynomials as structures of type `Map, C>`. Signatures are stored as `List`. To prevent ambiguity signatures should not end with zeros. +3. `LabeledPolynomial`, `LabeledPolynomialSpace`, `LabeledRationalFunction` and `LabeledRationalFunctionSpace` implement third scenario using common `Symbol` as variable type. `LabeledPolynomial` stores polynomials as structures of type `Map, C>`. Signatures are stored as `Map`. To prevent ambiguity each signature should not map any variable to zero. + +### Example: `ListPolynomial` + +For example, polynomial $2 - 3x + x^2 $ (with `Int` coefficients) is represented +```kotlin +val polynomial: ListPolynomial = ListPolynomial(listOf(2, -3, 1)) +// or +val polynomial: ListPolynomial = ListPolynomial(2, -3, 1) +``` + +All algebraic operations can be used in corresponding space: +```kotlin +val computationResult = Int.algebra.listPolynomialSpace { + ListPolynomial(2, -3, 1) + ListPolynomial(0, 6) == ListPolynomial(2, 3, 1) +} + +println(computationResult) // true +``` + +For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt). + +### Example: `NumberedPolynomial` + +For example, polynomial $3 + 5 x_1 - 7 x_0^2 x_2 $ (with `Int` coefficients) is represented +```kotlin +val polynomial: NumberedPolynomial = NumberedPolynomial( + mapOf( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, + ) +) +// or +val polynomial: NumberedPolynomial = NumberedPolynomial( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, +) +``` + +All algebraic operations can be used in corresponding space: +```kotlin +val computationResult = Int.algebra.numberedPolynomialSpace { + NumberedPolynomial( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, + ) + NumberedPolynomial( + listOf(0u, 1u) to -5, + listOf(0u, 0u, 0u, 4u) to 4, + ) == NumberedPolynomial( + listOf() to 3, + listOf(0u, 1u) to 0, + listOf(2u, 0u, 1u) to -7, + listOf(0u, 0u, 0u, 4u) to 4, + ) +} + +println(computationResult) // true +``` + +For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt). + +### Example: `LabeledPolynomial` + +For example, polynomial $3 + 5 y - 7 x^2 z $ (with `Int` coefficients) is represented +```kotlin +val polynomial: LabeledPolynomial = LabeledPolynomial( + mapOf( + mapOf() to 3, + mapOf(y to 1u) to 5, + mapOf(x to 2u, z to 1u) to -7, + ) +) +// or +val polynomial: LabeledPolynomial = LabeledPolynomial( + mapOf() to 3, + mapOf(y to 1u) to 5, + mapOf(x to 2u, z to 1u) to -7, +) +``` + +All algebraic operations can be used in corresponding space: +```kotlin +val computationResult = Int.algebra.labeledPolynomialSpace { + LabeledPolynomial( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, + ) + LabeledPolynomial( + listOf(0u, 1u) to -5, + listOf(0u, 0u, 0u, 4u) to 4, + ) == LabeledPolynomial( + listOf() to 3, + listOf(0u, 1u) to 0, + listOf(2u, 0u, 1u) to -7, + listOf(0u, 0u, 0u, 4u) to 4, + ) +} + +println(computationResult) // true +``` + +For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt). + +## Abstract entities (interfaces and abstract classes) + +```mermaid +classDiagram + Polynomial <|-- ListPolynomial + Polynomial <|-- NumberedPolynomial + Polynomial <|-- LabeledPolynomial + + RationalFunction <|-- ListRationalFunction + RationalFunction <|-- NumberedRationalFunction + RationalFunction <|-- LabeledRationalFunction + + Ring <|-- PolynomialSpace + PolynomialSpace <|-- MultivariatePolynomialSpace + PolynomialSpace <|-- PolynomialSpaceOverRing + + Ring <|-- RationalFunctionSpace + RationalFunctionSpace <|-- MultivariateRationalFunctionSpace + RationalFunctionSpace <|-- RationalFunctionSpaceOverRing + RationalFunctionSpace <|-- RationalFunctionSpaceOverPolynomialSpace + RationalFunctionSpace <|-- PolynomialSpaceOfFractions + RationalFunctionSpaceOverPolynomialSpace <|-- MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace + MultivariateRationalFunctionSpace <|-- MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace + MultivariateRationalFunctionSpace <|-- MultivariatePolynomialSpaceOfFractions + PolynomialSpaceOfFractions <|-- MultivariatePolynomialSpaceOfFractions +``` + +There are implemented `Polynomial` and `RationalFunction` interfaces as abstractions of polynomials and rational functions respectively (although, there is not a lot of logic in them) and `PolynomialSpace` and `RationalFunctionSpace` (that implement `Ring` interface) as abstractions of polynomials' and rational functions' spaces respectively. More precisely, that means they allow to declare common logic of interaction with such objects and spaces: +- `Polynomial` does not provide any logic. It is marker interface. +- `RationalFunction` provides numerator and denominator of rational function and destructuring declaration for them. +- `PolynomialSpace` provides all possible arithmetic interactions of integers, constants (of type `C`), and polynomials (of type `P`) like addition, subtraction, multiplication, and some others and common properties like degree of polynomial. +- `RationalFunctionSpace` provides the same as `PolynomialSpace` but also for rational functions: all possible arithmetic interactions of integers, constants (of type `C`), polynomials (of type `P`), and rational functions (of type `R`) like addition, subtraction, multiplication, division (in some cases), and some others and common properties like degree of polynomial. + +Then to add abstraction of similar behaviour with variables (in multivariate case) there are implemented `MultivariatePolynomialSpace` and `MultivariateRationalFunctionSpace`. They just include variables (of type `V`) in the interactions of the entities. + +Also, to remove boilerplates there were provided helping subinterfaces and abstract subclasses: +- `PolynomialSpaceOverRing` allows to replace implementation of interactions of integers and constants with implementations from provided ring over constants (of type `A: Ring`). +- `RationalFunctionSpaceOverRing` — the same but for `RationalFunctionSpace`. +- `RationalFunctionSpaceOverPolynomialSpace` — the same but "the inheritance" includes interactions with polynomials from provided `PolynomialSpace`. +- `PolynomialSpaceOfFractions` is actually abstract subclass of `RationalFunctionSpace` that implements all fractions boilerplates with provided (`protected`) constructor of rational functions by polynomial numerator and denominator. +- `MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace` and `MultivariatePolynomialSpaceOfFractions` — the same stories of operators inheritance and fractions boilerplates respectively but in multivariate case. + +## Utilities + +For all kinds of polynomials there are provided (implementation details depend on kind of polynomials) such common utilities as: +1. differentiation and anti-differentiation, +2. substitution, invocation and functional representation. \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 1b0bbbec8..b1d0dd4d9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -30,7 +30,7 @@ public data class LabeledRationalFunction( public class LabeledRationalFunctionSpace>( public val ring: A, ) : - MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< + MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace< C, Symbol, LabeledPolynomial, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index e23baa548..7434063f2 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -28,7 +28,7 @@ public data class ListRationalFunction( public class ListRationalFunctionSpace> ( public val ring: A, ) : - RationalFunctionalSpaceOverPolynomialSpace< + RationalFunctionSpaceOverPolynomialSpace< C, ListPolynomial, ListRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 497755126..e61d6c55e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -32,7 +32,7 @@ public data class NumberedRationalFunction( public class NumberedRationalFunctionSpace> ( public val ring: A, ) : - RationalFunctionalSpaceOverPolynomialSpace< + RationalFunctionSpaceOverPolynomialSpace< C, NumberedPolynomial, NumberedRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 338ae9935..1782dba74 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -29,7 +29,7 @@ public interface RationalFunction> { * @param R the type of rational functions. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpace, R: RationalFunction> : Ring { +public interface RationalFunctionSpace, R: RationalFunction> : Ring { /** * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * @@ -459,12 +459,12 @@ public interface RationalFunctionalSpace, R: RationalFunctio * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpaceOverRing< +public interface RationalFunctionSpaceOverRing< C, P: Polynomial, R: RationalFunction, A: Ring - > : RationalFunctionalSpace { + > : RationalFunctionSpace { /** * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. @@ -561,12 +561,12 @@ public interface RationalFunctionalSpaceOverRing< * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpaceOverPolynomialSpace< +public interface RationalFunctionSpaceOverPolynomialSpace< C, P: Polynomial, R: RationalFunction, AP: PolynomialSpace, - > : RationalFunctionalSpace { + > : RationalFunctionSpace { /** * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. @@ -797,7 +797,7 @@ public abstract class PolynomialSpaceOfFractions< C, P: Polynomial, R: RationalFunction, - > : RationalFunctionalSpace { + > : RationalFunctionSpace { /** * Constructor of rational functions (of type [R]) from numerator and denominator (of type [P]). @@ -1106,12 +1106,12 @@ public abstract class PolynomialSpaceOfFractions< * @param R the type of rational functions. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface MultivariateRationalFunctionalSpace< +public interface MultivariateRationalFunctionSpace< C, V, P: Polynomial, R: RationalFunction - >: RationalFunctionalSpace { + >: RationalFunctionSpace { /** * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @@ -1335,13 +1335,13 @@ public interface MultivariateRationalFunctionalSpace< * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< +public interface MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace< C, V, P: Polynomial, R: RationalFunction, AP: MultivariatePolynomialSpace, - > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace { + > : RationalFunctionSpaceOverPolynomialSpace, MultivariateRationalFunctionSpace { /** * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @@ -1517,7 +1517,7 @@ public abstract class MultivariatePolynomialSpaceOfFractions< V, P: Polynomial, R: RationalFunction, - > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { + > : MultivariateRationalFunctionSpace, PolynomialSpaceOfFractions() { /** * Returns sum of the variable represented as a rational function and the rational function. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt index 39c781a14..4002eb25a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt @@ -19,8 +19,8 @@ import kotlin.jvm.JvmName /** * Creates a [LabeledPolynomialSpace] over a received ring. */ -public fun > A.labeledPolynomialSpace(): LabeledPolynomialSpace = - LabeledPolynomialSpace(this) +public inline val > A.labeledPolynomialSpace: LabeledPolynomialSpace + get() = LabeledPolynomialSpace(this) /** * Creates a [LabeledPolynomialSpace]'s scope over a received ring. @@ -32,8 +32,8 @@ public inline fun , R> A.labeledPolynomialSpace(block: LabeledPol /** * Creates a [LabeledRationalFunctionSpace] over a received ring. */ -public fun > A.labeledRationalFunctionSpace(): LabeledRationalFunctionSpace = - LabeledRationalFunctionSpace(this) +public inline val > A.labeledRationalFunctionSpace: LabeledRationalFunctionSpace + get() = LabeledRationalFunctionSpace(this) /** * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt index 649fc48bd..4f3f6d88e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt @@ -16,8 +16,8 @@ import kotlin.math.pow /** * Creates a [ListPolynomialSpace] over a received ring. */ -public fun > A.listPolynomialSpace(): ListPolynomialSpace = - ListPolynomialSpace(this) +public inline val > A.listPolynomialSpace: ListPolynomialSpace + get() = ListPolynomialSpace(this) /** * Creates a [ListPolynomialSpace]'s scope over a received ring. @@ -30,8 +30,8 @@ public inline fun , R> A.listPolynomialSpace(block: ListPolynomia /** * Creates a [ScalableListPolynomialSpace] over a received scalable ring. */ -public fun A.scalableListPolynomialSpace(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = - ScalableListPolynomialSpace(this) +public inline val A.scalableListPolynomialSpace: ScalableListPolynomialSpace where A : Ring, A : ScaleOperations + get() = ScalableListPolynomialSpace(this) /** * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. @@ -44,8 +44,8 @@ public inline fun A.scalableListPolynomialSpace(block: ScalableListPol /** * Creates a [ListRationalFunctionSpace] over a received ring. */ -public fun > A.listRationalFunctionSpace(): ListRationalFunctionSpace = - ListRationalFunctionSpace(this) +public inline val > A.listRationalFunctionSpace: ListRationalFunctionSpace + get() = ListRationalFunctionSpace(this) /** * Creates a [ListRationalFunctionSpace]'s scope over a received ring. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index 96f5f480b..e485652f4 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -21,8 +21,8 @@ import kotlin.math.min /** * Creates a [NumberedPolynomialSpace] over a received ring. */ -public fun > A.numberedPolynomialSpace(): NumberedPolynomialSpace = - NumberedPolynomialSpace(this) +public inline val > A.numberedPolynomialSpace: NumberedPolynomialSpace + get() = NumberedPolynomialSpace(this) /** * Creates a [NumberedPolynomialSpace]'s scope over a received ring. @@ -35,8 +35,8 @@ public inline fun , R> A.numberedPolynomialSpace(block: NumberedP /** * Creates a [NumberedRationalFunctionSpace] over a received ring. */ -public fun > A.numberedRationalFunctionSpace(): NumberedRationalFunctionSpace = - NumberedRationalFunctionSpace(this) +public inline val > A.numberedRationalFunctionSpace: NumberedRationalFunctionSpace + get() = NumberedRationalFunctionSpace(this) /** * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring.