Skip to content

Commit d4e4821

Browse files
authored
Add variable and monomial order (#120)
* Fix format * Abstract monomial ordering * Fixes * MP#bl/order * Fix * Fix * Adapt with monomial order * Update README * Fixes * Fix format * Fix getZfordegs
1 parent 723e025 commit d4e4821

25 files changed

+1436
-674
lines changed

.JuliaFormatter.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Configuration file for JuliaFormatter.jl
2+
# For more information, see: https://domluna.github.io/JuliaFormatter.jl/stable/config/
3+
4+
always_for_in = true
5+
always_use_return = true
6+
margin = 80
7+
remove_extra_newlines = true
8+
short_to_long_function_def = true

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ jobs:
4646
shell: julia --project=@. {0}
4747
run: |
4848
using Pkg
49-
Pkg.add(PackageSpec(name="MultivariatePolynomials", rev="master"))
49+
Pkg.add(PackageSpec(name="MultivariatePolynomials", rev="bl/order"))
5050
- uses: julia-actions/julia-buildpkg@v1
5151
- uses: julia-actions/julia-runtest@v1
5252
with:

README.md

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ Sparse dynamic representation of multivariate polynomials that can be used with
99
Both commutative and non-commutative variables are supported.
1010
The following types are defined:
1111

12-
* `PolyVar{C}`: A variable which is commutative with `*` when `C` is `true`. Commutative variables are created using the `@polyvar` macro, e.g. `@polyvar x y`, `@polyvar x[1:8]` and non-commutative variables are created likewise using the `@ncpolyvar` macro.
13-
* `Monomial{C}`: A product of variables: e.g. `x*y^2`.
14-
* `Term{C, T}`: A product between an element of type `T` and a `Monomial{C}`, e.g `2x`, `3.0x*y^2`.
15-
* `Polynomial{C, T}`: A sum of `Term{C, T}`, e.g. `2x + 3.0x*y^2 + y`.
12+
* `Variable{V,M}`: A variable which is commutative with `*` when `V<:Commutative`. Commutative variables are created using the `@polyvar` macro, e.g. `@polyvar x y`, `@polyvar x[1:8]` and non-commutative variables are created likewise using the `@ncpolyvar` macro. The type parameter `M` is the monomial ordering.
13+
* `Monomial{V,M}`: A product of variables: e.g. `x*y^2`.
14+
* `MultivariatePolynomials.Term{T,Monomial{V,M}}`: A product between an element of type `T` and a `Monomial{V,M}`, e.g `2x`, `3.0x*y^2`.
15+
* `Polynomial{V,M,T}`: A sum of `Term{T,Monomial{V,M}}`, e.g. `2x + 3.0x*y^2 + y`.
1616

1717
All common algebraic operations between those types are designed to be as efficient as possible without doing any assumption on `T`.
1818
Typically, one imagine `T` to be a subtype of `Number` but it can be anything.
@@ -30,19 +30,19 @@ julia> @polyvar x y # assigns x (resp. y) to a variable of name x (resp. y)
3030
(x, y)
3131

3232
julia> p = 2x + 3.0x*y^2 + y # define a polynomial in variables x and y
33-
3.0xy² + 2.0x + y
33+
y + 2.0x + 3.0xy²
3434

3535
julia> differentiate(p, x) # compute the derivative of p with respect to x
36-
3.0 + 2.0
36+
2.0 + 3.0
3737

3838
julia> differentiate.(p, (x, y)) # compute the gradient of p
39-
(3.0 + 2.0, 6.0xy + 1.0)
39+
(2.0 + 3.0y², 1.0 + 6.0xy)
4040

4141
julia> p((x, y)=>(y, x)) # replace any x by y and y by x
42-
3.0x²y + x + 2.0y
42+
2.0y + x + 3.0x²y
4343

4444
julia> subs(p, y=>x^2) # replace any occurence of y by x^2
45-
3.0x ++ 2.0x
45+
2.0x ++ 3.0x
4646

4747
julia> p(x=>1, y=>2) # evaluate p at [1, 2]
4848
16.0
@@ -53,21 +53,50 @@ Below is an example with `@polyvar x[1:n]`
5353
julia> n = 3;
5454

5555
julia> @polyvar x[1:n] # assign x to a tuple of variables x1, x2, x3
56-
(PolyVar{true}[x₁, x₂, x₃],)
56+
(Variable{DynamicPolynomials.Commutative{DynamicPolynomials.CreationOrder}, Graded{LexOrder}}[x₁, x₂, x₃],)
5757

5858
julia> p = sum(x .* x) # compute the sum of squares
59-
x² + x₂² + x²
59+
x² + x₂² + x²
6060

6161
julia> subs(p, x[1]=>2, x[3]=>3) # make a partial substitution
62-
x₂² + 13
62+
13 + x₂²
6363

6464
julia> A = reshape(1:9, 3, 3);
6565

6666
julia> p(x => A * vec(x)) # corresponds to dot(A*x, A*x), need vec to convert the tuple to a vector
67-
14x₁² + 64x₁x₂ + 100x₁x₃ + 77x₂² + 244x₂x₃ + 194x₃²
67+
194x₃² + 244x₂x₃ + 77x₂² + 100x₁x₃ + 64x₁x₂ + 14x₁²
6868
```
69-
Note that, when doing substitution, it is required to give the `PolyVar` ordering that is meant.
70-
Indeed, the ordering between the `PolyVar` is not alphabetical but rather by order of creation
69+
70+
The terms of a polynomial are ordered in increasing monomial order. The default
71+
ordering is the graded lex order but it can be modified using the
72+
`monomial_order` keyword argument of the `@polyvar` macro.
73+
We illustrate this below by borrowing the example p. 59 of "Ideals, Varieties and Algorithms"
74+
of Cox, Little and O'Shea:
75+
```julia
76+
julia> p(x, y, z) = 4x*y^2*z + 4z^2 - 5x^3 + 7x^2*z^2
77+
p (generic function with 1 method)
78+
79+
julia> @polyvar x y z monomial_order = LexOrder
80+
(x, y, z)
81+
82+
julia> p(x, y, z)
83+
4+ 4xy²z + 7x²z² - 5
84+
85+
julia> @polyvar x y z
86+
(x, y, z)
87+
88+
julia> p(x, y, z)
89+
4- 5+ 4xy²z + 7x²z²
90+
91+
julia> @polyvar x y z monomial_order = Graded{Reverse{InverseLexOrder}}
92+
(x, y, z)
93+
94+
julia> p(x, y, z)
95+
4- 5+ 7x²z² + 4xy²z
96+
```
97+
98+
Note that, when doing substitution, it is required to give the `Variable` ordering that is meant.
99+
Indeed, the ordering between the `Variable` is not alphabetical but rather by order of creation
71100
which can be undeterministic with parallel computing.
72101
Therefore, this order cannot be used for substitution, even as a default (see [here](https://github.com/JuliaAlgebra/MultivariatePolynomials.jl/issues/3) for a discussion about this).
73102

src/DynamicPolynomials.jl

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,70 @@ const MA = MutableArithmetics
1212
using DataStructures
1313

1414
include("var.jl")
15+
#const CommutativeVariable{O,M} = Variable{Commutative{O},M}
16+
#const NonCommutativeVariable{O,M} = Variable{NonCommutative{O},M}
1517
include("mono.jl")
16-
const DMonomialLike{C} = Union{Monomial{C}, PolyVar{C}}
18+
const DMonomialLike{V,M} = Union{Monomial{V,M},Variable{V,M}}
1719
MA.mutability(::Type{<:Monomial}) = MA.IsMutable()
18-
include("term.jl")
19-
MA.mutability(::Type{Term{C, T}}) where {C, T} = MA.mutability(T)
20+
const _Term{V,M,T} = MP.Term{T,Monomial{V,M}}
2021
include("monomial_vector.jl")
2122
include("poly.jl")
2223
MA.mutability(::Type{<:Polynomial}) = MA.IsMutable()
23-
const TermPoly{C, T} = Union{Term{C, T}, Polynomial{C, T}}
24-
const PolyType{C} = Union{Polynomial{C}, Term{C}, Monomial{C}, PolyVar{C}}
25-
MP.variable_union_type(::Union{PolyType{C}, Type{<:PolyType{C}}}) where {C} = PolyVar{C}
26-
MP.constant_monomial(::Type{<:PolyType{C}}) where {C} = Monomial{C}()
27-
MP.constant_monomial(p::PolyType) = Monomial(_vars(p), zeros(Int, nvariables(p)))
28-
MP.monomial_type(::Type{<:PolyType{C}}) where C = Monomial{C}
29-
MP.monomial_type(::PolyType{C}) where C = Monomial{C}
30-
#function MP.constant_monomial(::Type{Monomial{C}}, vars=PolyVar{C}[]) where {C}
31-
# return Monomial{C}(vars, zeros(Int, length(vars)))
24+
const TermPoly{V,M,T} = Union{_Term{V,M,T},Polynomial{V,M,T}}
25+
const PolyType{V,M} =
26+
Union{Polynomial{V,M},_Term{V,M},Monomial{V,M},Variable{V,M}}
27+
function MP.variable_union_type(
28+
::Union{PolyType{V,M},Type{<:PolyType{V,M}}},
29+
) where {V,M}
30+
return Variable{V,M}
31+
end
32+
MP.constant_monomial(::Type{<:PolyType{V,M}}) where {V,M} = Monomial{V,M}()
33+
function MP.constant_monomial(p::PolyType)
34+
return Monomial(MP.variables(p), zeros(Int, nvariables(p)))
35+
end
36+
MP.monomial_type(::Type{<:PolyType{V,M}}) where {V,M} = Monomial{V,M}
37+
MP.monomial_type(::PolyType{V,M}) where {V,M} = Monomial{V,M}
38+
#function MP.constant_monomial(::Type{Monomial{V,M}}, vars=Variable{V,M}[]) where {V,M}
39+
# return Monomial{V,M}(vars, zeros(Int, length(vars)))
3240
#end
33-
MP.term_type(::Union{TermPoly{C, T}, Type{<:TermPoly{C, T}}}) where {C, T} = Term{C, T}
34-
MP.term_type(::Union{PolyType{C}, Type{<:PolyType{C}}}, ::Type{T}) where {C, T} = Term{C, T}
35-
MP.term_type(::Type{Polynomial{C}}) where {C} = Term{C}
36-
MP.polynomial_type(::Type{Term{C}}) where {C} = Polynomial{C}
37-
MP.polynomial_type(::Type{Term{C, T}}) where {T, C} = Polynomial{C, T}
38-
MP.polynomial_type(::Union{PolyType{C}, Type{<:PolyType{C}}}, ::Type{T}) where {C, T} = Polynomial{C, T}
39-
_vars(p::AbstractArray{<:PolyType}) = mergevars(_vars.(p))[1]
40-
MP.variables(p::Union{PolyType, MonomialVector, AbstractArray{<:PolyType}}) = _vars(p) # tuple(_vars(p))
41-
MP.nvariables(p::Union{PolyType, MonomialVector, AbstractArray{<:PolyType}}) = length(_vars(p))
42-
MP.similar_variable(p::Union{PolyType{C}, Type{<:PolyType{C}}}, ::Type{Val{V}}) where {C, V} = PolyVar{C}(string(V))
43-
MP.similar_variable(p::Union{PolyType{C}, Type{<:PolyType{C}}}, V::Symbol) where {C} = PolyVar{C}(string(V))
41+
function MP.term_type(
42+
::Union{TermPoly{V,M,T},Type{<:TermPoly{V,M,T}}},
43+
) where {V,M,T}
44+
return _Term{V,M,T}
45+
end
46+
function MP.term_type(
47+
::Union{PolyType{V,M},Type{<:PolyType{V,M}}},
48+
::Type{T},
49+
) where {V,M,T}
50+
return _Term{V,M,T}
51+
end
52+
MP.term_type(::Type{Polynomial{V,M}}) where {V,M} = _Term{V,M}
53+
MP.polynomial_type(::Type{_Term{V,M}}) where {V,M} = Polynomial{V,M}
54+
MP.polynomial_type(::Type{_Term{V,M,T}}) where {T,V,M} = Polynomial{V,M,T}
55+
function MP.polynomial_type(
56+
::Union{PolyType{V,M},Type{<:PolyType{V,M}}},
57+
::Type{T},
58+
) where {V,M,T}
59+
return Polynomial{V,M,T}
60+
end
61+
MP.variables(p::AbstractArray{<:PolyType}) = mergevars(MP.variables.(p))[1]
62+
function MP.nvariables(
63+
p::Union{PolyType,MonomialVector,AbstractArray{<:PolyType}},
64+
)
65+
return length(MP.variables(p))
66+
end
67+
function MP.similar_variable(
68+
P::Union{PolyType{V,M},Type{<:PolyType{V,M}}},
69+
::Type{Val{S}},
70+
) where {V,M,S}
71+
return MP.similar_variable(P, S)
72+
end
73+
function MP.similar_variable(
74+
::Union{PolyType{V,M},Type{<:PolyType{V,M}}},
75+
s::Symbol,
76+
) where {V,M}
77+
return Variable(string(s), V, M)
78+
end
4479

4580
include("promote.jl")
4681

0 commit comments

Comments
 (0)