From b8d65274f7cff2f3b797ff01ec474ec43a801e3c Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Thu, 30 Nov 2023 15:34:44 +0100 Subject: [PATCH 1/7] `MA.operate!(+, pol1, pol2)`: prevent captured variable perf issue (#145) The local function was spuriously recursive, making it not recursive fixes the performance problem. That is, this removes some run time dispatch and decreases the amount of allocation, but there's still some run time dispatch left in other places, according to JET.jl. Before: ```julia-repl julia> import MutableArithmetics; const MA = MutableArithmetics; julia> using DynamicPolynomials julia> @polyvar x y; julia> p = 2x + y; julia> q = x + 2y; julia> @allocated MA.operate!(+, p, q) 34413936 ``` After: ```julia-repl julia> import MutableArithmetics; const MA = MutableArithmetics; julia> using DynamicPolynomials julia> @polyvar x y; julia> p = 2x + y; julia> q = x + 2y; julia> @allocated MA.operate!(+, p, q) 30835632 ``` Both REPL runs was with nightly Julia v1.11. --- src/operators.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/operators.jl b/src/operators.jl index fdd2fd4..aa14e65 100644 --- a/src/operators.jl +++ b/src/operators.jl @@ -154,8 +154,9 @@ function MA.operate!( push!(p.a, t[1]) return push!(p.x.Z, t[2]) end - compare_monomials(t::_NoVarTerm, j::Int) = _exponents_compare(q, j, t[2]) - compare_monomials(i::Int, j::Int) = compare_monomials(get1(i), j) + compare_monomials_impl(t, j) = _exponents_compare(q, j, t[2]) + compare_monomials(t::_NoVarTerm, j::Int) = compare_monomials_impl(t, j) + compare_monomials(i::Int, j::Int) = compare_monomials_impl(get1(i), j) combine(i::Int, j::Int) = p.a[i] = MA.operate!!(op, p.a[i], q.a[j]) combine(t::_NoVarTerm, j::Int) = (MA.operate!!(op, t[1], q.a[j]), t[2]) function resize(n) From 6c40a3974afce59a4ba2f84b5d9de34d25918f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 8 Jan 2024 17:08:09 +0100 Subject: [PATCH 2/7] Add tests for ordering (#146) * Add tests for ordering * Update url --- README.md | 2 +- src/DynamicPolynomials.jl | 1 + src/monomial_vector.jl | 1 - src/var.jl | 9 +++++---- test/comp.jl | 14 ++++++++++++++ 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bd6e5a0..160d9e0 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ The following types are defined: All common algebraic operations between those types are designed to be as efficient as possible without doing any assumption on `T`. Typically, one imagine `T` to be a subtype of `Number` but it can be anything. -This is useful for example in the package [PolyJuMP](https://github.com/JuliaOpt/PolyJuMP.jl) where `T` is often an affine expression of [JuMP](https://github.com/JuliaOpt/JuMP.jl) decision variables. +This is useful for example in the package [PolyJuMP](https://github.com/jump-dev/PolyJuMP.jl) where `T` is often an affine expression of [JuMP](https://github.com/jump-dev/JuMP.jl) decision variables. The commutativity of `T` with `*` is not assumed, even if it is the coefficient of a monomial of commutative variables. However, commutativity of `T` and of the variables `+` is always assumed. This allows to keep the terms sorted (Graded Lexicographic order is used) in polynomial and measure which enables more efficient operations. diff --git a/src/DynamicPolynomials.jl b/src/DynamicPolynomials.jl index 895172e..f4eab05 100644 --- a/src/DynamicPolynomials.jl +++ b/src/DynamicPolynomials.jl @@ -36,6 +36,7 @@ function MP.constant_monomial(p::PolyType) end MP.monomial_type(::Type{<:PolyType{V,M}}) where {V,M} = Monomial{V,M} MP.monomial_type(::PolyType{V,M}) where {V,M} = Monomial{V,M} +MP.ordering(p::PolyType) = MP.ordering(MP.variable_union_type(p)) #function MP.constant_monomial(::Type{Monomial{V,M}}, vars=Variable{V,M}[]) where {V,M} # return Monomial{V,M}(vars, zeros(Int, length(vars))) #end diff --git a/src/monomial_vector.jl b/src/monomial_vector.jl index 9f63136..7186503 100644 --- a/src/monomial_vector.jl +++ b/src/monomial_vector.jl @@ -15,7 +15,6 @@ struct MonomialVector{V,M} <: AbstractVector{Monomial{V,M}} _isless = let M = M (a, b) -> MP.compare(a, b, M) < 0 end - @assert issorted(Z, lt = _isless) return new{V,M}(vars, Z) end end diff --git a/src/var.jl b/src/var.jl index b14014c..52877ac 100644 --- a/src/var.jl +++ b/src/var.jl @@ -26,8 +26,8 @@ function buildpolyvar(var, variable_order, monomial_order) varname, :( $(esc(varname)) = polyarrayvar( - $variable_order, - $monomial_order, + $(variable_order), + $(monomial_order), $prefix, $(esc.(var.args[2:end])...), ) @@ -53,9 +53,9 @@ function _extract_kw_args(args, variable_order) for arg in args if Base.Meta.isexpr(arg, :(=)) if arg.args[1] == :variable_order - variable_order = arg.args[2] + variable_order = esc(arg.args[2]) elseif arg.args[1] == :monomial_order - monomial_order = arg.args[2] + monomial_order = esc(arg.args[2]) else error("Unrecognized keyword argument `$(arg.args[1])`") end @@ -145,6 +145,7 @@ end MP.monomial(v::Variable) = Monomial(v) MP.variables(v::Variable) = [v] +MP.ordering(::Variable{V,M}) where {V,M} = M iscomm(::Type{Variable{C}}) where {C} = C diff --git a/test/comp.jl b/test/comp.jl index 66e068f..42e2f4a 100644 --- a/test/comp.jl +++ b/test/comp.jl @@ -1,8 +1,14 @@ +using Test +using DynamicPolynomials +import DynamicPolynomials: Commutative, CreationOrder # to test hygiene @testset "Variable order" begin @polyvar x z = x @polyvar x @test z != x + order = Commutative{CreationOrder} + @polyvar x variable_order = order + @test z != x end @testset "README example" begin function p(x, y, z) @@ -19,3 +25,11 @@ end @polyvar x y z monomial_order = Graded{Reverse{InverseLexOrder}} @test p(x, y, z) == "4z² - 5x³ + 7x²z² + 4xy²z" end +# See https://github.com/JuliaAlgebra/DynamicPolynomials.jl/issues/138 +# Also tests `ordering` +@testset "InverseLexOrder" begin + order = Graded{InverseLexOrder} + @polyvar x[1:2] monomial_order = order + @test ordering(x[1]) == order + @test issorted(monomials(x[1], 0:2)) +end From 88f7e3ffb11b7fae001ee5172472ae8013598839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Wed, 14 Feb 2024 14:30:13 +0100 Subject: [PATCH 3/7] v0.5.4 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 2541883..f850c5e 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "DynamicPolynomials" uuid = "7c1d4256-1411-5781-91ec-d7bc3513ac07" repo = "https://github.com/JuliaAlgebra/DynamicPolynomials.jl.git" -version = "0.5.3" +version = "0.5.4" [deps] Future = "9fa8497b-333b-5362-9e8d-4d0656e87820" From 5e0a70cc4cba7f11c62403c1fbea22c17a44f041 Mon Sep 17 00:00:00 2001 From: Alexander Demin <60229118+sumiya11@users.noreply.github.com> Date: Thu, 15 Feb 2024 00:44:07 +0300 Subject: [PATCH 4/7] ordering(poly) (#151) --- src/var.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/var.jl b/src/var.jl index 52877ac..b7eb350 100644 --- a/src/var.jl +++ b/src/var.jl @@ -145,7 +145,8 @@ end MP.monomial(v::Variable) = Monomial(v) MP.variables(v::Variable) = [v] -MP.ordering(::Variable{V,M}) where {V,M} = M +MP.ordering(v::Variable) = MP.ordering(typeof(v)) +MP.ordering(::Type{Variable{V,M}}) where {V,M} = M iscomm(::Type{Variable{C}}) where {C} = C From 4bd74ad2f4895182d4e5ff47f65c013de6bdf65f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Thu, 15 Feb 2024 12:00:50 +0100 Subject: [PATCH 5/7] Fix Lex comparison (#153) * Fix Lex comparison * fix --- src/comp.jl | 12 ++++++++++++ test/comp.jl | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/comp.jl b/src/comp.jl index b29a6e3..d9c0fbd 100644 --- a/src/comp.jl +++ b/src/comp.jl @@ -99,6 +99,18 @@ function MP.compare( j += 1 end end + @inbounds while i <= nvariables(x) + if x.z[i] > 0 + return 1 + end + i += 1 + end + @inbounds while j <= nvariables(y) + if y.z[j] > 0 + return -1 + end + j += 1 + end return 0 end diff --git a/test/comp.jl b/test/comp.jl index 42e2f4a..2e72721 100644 --- a/test/comp.jl +++ b/test/comp.jl @@ -10,6 +10,17 @@ import DynamicPolynomials: Commutative, CreationOrder # to test hygiene @polyvar x variable_order = order @test z != x end +function _less(a, b) + @test a < b + @test b > a + @test compare(monomial(a), b) < 0 + @test compare(b, monomial(a)) > 0 +end +@testset "Issue 152" begin + @polyvar x y monomial_order=LexOrder + _less(x, x * y) + _less(x * y^2, x^2) +end @testset "README example" begin function p(x, y, z) return sprint( From 5be6070be7289e3f36575a8eab00fd63cd04094c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Thu, 15 Feb 2024 12:01:11 +0100 Subject: [PATCH 6/7] v0.5.5 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index f850c5e..a2ea9ae 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "DynamicPolynomials" uuid = "7c1d4256-1411-5781-91ec-d7bc3513ac07" repo = "https://github.com/JuliaAlgebra/DynamicPolynomials.jl.git" -version = "0.5.4" +version = "0.5.5" [deps] Future = "9fa8497b-333b-5362-9e8d-4d0656e87820" From 005621b454915428fa1a4c6ad72f90dc42b47f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 16 Feb 2024 18:05:16 +0100 Subject: [PATCH 7/7] Error for divides with noncommutative (#154) --- src/div.jl | 5 ++++- test/mono.jl | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/div.jl b/src/div.jl index 16e5ea9..51e2645 100644 --- a/src/div.jl +++ b/src/div.jl @@ -1,4 +1,7 @@ -function MP.divides(m1::Monomial, m2::Monomial) +function MP.divides(m1::Monomial{<:NonCommutative}, m2::Monomial{<:NonCommutative}) + error("Not implemented yet") +end +function MP.divides(m1::Monomial{<:Commutative}, m2::Monomial{<:Commutative}) e1 = exponents(m1) v1 = variables(m1) e2 = exponents(m2) diff --git a/test/mono.jl b/test/mono.jl index 86aa59b..25b2361 100644 --- a/test/mono.jl +++ b/test/mono.jl @@ -166,4 +166,9 @@ import MultivariatePolynomials as MP @test filter(mono -> degree(mono) == 1, X) == monomial_vector([x, y]) @test filter(mono -> degree(mono) == 0, X) == monomial_vector([x^0]) end + @testset "Noncommutative div" begin + @ncpolyvar x y + err = ErrorException("Not implemented yet") + @test_throws err div(x, x * y) + end end