From 65dc733512ee29040e69e0c5e2f9a3ee0034bf37 Mon Sep 17 00:00:00 2001 From: Benjamin Desef Date: Thu, 28 Mar 2024 11:51:02 +0100 Subject: [PATCH 1/3] Fix degree_complex More consistent behavior of degree_complex and halfdegree Make assertions into actual checks --- src/complex.jl | 72 ++++++++++++++++++++++++++----------------------- test/complex.jl | 5 +++- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/src/complex.jl b/src/complex.jl index 7a3f4e1f..dc8c7d91 100644 --- a/src/complex.jl +++ b/src/complex.jl @@ -214,26 +214,55 @@ end # Also give complex-valued degree definitions. We choose not to overwrite degree, as this will lead to issues in monovecs # and their sorting. So now there are two ways to calculate degrees: strictly by considering all variables independently, # and also by looking at their complex structure. +for fn in (:degree_complex, :halfdegree) + @eval function $fn(t::AbstractTermLike) + realdeg = 0 + cpdeg = 0 + conjdeg = 0 + for (var, exp) in powers(t) + if isreal(var) + realdeg += exp + (isrealpart(var) || isimagpart(var)) && error( + "Cannot calculate complex degrees when real or imaginary parts are present", + ) + else + if isconj(var) + conjdeg += exp + else + cpdeg += exp + end + end + end + return $( + fn === :degree_complex ? :(realdeg) : :(div(realdeg, 2, RoundUp)) + ) + max(cpdeg, conjdeg) + end +end + """ degree_complex(t::AbstractTermLike) Return the _total complex degree_ of the monomial of the term `t`, i.e., the maximum of the total degree of the declared variables in `t` and the total degree of the conjugate variables in `t`. To be well-defined, the monomial must not contain real parts or imaginary parts of variables. +""" +degree_complex(t::AbstractTermLike) + +""" + halfdegree(t::AbstractTermLike) + +Return the equivalent of `ceil(degree(t)/2)`` for real-valued terms or `degree_complex(t)` for terms with only complex +variables; however, respect any mixing between complex and real-valued variables. +""" +halfdegree(t::AbstractTermLike) +""" degree_complex(t::AbstractTermLike, v::AbstractVariable) Returns the exponent of the variable `v` or its conjugate in the monomial of the term `t`, whatever is larger. See also [`isconj`](@ref). """ -function degree_complex(t::AbstractTermLike) - vars = variables(t) - @assert(!any(isrealpart, vars) && !any(isimagpart, vars)) - grouping = isconj.(vars) - exps = exponents(t) - return max(sum(exps[grouping]), sum(exps[map(!, grouping)])) -end function degree_complex(t::AbstractTermLike, var::AbstractVariable) return degree_complex(monomial(t), var) end @@ -243,7 +272,9 @@ function degree_complex(m::AbstractMonomial, v::AbstractVariable) deg_c = 0 c_v = conj(v) for (var, exp) in powers(m) - @assert(!isrealpart(var) && !isimagpart(var)) + (isrealpart(var) || isimagpart(var)) && error( + "Cannot calculate complex degrees when real or imaginary parts are present", + ) if var == v deg += exp elseif var == c_v @@ -253,31 +284,6 @@ function degree_complex(m::AbstractMonomial, v::AbstractVariable) return max(deg, deg_c) end -""" - halfdegree(t::AbstractTermLike) - -Return the equivalent of `ceil(degree(t)/2)`` for real-valued terms or `degree_complex(t)` for terms with only complex -variables; however, respect any mixing between complex and real-valued variables. -""" -function halfdegree(t::AbstractTermLike) - realdeg = 0 - cpdeg = 0 - conjdeg = 0 - for (var, exp) in powers(t) - if isreal(var) - realdeg += exp - else - if isconj(var) - conjdeg += exp - else - @assert(!isrealpart(var) && !isimagpart(var)) - cpdeg += exp - end - end - end - return ((realdeg + 1) >> 1) + max(cpdeg, conjdeg) -end - """ mindegree_complex(p::Union{AbstractPolynomialLike, AbstractVector{<:AbstractTermLike}}) diff --git a/test/complex.jl b/test/complex.jl index cfad5448..35229673 100644 --- a/test/complex.jl +++ b/test/complex.jl @@ -64,8 +64,11 @@ @test degree_complex(x * y^2 * conj(y)^3) == 3 @test degree_complex(x * y^2 * conj(y)^3, x) == 1 @test degree_complex(x * y^2 * conj(y)^3, y) == 3 + @test degree_complex(a^5 * x * y^2 * conj(y)^4) == 9 + @test degree_complex(a^5 * x * y^2 * conj(y)^2) == 8 @test halfdegree(x * y^2 * conj(y^3)) == 3 - @test halfdegree(x * a^5 * conj(y)) == 4 + @test halfdegree(x * a^5 * conj(y^2)) == 5 + @test halfdegree(x^2 * a^5 * conj(y^2)) == 5 @test ordinary_variable([x, y, conj(x), a, real(x), imag(y)]) == [x, y, a] @test subs(4x + 8y^2 - 6x^3, [x, y] => [2 + 4im, 9 - im]) == From 1c9b144bd487bffb0a56acc05748e814bf71f8f6 Mon Sep 17 00:00:00 2001 From: Benjamin Desef Date: Thu, 28 Mar 2024 15:42:26 +0100 Subject: [PATCH 2/3] Add example for degree_complex/halfdegree to docstring --- src/complex.jl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/complex.jl b/src/complex.jl index dc8c7d91..35e758f1 100644 --- a/src/complex.jl +++ b/src/complex.jl @@ -245,6 +245,10 @@ end Return the _total complex degree_ of the monomial of the term `t`, i.e., the maximum of the total degree of the declared variables in `t` and the total degree of the conjugate variables in `t`. To be well-defined, the monomial must not contain real parts or imaginary parts of variables. +If `x` is a real-valued variable and `z` is complex-valued, +- `degree_complex(x^5) = 5` +- `degree_complex(z^3 * conj(z)^4) = 4` and `degree_complex(z^4 * conj(z)^3) = 4` +- `degree_complex(x^5 * z^3 * conj(z^4)) = 5 + 4 = 9` """ degree_complex(t::AbstractTermLike) @@ -253,6 +257,11 @@ degree_complex(t::AbstractTermLike) Return the equivalent of `ceil(degree(t)/2)`` for real-valued terms or `degree_complex(t)` for terms with only complex variables; however, respect any mixing between complex and real-valued variables. +To be well-defined, the monomial must not contain real parts or imaginary parts of variables. +If `x` is a real-valued variable and `z` is complex-valued, +- `halfdegree(x^5) = 3` +- `halfdegree(z^3 * conj(z)^4) = 4` and `halfdegree(z^4 * conj(z)^3) = 4` +- `halfdegree(x^5 * z^3 * conj(z^4)) = 3 + 4 = 7` """ halfdegree(t::AbstractTermLike) From d666102a4b4d5a2e928bfa290a337a0b9773c206 Mon Sep 17 00:00:00 2001 From: Benjamin Desef Date: Sat, 30 Mar 2024 11:04:54 +0100 Subject: [PATCH 3/3] Extend examples --- src/complex.jl | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/complex.jl b/src/complex.jl index 35e758f1..9575bc34 100644 --- a/src/complex.jl +++ b/src/complex.jl @@ -245,10 +245,12 @@ end Return the _total complex degree_ of the monomial of the term `t`, i.e., the maximum of the total degree of the declared variables in `t` and the total degree of the conjugate variables in `t`. To be well-defined, the monomial must not contain real parts or imaginary parts of variables. -If `x` is a real-valued variable and `z` is complex-valued, -- `degree_complex(x^5) = 5` -- `degree_complex(z^3 * conj(z)^4) = 4` and `degree_complex(z^4 * conj(z)^3) = 4` -- `degree_complex(x^5 * z^3 * conj(z^4)) = 5 + 4 = 9` +If `x₁` and `x₂` are real-valued variables and `z₁` and `z₂` are complex-valued, +- `degree_complex(x₁^2 * x₂^3) = 5` +- `degree_complex(z₁^3 * conj(z₁)^4) = max(3, 4) = 4` and `degree_complex(z₁^4 * conj(z₁)^3) = max(4, 3) = 4` +- `degree_complex(z₁^3 * z₂ * conj(z₁)^2 * conj(z₂)^4) = max(4, 6) = 6` and + `degree_complex(z₁^4 * z₂ * conj(z₁) * conj(z₂)^3) = max(5, 4) = 5` +- `degree_complex(x₁^2 * x₂^3 * z₁^3 * z₂ * conj(z₁)^2 * conj(z₂)^4) = 5 + max(4, 6) = 11` """ degree_complex(t::AbstractTermLike) @@ -258,10 +260,12 @@ degree_complex(t::AbstractTermLike) Return the equivalent of `ceil(degree(t)/2)`` for real-valued terms or `degree_complex(t)` for terms with only complex variables; however, respect any mixing between complex and real-valued variables. To be well-defined, the monomial must not contain real parts or imaginary parts of variables. -If `x` is a real-valued variable and `z` is complex-valued, -- `halfdegree(x^5) = 3` -- `halfdegree(z^3 * conj(z)^4) = 4` and `halfdegree(z^4 * conj(z)^3) = 4` -- `halfdegree(x^5 * z^3 * conj(z^4)) = 3 + 4 = 7` +If `x₁` and `x₂` are real-valued variables and `z₁` and `z₂` are complex-valued, +- `halfdegree(x₁^2 * x₂^3) = ⌈5/2⌉ = 3` +- `halfdegree(z₁^3 * conj(z₁)^4) = max(3, 4) = 4` and `halfdegree(z₁^4 * conj(z₁)^3) = max(4, 3) = 4` +- `halfdegree(z₁^3 * z₂ * conj(z₁)^2 * conj(z₂)^4) = max(4, 6) = 6` and + `halfdegree(z₁^4 * z₂ * conj(z₁) * conj(z₂)^3) = max(5, 4) = 5` +- `halfdegree(x₁^2 * x₂^3 * z₁^3 * z₂ * conj(z₁)^2 * conj(z₂)^4) = ⌈5/2⌉ + max(4, 6) = 9` """ halfdegree(t::AbstractTermLike)