Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve docs for division #299

Merged
merged 2 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ makedocs(
"Substitution" => "substitution.md",
"Differentiation" => "differentiation.md",
"Division" => "division.md",
]
"Internal" => "internal.md",
],

# The following ensures that we only include the docstrings from
# this module for functions define in Base that we overwrite.
modules = [MultivariatePolynomials],
)

deploydocs(
Expand Down
33 changes: 30 additions & 3 deletions docs/src/division.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,45 @@
# Division

The `gcd` and `lcm` functions of `Base` have been implemented for monomials, you have for example `gcd(x^2*y^7*z^3, x^4*y^5*z^2)` returning `x^2*y^5*z^2` and `lcm(x^2*y^7*z^3, x^4*y^5*z^2)` returning `x^4*y^7*z^3`.

Given two polynomials, ``p`` and ``d``, there are unique ``r`` and ``q`` such that ``p = q d + r`` and the leading term of ``d`` does not divide the leading term of ``r``.
You can obtain ``q`` using the `div` function and ``r`` using the `rem` function.
The `divrem` function returns ``(q, r)``.

Given a polynomial ``p`` and divisors ``d_1, \ldots, d_n``, one can find ``r`` and ``q_1, \ldots, q_n`` such that ``p = q_1 d_1 + \cdots + q_n d_n + r`` and none of the leading terms of ``q_1, \ldots, q_n`` divide the leading term of ``r``.
You can obtain the vector ``[q_1, \ldots, q_n]`` using `div(p, d)` where ``d = [d_1, \ldots, d_n]`` and ``r`` using the `rem` function with the same arguments.
The `divrem` function returns ``(q, r)``.

```@docs
divides
div_multiple
```

Note that the coefficients of the polynomials need to be a field for `div`,
`rem` and `divrem` to work.
Alternatively, [`pseudo_rem`](@ref) or [`pseudo_divrem`](@ref) can be used
instead as they do not require the coefficient type to be a field.
```@docs
pseudo_rem
pseudo_divrem
rem_or_pseudo_rem
```

## Greatest Common Divisor (GCD)

The Greatest Common Divisor (GCD) and Least Common Multiple (LCM) can be
obtained for integers respectively with the `gcd` and `lcm` functions.
The same functions can be used with monomials and polynomials:
```@docs
gcd
lcm
AbstractUnivariateGCDAlgorithm
GeneralizedEuclideanAlgorithm
SubresultantAlgorithm
```
Internal functions of the `gcd` algorithm:
```@docs
isolate_variable
primitive_univariate_gcd!
univariate_gcd
content
primitive_part
primitive_part_content
```
2 changes: 1 addition & 1 deletion docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ The following packages extend the interface and/or implement algorithms using th

## Contents
```@contents
Pages = ["types.md", "substitution.md", "differentiation.md", "division.md"]
Pages = ["types.md", "substitution.md", "differentiation.md", "division.md", "internal.md"]
Depth = 3
```
9 changes: 9 additions & 0 deletions docs/src/internal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Internal

Internal utilities:
```@docs
pair_zip
vec
print_maybe_multiplication_sign
LazyMap
```
1 change: 1 addition & 0 deletions docs/src/substitution.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ However, if some variables only are replaced by `Int` then the return type shoul

```@docs
subs
substitute
```
1 change: 1 addition & 0 deletions docs/src/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ extdegree
leading_term
leading_coefficient
leading_monomial
deg_num_leading_terms
remove_leading_term
remove_monomials
filter_terms
Expand Down
51 changes: 50 additions & 1 deletion src/division.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,36 @@ function divides(t1::AbstractTermLike, t2::AbstractTermLike)
end
divides(t1::AbstractVariable, t2::AbstractVariable) = t1 == t2

"""
gcd(m1::AbstractMonomialLike, m2::AbstractMonomialLike)

Return the largest monomial `m` such that both `divides(m, m1)`
and `divides(m, m2)` are `true`.

```@example
julia> @polyvar x y z;

julia> gcd(x^2*y^7*z^3, x^4*y^5*z^2)
x²y⁵z²
```
"""
function Base.gcd(m1::AbstractMonomialLike, m2::AbstractMonomialLike)
return map_exponents(min, m1, m2)
end

"""
lcm(m1::AbstractMonomialLike, m2::AbstractMonomialLike)

Return the smallest monomial `m` such that both `divides(m1, m)`
and `divides(m2, m)` are `true`.

```@example
julia> @polyvar x y z;

julia> lcm(x^2*y^7*z^3, x^4*y^5*z^2)
x^4*y^7*z^3
```
"""
function Base.lcm(m1::AbstractMonomialLike, m2::AbstractMonomialLike)
return map_exponents(max, m1, m2)
end
Expand Down Expand Up @@ -152,6 +179,26 @@ function Base.rem(f::_APL, g::Union{_APL,AbstractVector{<:_APL}}; kwargs...)
return divrem(f, g; kwargs...)[2]
end

"""
pseudo_divrem(f::_APL{S}, g::_APL{T}, algo) where {S,T}

Return the pseudo divisor and remainder of `f` modulo `g` as defined in [Knu14, Algorithm R, p. 425].

When the coefficient type is not a field, it is not always possible to carry a
division. For instance, the division of `f = 3x + 1` by `g = 2x + 1` cannot be done over
integers. On the other hand, one can write `2f = 3g - 1`.
In general, the *pseudo* division of `f` by `g` is:
```math
l f(x) = q(x) g(x) + r(x)
```
where `l` is a power of the leading coefficient of `g` some constant.

See also [`pseudo_rem`](@ref).

[Knu14] Knuth, D.E., 2014.
*Art of computer programming, volume 2: Seminumerical algorithms.*
Addison-Wesley Professional. Third edition.
"""
function pseudo_divrem(f::_APL{S}, g::_APL{T}, algo) where {S,T}
return _pseudo_divrem(
algebraic_structure(MA.promote_operation(-, S, T)),
Expand Down Expand Up @@ -189,6 +236,8 @@ end

Return the pseudo remainder of `f` modulo `g` as defined in [Knu14, Algorithm R, p. 425].

See [`pseudo_divrem`](@ref) for more details.

[Knu14] Knuth, D.E., 2014.
*Art of computer programming, volume 2: Seminumerical algorithms.*
Addison-Wesley Professional. Third edition.
Expand Down Expand Up @@ -285,7 +334,7 @@ end
"""
rem_or_pseudo_rem(f::_APL, g::_APL, algo)

If the coefficient type is a field, return `rem`, otherwise, return [`pseudo_rem`](ref).
If the coefficient type is a field, return `rem`, otherwise, return [`pseudo_rem`](@ref).
"""
function rem_or_pseudo_rem(f::_APL, g::_APL, algo)
return MA.operate!!(rem_or_pseudo_rem, MA.mutable_copy(f), g, algo)
Expand Down
Loading