Upload 19 files
Browse filesLicense
This dataset is licensed under a Creative Commons Attribution 4.0 International (CC BY 4.0) license.
This allows for the sharing and adaptation of the datasets for any purpose, provided that the appropriate credit is given.
Pawel Bielski
[email protected]
Karlsruhe Institute of Technology
Dustin Kottonau
Karlsruhe Institute of Technology
Additional Information
- staDynBenignLab.csv: 1086 features extracted from 595 files on MS Windows 7 and 8, obtained Program Files directory.
- staDynVxHeaven2698Lab.csv: 1087 features extracted from 2698 files of VxHeaven dataset.
- staDynVt2955Lab.csv: 1087 features extracted from 2955 provided by Virus Total in 2018.
Has Missing Values?
No
Variable Information
Static features: ASM, Hex dump and PE Header (discreate, continuous)
Dynamic features: extracted from a Cuckoo sandbox
Dataset Files
Reviews
There are no reviews for this dataset yet.
Write a Review
Comments
Install the ucimlrepo package
pip install ucimlrepo
Import the dataset into your code
from ucimlrepo import fetch_ucirepo
# fetch dataset
malware_static_and_dynamic_features_vxheaven_and_virus_total = fetch_ucirepo(id=541)
# data (as pandas dataframes)
X = malware_static_and_dynamic_features_vxheaven_and_virus_total.data.features
y = malware_static_and_dynamic_features_vxheaven_and_virus_total.data.targets
# metadata
print(malware_static_and_dynamic_features_vxheaven_and_virus_total.metadata)
# variable information
print(malware_static_and_dynamic_features_vxheaven_and_virus_total.variables)
View the full documentation
0 citations
4165 views
Citation
Malware static and dynamic features VxHeaven and Virus Total [Dataset]. (2019). UCI Machine Learning Repository. https://doi.org/10.24432/C58K6H.
Style:
DOI
10.24432/C58K6H
License
This dataset is licensed under a Creative Commons Attribution 4.0 International (CC BY 4.0) license.
This allows for the sharing and adaptation of the datasets for any purpose, provided that the appropriate credit is given.
- DynamicPolynomials.jl +47 -0
- appveyor.yml +36 -0
- cmult.jl +65 -0
- comp.jl +162 -0
- diff.jl +28 -0
- div.jl +22 -0
- mono.jl +81 -0
- monovec.jl +241 -0
- mult.jl +101 -0
- ncmult.jl +123 -0
- operators.jl +66 -0
- poly.jl +230 -0
- promote.jl +27 -0
- staDynBenignLab.csv +0 -0
- staDynVt2955Lab.csv +0 -0
- staDynVxHeaven2698Lab.csv +0 -0
- subs.jl +106 -0
- term.jl +52 -0
- var.jl +101 -0
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
module DynamicPolynomials
|
2 |
+
|
3 |
+
using Reexport
|
4 |
+
@reexport using MultivariatePolynomials
|
5 |
+
const MP = MultivariatePolynomials
|
6 |
+
|
7 |
+
|
8 |
+
include("var.jl")
|
9 |
+
include("mono.jl")
|
10 |
+
const DMonomialLike{C} = Union{Monomial{C}, PolyVar{C}}
|
11 |
+
include("term.jl")
|
12 |
+
include("monovec.jl")
|
13 |
+
include("poly.jl")
|
14 |
+
const TermPoly{C, T} = Union{Term{C, T}, Polynomial{C, T}}
|
15 |
+
const PolyType{C} = Union{Polynomial{C}, Term{C}, Monomial{C}, PolyVar{C}}
|
16 |
+
MP.constantmonomial(::Type{<:PolyType{C}}) where {C} = Monomial{C}()
|
17 |
+
MP.constantmonomial(p::PolyType) = Monomial(_vars(p), zeros(Int, nvariables(p)))
|
18 |
+
MP.monomialtype(::Type{<:PolyType{C}}) where C = Monomial{C}
|
19 |
+
MP.monomialtype(::PolyType{C}) where C = Monomial{C}
|
20 |
+
#function MP.constantmonomial(::Type{Monomial{C}}, vars=PolyVar{C}[]) where {C}
|
21 |
+
# return Monomial{C}(vars, zeros(Int, length(vars)))
|
22 |
+
#end
|
23 |
+
MP.termtype(::Union{TermPoly{C, T}, Type{<:TermPoly{C, T}}}) where {C, T} = Term{C, T}
|
24 |
+
MP.termtype(::Union{PolyType{C}, Type{<:PolyType{C}}}, ::Type{T}) where {C, T} = Term{C, T}
|
25 |
+
MP.polynomial(p::PolyType) = Polynomial(p)
|
26 |
+
function MP.polynomial(p::PolyType{C}, ::Type{T}) where {C, T}
|
27 |
+
return convert(Polynomial{C, T}, p)
|
28 |
+
end
|
29 |
+
MP.polynomialtype(::Type{Term{C, T}}) where {T, C} = Polynomial{C, T}
|
30 |
+
MP.polynomialtype(::Type{T}, ::Type{<:DMonomialLike{C}}) where {T, C} = Polynomial{C, T}
|
31 |
+
MP.polynomialtype(::Union{PolyType{C}, Type{<:PolyType{C}}}, ::Type{T}) where {C, T} = Polynomial{C, T}
|
32 |
+
_vars(p::AbstractArray{<:PolyType}) = mergevars(_vars.(p))[1]
|
33 |
+
MP.variables(p::Union{PolyType, MonomialVector, AbstractArray{<:PolyType}}) = _vars(p) # tuple(_vars(p))
|
34 |
+
MP.nvariables(p::Union{PolyType, MonomialVector, AbstractArray{<:PolyType}}) = length(_vars(p))
|
35 |
+
MP.similarvariable(p::Union{PolyType{C}, Type{<:PolyType{C}}}, ::Type{Val{V}}) where {C, V} = PolyVar{C}(string(V))
|
36 |
+
MP.similarvariable(p::Union{PolyType{C}, Type{<:PolyType{C}}}, V::Symbol) where {C} = PolyVar{C}(string(V))
|
37 |
+
include("promote.jl")
|
38 |
+
|
39 |
+
include("operators.jl")
|
40 |
+
include("comp.jl")
|
41 |
+
|
42 |
+
include("diff.jl")
|
43 |
+
include("subs.jl")
|
44 |
+
|
45 |
+
include("div.jl")
|
46 |
+
|
47 |
+
end # module
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
environment:
|
2 |
+
matrix:
|
3 |
+
- julia_version: 1.0
|
4 |
+
- julia_version: latest
|
5 |
+
|
6 |
+
platform:
|
7 |
+
- x86 # 32-bit
|
8 |
+
- x64 # 64-bit
|
9 |
+
|
10 |
+
## uncomment the following lines to allow failures on nightly julia
|
11 |
+
## (tests will run but not make your overall status red)
|
12 |
+
matrix:
|
13 |
+
allow_failures:
|
14 |
+
- julia_version: latest
|
15 |
+
|
16 |
+
branches:
|
17 |
+
only:
|
18 |
+
- master
|
19 |
+
- /release-.*/
|
20 |
+
|
21 |
+
notifications:
|
22 |
+
- provider: Email
|
23 |
+
on_build_success: false
|
24 |
+
on_build_failure: false
|
25 |
+
on_build_status_changed: false
|
26 |
+
|
27 |
+
install:
|
28 |
+
- ps: iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/JuliaCI/Appveyor.jl/version-1/bin/install.ps1"))
|
29 |
+
|
30 |
+
build_script:
|
31 |
+
- echo "%JL_BUILD_SCRIPT%"
|
32 |
+
- C:\julia\bin\julia -e "%JL_BUILD_SCRIPT%"
|
33 |
+
|
34 |
+
test_script:
|
35 |
+
- echo "%JL_TEST_SCRIPT%"
|
36 |
+
- C:\julia\bin\julia -e "%JL_TEST_SCRIPT%"
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Product between PolyVar and Monomial -> Monomial
|
2 |
+
function Base.:(*)(x::PolyVar{true}, y::PolyVar{true})
|
3 |
+
if x === y
|
4 |
+
Monomial{true}([x], [2])
|
5 |
+
else
|
6 |
+
Monomial{true}(x > y ? [x,y] : [y,x], [1,1])
|
7 |
+
end
|
8 |
+
end
|
9 |
+
function multiplyvar(v::Vector{PolyVar{true}}, x::PolyVar{true})
|
10 |
+
i = findfirst(w->w <= x, v)
|
11 |
+
if (i != nothing && i > 0) && v[i] == x
|
12 |
+
multiplyexistingvar(v, x, i)
|
13 |
+
else
|
14 |
+
insertvar(v, x, (i == nothing || i == 0) ? length(v)+1 : i)
|
15 |
+
end
|
16 |
+
end
|
17 |
+
function Base.:(*)(x::PolyVar{true}, y::Monomial{true})
|
18 |
+
w, updatez = multiplyvar(y.vars, x)
|
19 |
+
Monomial{true}(w, updatez(y.z))
|
20 |
+
end
|
21 |
+
Base.:(*)(y::MonomialVector{true}, x::PolyVar{true}) = x * y
|
22 |
+
function Base.:(*)(x::PolyVar{true}, y::MonomialVector{true})
|
23 |
+
w, updatez = multiplyvar(y.vars, x)
|
24 |
+
MonomialVector{true}(w, updatez.(y.Z))
|
25 |
+
end
|
26 |
+
function multdivmono(v::Vector{PolyVar{true}}, x::Monomial{true}, op)
|
27 |
+
if v == x.vars
|
28 |
+
# /!\ no copy done here for efficiency, do not mess up with vars
|
29 |
+
w = v
|
30 |
+
updatez = z -> op.(z, x.z)
|
31 |
+
else
|
32 |
+
w, maps = mergevars([v, x.vars])
|
33 |
+
updatez = z -> begin
|
34 |
+
newz = zeros(Int, length(w))
|
35 |
+
I = maps[1]; i = 1; lI = length(I)
|
36 |
+
J = maps[2]; j = 1; lJ = length(J)
|
37 |
+
while i <= lI || j <= lJ
|
38 |
+
if i > lI || (j <= lJ && J[j] < I[i])
|
39 |
+
newz[J[j]] = op(0, x.z[j])
|
40 |
+
j += 1
|
41 |
+
elseif j > lJ || (i <= lI && I[i] < J[j])
|
42 |
+
newz[I[i]] = op(z[i], 0)
|
43 |
+
i += 1
|
44 |
+
else
|
45 |
+
@assert I[i] == J[j]
|
46 |
+
newz[I[i]] = op(z[i], x.z[j])
|
47 |
+
i += 1
|
48 |
+
j += 1
|
49 |
+
end
|
50 |
+
end
|
51 |
+
newz
|
52 |
+
end
|
53 |
+
end
|
54 |
+
w, updatez
|
55 |
+
end
|
56 |
+
function MP.mapexponents(f, x::Monomial{true}, y::Monomial{true})
|
57 |
+
w, updatez = multdivmono(x.vars, y, f)
|
58 |
+
Monomial{true}(w, updatez(x.z))
|
59 |
+
end
|
60 |
+
function Base.:(*)(x::Monomial{true}, y::MonomialVector{true})
|
61 |
+
w, updatez = multdivmono(y.vars, x, +)
|
62 |
+
MonomialVector{true}(w, updatez.(y.Z))
|
63 |
+
end
|
64 |
+
Base.:(*)(y::MonomialVector{true}, x::Monomial{true}) = x * y
|
65 |
+
Base.:(*)(x::Monomial{true}, y::PolyVar{true}) = y * x
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import Base.==
|
2 |
+
|
3 |
+
#Base.iszero(t::Term) = iszero(t.α)
|
4 |
+
Base.iszero(p::Polynomial) = isempty(p)
|
5 |
+
|
6 |
+
# TODO This should be in Base with T instead of PolyVar{C}.
|
7 |
+
# See https://github.com/blegat/MultivariatePolynomials.jl/issues/3
|
8 |
+
function (==)(x::Vector{PolyVar{C}}, y::Vector{PolyVar{C}}) where C
|
9 |
+
if length(x) != length(y)
|
10 |
+
false
|
11 |
+
else
|
12 |
+
#for (xi, yi) in zip(x, y)
|
13 |
+
for i in 1:length(x)
|
14 |
+
if x[i] != y[i]
|
15 |
+
return false
|
16 |
+
end
|
17 |
+
end
|
18 |
+
true
|
19 |
+
end
|
20 |
+
end
|
21 |
+
|
22 |
+
# Comparison of PolyVar
|
23 |
+
|
24 |
+
function (==)(x::PolyVar{C}, y::PolyVar{C}) where C
|
25 |
+
x.id == y.id
|
26 |
+
end
|
27 |
+
|
28 |
+
Base.isless(x::PolyVar{C}, y::PolyVar{C}) where C = isless(y.id, x.id)
|
29 |
+
|
30 |
+
# Comparison of Monomial
|
31 |
+
|
32 |
+
# graded lex ordering
|
33 |
+
function mycomp(x::Monomial{C}, y::Monomial{C}) where C
|
34 |
+
degx = degree(x)
|
35 |
+
degy = degree(y)
|
36 |
+
if degx != degy
|
37 |
+
degx - degy
|
38 |
+
else
|
39 |
+
i = j = 1
|
40 |
+
# since they have the same degree,
|
41 |
+
# if we get j > nvariables(y), the rest in x.z should be zeros
|
42 |
+
while i <= nvariables(x) && j <= nvariables(y)
|
43 |
+
if x.vars[i] > y.vars[j]
|
44 |
+
if x.z[i] == 0
|
45 |
+
i += 1
|
46 |
+
else
|
47 |
+
return 1
|
48 |
+
end
|
49 |
+
elseif x.vars[i] < y.vars[j]
|
50 |
+
if y.z[j] == 0
|
51 |
+
j += 1
|
52 |
+
else
|
53 |
+
return -1
|
54 |
+
end
|
55 |
+
elseif x.z[i] != y.z[j]
|
56 |
+
return x.z[i] - y.z[j]
|
57 |
+
else
|
58 |
+
i += 1
|
59 |
+
j += 1
|
60 |
+
end
|
61 |
+
end
|
62 |
+
0
|
63 |
+
end
|
64 |
+
end
|
65 |
+
|
66 |
+
function (==)(x::Monomial{C}, y::Monomial{C}) where C
|
67 |
+
mycomp(x, y) == 0
|
68 |
+
end
|
69 |
+
(==)(x::PolyVar{C}, y::Monomial{C}) where C = convert(Monomial{C}, x) == y
|
70 |
+
|
71 |
+
# graded lex ordering
|
72 |
+
function Base.isless(x::Monomial{C}, y::Monomial{C}) where C
|
73 |
+
mycomp(x, y) < 0
|
74 |
+
end
|
75 |
+
Base.isless(x::Monomial{C}, y::PolyVar{C}) where C = isless(x, convert(Monomial{C}, y))
|
76 |
+
Base.isless(x::PolyVar{C}, y::Monomial{C}) where C = isless(convert(Monomial{C}, x), y)
|
77 |
+
|
78 |
+
# Comparison of MonomialVector
|
79 |
+
function (==)(x::MonomialVector{C}, y::MonomialVector{C}) where C
|
80 |
+
if length(x.Z) != length(y.Z)
|
81 |
+
return false
|
82 |
+
end
|
83 |
+
allvars, maps = mergevars([_vars(x), _vars(y)])
|
84 |
+
# Should be sorted in the same order since the non-common
|
85 |
+
# polyvar should have exponent 0
|
86 |
+
for (a, b) in zip(x.Z, y.Z)
|
87 |
+
A = zeros(length(allvars))
|
88 |
+
B = zeros(length(allvars))
|
89 |
+
A[maps[1]] = a
|
90 |
+
B[maps[2]] = b
|
91 |
+
if A != B
|
92 |
+
return false
|
93 |
+
end
|
94 |
+
end
|
95 |
+
return true
|
96 |
+
end
|
97 |
+
(==)(mv::AbstractVector, x::MonomialVector) = monovec(mv) == x
|
98 |
+
(==)(x::MonomialVector, mv::AbstractVector) = x == monovec(mv)
|
99 |
+
|
100 |
+
# Comparison of Term
|
101 |
+
function (==)(p::Polynomial{C}, q::Polynomial{C}) where {C}
|
102 |
+
# terms should be sorted and without zeros
|
103 |
+
if length(p) != length(q)
|
104 |
+
return false
|
105 |
+
end
|
106 |
+
for i in 1:length(p)
|
107 |
+
if p.x[i] != q.x[i]
|
108 |
+
# There should not be zero terms
|
109 |
+
@assert p.a[i] != 0
|
110 |
+
@assert q.a[i] != 0
|
111 |
+
return false
|
112 |
+
end
|
113 |
+
if p.a[i] != q.a[i]
|
114 |
+
return false
|
115 |
+
end
|
116 |
+
end
|
117 |
+
return true
|
118 |
+
end
|
119 |
+
|
120 |
+
function grlex(x::Vector{Int}, y::Vector{Int})
|
121 |
+
@assert length(x) == length(y)
|
122 |
+
degx = sum(x)
|
123 |
+
degy = sum(y)
|
124 |
+
if degx != degy
|
125 |
+
degx < degy
|
126 |
+
else
|
127 |
+
for (a, b) in zip(x, y)
|
128 |
+
if a < b
|
129 |
+
return true
|
130 |
+
elseif a > b
|
131 |
+
return false
|
132 |
+
end
|
133 |
+
end
|
134 |
+
false
|
135 |
+
end
|
136 |
+
end
|
137 |
+
|
138 |
+
function Base.isapprox(p::Polynomial{C, S}, q::Polynomial{C, T};
|
139 |
+
rtol::Real=Base.rtoldefault(S, T, 0), atol::Real=0,
|
140 |
+
ztol::Real=iszero(atol) ? Base.rtoldefault(S, T, 0) : atol) where {C, S, T}
|
141 |
+
i = j = 1
|
142 |
+
while i <= length(p.x) || j <= length(q.x)
|
143 |
+
if i > length(p.x) || (j <= length(q.x) && q.x[j] > p.x[i])
|
144 |
+
if !isapproxzero(q.a[j], ztol=ztol)
|
145 |
+
return false
|
146 |
+
end
|
147 |
+
j += 1
|
148 |
+
elseif j > length(q.x) || p.x[i] > q.x[j]
|
149 |
+
if !isapproxzero(p.a[i], ztol=ztol)
|
150 |
+
return false
|
151 |
+
end
|
152 |
+
i += 1
|
153 |
+
else
|
154 |
+
if !isapprox(p.a[i], q.a[j], rtol=rtol, atol=atol)
|
155 |
+
return false
|
156 |
+
end
|
157 |
+
i += 1
|
158 |
+
j += 1
|
159 |
+
end
|
160 |
+
end
|
161 |
+
true
|
162 |
+
end
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
function MP.differentiate(m::Monomial{C}, x::PolyVar{C}) where C
|
2 |
+
i = findfirst(isequal(x), _vars(m))
|
3 |
+
if (i == nothing || i == 0) || m.z[i] == 0
|
4 |
+
zeroterm(m)
|
5 |
+
else
|
6 |
+
z = copy(m.z)
|
7 |
+
z[i] -= 1
|
8 |
+
m.z[i] * Monomial(_vars(m), z)
|
9 |
+
end
|
10 |
+
end
|
11 |
+
|
12 |
+
function MP.differentiate(p::Polynomial{C, T}, x::PolyVar{C}) where {C, T}
|
13 |
+
# grlex order preserved
|
14 |
+
i = something(findfirst(isequal(x), _vars(p)), 0)
|
15 |
+
S = typeof(zero(T) * 0)
|
16 |
+
if iszero(i)
|
17 |
+
zero(Polynomial{C, S})
|
18 |
+
else
|
19 |
+
keep = findall(z -> z[i] > 0, p.x.Z)
|
20 |
+
Z = copy.(p.x.Z[keep])
|
21 |
+
a = Vector{S}(undef, length(keep))
|
22 |
+
for j in 1:length(Z)
|
23 |
+
a[j] = p.a[keep[j]] * Z[j][i]
|
24 |
+
Z[j][i] -= 1
|
25 |
+
end
|
26 |
+
Polynomial(a, MonomialVector(_vars(p), Z))
|
27 |
+
end
|
28 |
+
end
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
function MP.divides(m1::Monomial, m2::Monomial)
|
2 |
+
e1 = exponents(m1)
|
3 |
+
v1 = variables(m1)
|
4 |
+
e2 = exponents(m2)
|
5 |
+
v2 = variables(m2)
|
6 |
+
i = 1; lI = length(e1)
|
7 |
+
j = 1; lJ = length(e2)
|
8 |
+
while i <= lI || j <= lJ
|
9 |
+
if i > lI || (j <= lJ && v2[j] > v1[i])
|
10 |
+
j += 1
|
11 |
+
elseif j > lJ || (i <= lI && v1[i] > v2[j])
|
12 |
+
iszero(e1[i]) || return false
|
13 |
+
i += 1
|
14 |
+
else
|
15 |
+
@assert v1[i] == v2[j]
|
16 |
+
e1[i] <= e2[j] || return false
|
17 |
+
i += 1
|
18 |
+
j += 1
|
19 |
+
end
|
20 |
+
end
|
21 |
+
return true
|
22 |
+
end
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export Monomial
|
2 |
+
|
3 |
+
const TupOrVec{T} = Union{AbstractVector{T}, Tuple{Vararg{T}}}
|
4 |
+
|
5 |
+
# Invariant:
|
6 |
+
# vars is increasing
|
7 |
+
# z may contain 0's (otherwise, getindex of MonomialVector would be inefficient)
|
8 |
+
struct Monomial{C} <: AbstractMonomial
|
9 |
+
vars::Vector{PolyVar{C}}
|
10 |
+
z::Vector{Int}
|
11 |
+
|
12 |
+
function Monomial{C}(vars::Vector{PolyVar{C}}, z::Vector{Int}) where {C}
|
13 |
+
if length(vars) != length(z)
|
14 |
+
throw(ArgumentError("There should be as many vars than exponents"))
|
15 |
+
end
|
16 |
+
new(vars, z)
|
17 |
+
end
|
18 |
+
end
|
19 |
+
|
20 |
+
Monomial{C}(vars::Tuple{Vararg{PolyVar{C}}}, z::Vector{Int}) where C = Monomial{C}([vars...], z)
|
21 |
+
|
22 |
+
iscomm(::Type{Monomial{C}}) where C = C
|
23 |
+
Monomial{C}() where C = Monomial{C}(PolyVar{C}[], Int[])
|
24 |
+
Monomial(vars::TupOrVec{PolyVar{C}}, z::Vector{Int}) where C = Monomial{C}(vars, z)
|
25 |
+
function Base.convert(::Type{Monomial{C}}, x::PolyVar{C}) where C
|
26 |
+
return Monomial{C}([x], [1])
|
27 |
+
end
|
28 |
+
Monomial(x::PolyVar{C}) where C = convert(Monomial{C}, x)
|
29 |
+
function MP.convertconstant(::Type{Monomial{C}}, α) where C
|
30 |
+
α == 1 || error("Cannot convert $α to a Monomial{$C} as it is not one")
|
31 |
+
Monomial{C}(PolyVar{C}[], Int[])
|
32 |
+
end
|
33 |
+
|
34 |
+
# defaults to commutative so that `Monomial(1)` is consistent with TypedPolynomials
|
35 |
+
Monomial(α::Number) = convert(Monomial{true}, α)
|
36 |
+
|
37 |
+
Base.broadcastable(m::Monomial) = Ref(m)
|
38 |
+
Base.copy(m::M) where {M<:Monomial} = M(m.vars, copy(m.z))
|
39 |
+
|
40 |
+
# Generate canonical reperesentation by removing variables that are not used
|
41 |
+
function canonical(m::Monomial)
|
42 |
+
list = m.z .> 0
|
43 |
+
Monomial(_vars(m)[list], m.z[list])
|
44 |
+
end
|
45 |
+
function Base.hash(x::Monomial, u::UInt)
|
46 |
+
cx = canonical(x)
|
47 |
+
if iszero(nvariables(cx))
|
48 |
+
hash(1, u)
|
49 |
+
elseif nvariables(cx) == 1 && cx.z[1] == 1
|
50 |
+
hash(cx.vars[1], u)
|
51 |
+
else # TODO reduce power in MP
|
52 |
+
hash(_vars(cx), hash(cx.z, u))
|
53 |
+
end
|
54 |
+
end
|
55 |
+
|
56 |
+
MP.exponents(m::Monomial) = m.z
|
57 |
+
# /!\ vars not copied, do not mess with vars
|
58 |
+
_vars(m::Union{Monomial}) = m.vars
|
59 |
+
|
60 |
+
MP.monomial(m::Monomial) = m
|
61 |
+
# Does m1 divides m2 ?
|
62 |
+
#function MP.divides(m1::Monomial, m2::Monomial)
|
63 |
+
# i = j = 1
|
64 |
+
# while i <= length(m1.z) && j <= length(m2.z)
|
65 |
+
# if m1.vars[i] == m2.vars[j]
|
66 |
+
# if m1.z[i] > m2.z[j]
|
67 |
+
# return false
|
68 |
+
# end
|
69 |
+
# i += 1
|
70 |
+
# j += 1
|
71 |
+
# elseif m1.vars[i] > m2.vars[j]
|
72 |
+
# if !iszero(m1.z[i])
|
73 |
+
# return false
|
74 |
+
# end
|
75 |
+
# i += 1
|
76 |
+
# else
|
77 |
+
# j += 1
|
78 |
+
# end
|
79 |
+
# end
|
80 |
+
# i > length(m1.z)
|
81 |
+
#end
|
@@ -0,0 +1,241 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export MonomialVector
|
2 |
+
|
3 |
+
# Invariant: Always sorted and no zero vector
|
4 |
+
struct MonomialVector{C} <: AbstractVector{Monomial{C}}
|
5 |
+
vars::Vector{PolyVar{C}}
|
6 |
+
Z::Vector{Vector{Int}}
|
7 |
+
|
8 |
+
function MonomialVector{C}(vars::Vector{PolyVar{C}}, Z::Vector{Vector{Int}}) where {C}
|
9 |
+
@assert !C || issorted(vars, rev=true)
|
10 |
+
@assert all(z -> length(z) == length(vars), Z)
|
11 |
+
@assert issorted(Z, rev=true, lt=grlex)
|
12 |
+
new(vars, Z)
|
13 |
+
end
|
14 |
+
end
|
15 |
+
MonomialVector(vars::Vector{PolyVar{C}}, Z::Vector{Vector{Int}}) where {C} = MonomialVector{C}(vars, Z)
|
16 |
+
MonomialVector{C}() where {C} = MonomialVector{C}(PolyVar{C}[], Vector{Int}[])
|
17 |
+
|
18 |
+
# Generate canonical reperesentation by removing variables that are not used
|
19 |
+
function canonical(m::MonomialVector)
|
20 |
+
v = zeros(Bool, nvariables(m))
|
21 |
+
for z in m.Z
|
22 |
+
v = [v[i] || z[i] > 0 for i in eachindex(v)]
|
23 |
+
end
|
24 |
+
MonomialVector(_vars(m)[v], Vector{Int}[z[v] for z in m.Z])
|
25 |
+
end
|
26 |
+
|
27 |
+
function Base.hash(m::MonomialVector, u::UInt)
|
28 |
+
cm = canonical(m)
|
29 |
+
if length(cm.Z) == 0
|
30 |
+
hash([], u)
|
31 |
+
elseif length(cm.Z) == 1
|
32 |
+
hash(Monomial(_vars(cm), cm.Z[1]), u)
|
33 |
+
else
|
34 |
+
hash(_vars(cm), hash(cm.Z, hash(u)))
|
35 |
+
end
|
36 |
+
end
|
37 |
+
|
38 |
+
# /!\ vars not copied, do not mess with vars
|
39 |
+
Base.copy(m::MV) where {MV<:MonomialVector} = MV(m.vars, copy(m.Z))
|
40 |
+
function Base.getindex(x::MV, I) where {MV<:MonomialVector}
|
41 |
+
MV(x.vars, x.Z[sort(I)])
|
42 |
+
end
|
43 |
+
Base.getindex(x::MonomialVector, i::Integer) = Monomial(x.vars, x.Z[i])
|
44 |
+
|
45 |
+
Base.firstindex(x::MonomialVector) = firstindex(x.Z)
|
46 |
+
Base.lastindex(x::MonomialVector) = lastindex(x.Z)
|
47 |
+
Base.size(x::MonomialVector) = (length(x),)
|
48 |
+
Base.length(x::MonomialVector) = length(x.Z)
|
49 |
+
Base.isempty(x::MonomialVector) = length(x) == 0
|
50 |
+
Base.iterate(x::MonomialVector) = isempty(x) ? nothing : (x[1], 1)
|
51 |
+
function Base.iterate(x::MonomialVector, state::Int)
|
52 |
+
state < length(x) ? (x[state+1], state+1) : nothing
|
53 |
+
end
|
54 |
+
|
55 |
+
MultivariatePolynomials.extdegree(x::MonomialVector) = isempty(x) ? (0, 0) : extrema(sum.(x.Z))
|
56 |
+
MultivariatePolynomials.mindegree(x::MonomialVector) = isempty(x) ? 0 : minimum(sum.(x.Z))
|
57 |
+
MultivariatePolynomials.maxdegree(x::MonomialVector) = isempty(x) ? 0 : maximum(sum.(x.Z))
|
58 |
+
|
59 |
+
_vars(m::Union{Monomial, MonomialVector}) = m.vars
|
60 |
+
|
61 |
+
# Recognize arrays of monomials of this module
|
62 |
+
# [x, y] -> Vector{PolyVar}
|
63 |
+
# [x, x*y] -> Vector{Monomial}
|
64 |
+
# [1, x] -> Vector{Term{Int}}
|
65 |
+
const DMonoVecElemNonConstant{C} = Union{PolyVar{C}, Monomial{C}, Term{C}}
|
66 |
+
# [1] -> Vector{Int}
|
67 |
+
const DMonoVecElem{C} = Union{Int, DMonoVecElemNonConstant{C}}
|
68 |
+
const DMonoVec{C} = AbstractVector{<:DMonoVecElem{C}}
|
69 |
+
|
70 |
+
MP.emptymonovec(vars::AbstractVector{PolyVar{C}}) where {C} = MonomialVector{C}(vars, Vector{Int}[])
|
71 |
+
MP.emptymonovec(t::DMonoVecElemNonConstant) = emptymonovec(_vars(t))
|
72 |
+
MP.emptymonovec(::Type{<:DMonoVecElemNonConstant{C}}) where {C} = MonomialVector{C}()
|
73 |
+
|
74 |
+
function fillZfordeg!(Z, n, deg, ::Type{Val{true}}, filter::Function)
|
75 |
+
z = zeros(Int, n)
|
76 |
+
z[1] = deg
|
77 |
+
while true
|
78 |
+
if filter(z)
|
79 |
+
push!(Z, z)
|
80 |
+
z = copy(z)
|
81 |
+
end
|
82 |
+
if z[end] == deg
|
83 |
+
break
|
84 |
+
end
|
85 |
+
sum = 1
|
86 |
+
for j in (n-1):-1:1
|
87 |
+
if z[j] != 0
|
88 |
+
z[j] -= 1
|
89 |
+
z[j+1] += sum
|
90 |
+
break
|
91 |
+
else
|
92 |
+
sum += z[j+1]
|
93 |
+
z[j+1] = 0
|
94 |
+
end
|
95 |
+
end
|
96 |
+
end
|
97 |
+
end
|
98 |
+
function fillZrec!(Z, z, i, n, deg, filter::Function)
|
99 |
+
if deg == 0
|
100 |
+
if filter(z)
|
101 |
+
push!(Z, copy(z))
|
102 |
+
end
|
103 |
+
else
|
104 |
+
for i in i:i+n-1
|
105 |
+
z[i] += 1
|
106 |
+
fillZrec!(Z, z, i, n, deg-1, filter)
|
107 |
+
z[i] -= 1
|
108 |
+
end
|
109 |
+
end
|
110 |
+
end
|
111 |
+
function fillZfordeg!(Z, n, deg, ::Type{Val{false}}, filter::Function)
|
112 |
+
z = zeros(Int, deg * n - deg + 1)
|
113 |
+
fillZrec!(Z, z, 1, n, deg, filter)
|
114 |
+
end
|
115 |
+
# List exponents in decreasing Graded Lexicographic Order
|
116 |
+
function getZfordegs(n, degs::AbstractVector{Int}, ::Type{Val{C}}, filter::Function) where C
|
117 |
+
Z = Vector{Vector{Int}}()
|
118 |
+
for deg in sort(degs, rev=true)
|
119 |
+
fillZfordeg!(Z, n, deg, Val{C}, filter)
|
120 |
+
end
|
121 |
+
@assert issorted(Z, rev=true, lt=grlex)
|
122 |
+
Z
|
123 |
+
end
|
124 |
+
|
125 |
+
function MonomialVector(vars::Vector{PolyVar{true}}, degs::AbstractVector{Int}, filter::Function = x->true)
|
126 |
+
MonomialVector{true}(vars, getZfordegs(length(vars), degs, Val{true}, z -> filter(Monomial(vars, z))))
|
127 |
+
end
|
128 |
+
|
129 |
+
function getvarsforlength(vars::Vector{PolyVar{false}}, len::Int)
|
130 |
+
n = length(vars)
|
131 |
+
map(i -> vars[((i-1) % n) + 1], 1:len)
|
132 |
+
end
|
133 |
+
function MonomialVector(vars::Vector{PolyVar{false}}, degs::AbstractVector{Int}, filter::Function = x->true)
|
134 |
+
Z = getZfordegs(length(vars), degs, Val{false}, z -> filter(Monomial(getvarsforlength(vars, length(z)), z)))
|
135 |
+
v = isempty(Z) ? vars : getvarsforlength(vars, length(first(Z)))
|
136 |
+
MonomialVector{false}(v, Z)
|
137 |
+
end
|
138 |
+
MonomialVector(vars::Vector{<:PolyVar}, degs::Int, filter::Function = x->true) = MonomialVector(vars, [degs], filter)
|
139 |
+
|
140 |
+
MP.monomials(vars::AbstractVector{<:PolyVar}, args...) = MonomialVector(vars, args...)
|
141 |
+
MP.monomials(vars::Tuple{Vararg{PolyVar}}, args...) = monomials([vars...], args...)
|
142 |
+
|
143 |
+
#function MP.monomials(vars::TupOrVec{PolyVar{true}}, degs::AbstractVector{Int}, filter::Function = x->true)
|
144 |
+
# Z = getZfordegs(length(vars), degs, true, z -> filter(Monomial(vars, z)))
|
145 |
+
# [Monomial{true}(vars, z) for z in Z]
|
146 |
+
#end
|
147 |
+
#function MP.monomials(vars::TupOrVec{PolyVar{false}}, degs::AbstractVector{Int}, filter::Function = x->true)
|
148 |
+
# Z = getZfordegs(length(vars), degs, false, z -> filter(Monomial(vars, z)))
|
149 |
+
# v = isempty(Z) ? vars : getvarsforlength(vars, length(first(Z)))
|
150 |
+
# [Monomial{false}(v, z) for z in Z]
|
151 |
+
#end
|
152 |
+
#MP.monomials(vars::TupOrVec{PV}, degs::Int, filter::Function = x->true) where {PV<:PolyVar} = monomials(vars, [degs], filter)
|
153 |
+
|
154 |
+
function buildZvarsvec(::Type{PV}, X::DMonoVec) where {PV<:PolyVar}
|
155 |
+
varsvec = Vector{PV}[ (isa(x, DMonoVecElemNonConstant) ? _vars(x) : PolyVar[]) for x in X ]
|
156 |
+
allvars, maps = mergevars(varsvec)
|
157 |
+
nvars = length(allvars)
|
158 |
+
Z = [zeros(Int, nvars) for i in 1:length(X)]
|
159 |
+
offset = 0
|
160 |
+
for (i, x) in enumerate(X)
|
161 |
+
if isa(x, PolyVar)
|
162 |
+
@assert length(maps[i]) == 1
|
163 |
+
z = [1]
|
164 |
+
elseif isa(x, Monomial)
|
165 |
+
z = x.z
|
166 |
+
elseif isa(x, Term)
|
167 |
+
z = x.x.z
|
168 |
+
else
|
169 |
+
@assert isa(x, Int)
|
170 |
+
z = Int[]
|
171 |
+
end
|
172 |
+
Z[i][maps[i]] = z
|
173 |
+
end
|
174 |
+
allvars, Z
|
175 |
+
end
|
176 |
+
|
177 |
+
MP.sortmonovec(X::MonomialVector) = (1:length(X), X)
|
178 |
+
function _sortmonovec(X::DMonoVec{C}) where {C}
|
179 |
+
allvars, Z = buildZvarsvec(PolyVar{C}, X)
|
180 |
+
σ = sortperm(Z, rev=true, lt=grlex)
|
181 |
+
allvars, Z, σ
|
182 |
+
end
|
183 |
+
function _removedups!(Z::Vector{Vector{Int}}, σ::Vector{Int})
|
184 |
+
dups = findall(i -> Z[σ[i]] == Z[σ[i-1]], 2:length(σ))
|
185 |
+
deleteat!(σ, dups)
|
186 |
+
end
|
187 |
+
function MP.sortmonovec(X::DMonoVec{C}) where {C}
|
188 |
+
if isempty(X)
|
189 |
+
Int[], MonomialVector{C}()
|
190 |
+
else
|
191 |
+
allvars, Z, σ = _sortmonovec(X)
|
192 |
+
_removedups!(Z, σ)
|
193 |
+
σ, MonomialVector{C}(allvars, Z[σ])
|
194 |
+
end
|
195 |
+
end
|
196 |
+
|
197 |
+
function MonomialVector{C}(X::DMonoVec{C}) where C
|
198 |
+
allvars, Z = buildZvarsvec(PolyVar{C}, X)
|
199 |
+
sort!(Z, rev=true, lt=grlex)
|
200 |
+
dups = findall(i -> Z[i] == Z[i-1], 2:length(Z))
|
201 |
+
deleteat!(Z, dups)
|
202 |
+
MonomialVector{C}(allvars, Z)
|
203 |
+
end
|
204 |
+
function MonomialVector(X)
|
205 |
+
monovectype(X)(X)
|
206 |
+
end
|
207 |
+
|
208 |
+
MP.monovectype(X::Union{DMonoVecElemNonConstant{C}, Type{<:DMonoVecElemNonConstant{C}}, DMonoVec{C}, Type{<:DMonoVec{C}}}) where {C} = MonomialVector{C}
|
209 |
+
function MP.monovec(X::DMonoVec)
|
210 |
+
MonomialVector(X)
|
211 |
+
end
|
212 |
+
MP.monovec(a, mv::MonomialVector) = (a, mv)
|
213 |
+
|
214 |
+
function MP.mergemonovec(ms::Vector{MonomialVector{C}}) where {C}
|
215 |
+
m = length(ms)
|
216 |
+
I = ones(Int, length(ms))
|
217 |
+
L = length.(ms)
|
218 |
+
X = Vector{Monomial{C}}()
|
219 |
+
while any(I .<= L)
|
220 |
+
max = nothing
|
221 |
+
for i in 1:m
|
222 |
+
if I[i] <= L[i]
|
223 |
+
x = ms[i][I[i]]
|
224 |
+
if max === nothing || max < x
|
225 |
+
max = x
|
226 |
+
end
|
227 |
+
end
|
228 |
+
end
|
229 |
+
@assert max !== nothing
|
230 |
+
# to ensure that max is no more a union
|
231 |
+
max === nothing && return X
|
232 |
+
push!(X, max)
|
233 |
+
for i in 1:m
|
234 |
+
if I[i] <= L[i] && max == ms[i][I[i]]
|
235 |
+
I[i] += 1
|
236 |
+
end
|
237 |
+
end
|
238 |
+
end
|
239 |
+
# There is no duplicate by construction
|
240 |
+
return MonomialVector{C}(buildZvarsvec(PolyVar{C}, X)...)
|
241 |
+
end
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
function multiplyexistingvar(v::Vector{PolyVar{C}}, x::PolyVar{C}, i::Int) where {C}
|
2 |
+
updatez = z -> begin
|
3 |
+
newz = copy(z)
|
4 |
+
newz[i] += 1
|
5 |
+
newz
|
6 |
+
end
|
7 |
+
# /!\ v not copied for efficiency, do not mess up with vars
|
8 |
+
v, updatez
|
9 |
+
end
|
10 |
+
function insertvar(v::Vector{PolyVar{C}}, x::PolyVar{C}, i::Int) where {C}
|
11 |
+
n = length(v)
|
12 |
+
I = 1:i-1
|
13 |
+
J = i:n
|
14 |
+
K = J.+1
|
15 |
+
w = Vector{PolyVar{C}}(undef, n+1)
|
16 |
+
w[I] = v[I]
|
17 |
+
w[i] = x
|
18 |
+
w[K] = v[J]
|
19 |
+
updatez = z -> begin
|
20 |
+
newz = Vector{Int}(undef, n+1)
|
21 |
+
newz[I] = z[I]
|
22 |
+
newz[i] = 1
|
23 |
+
newz[K] = z[J]
|
24 |
+
newz
|
25 |
+
end
|
26 |
+
w, updatez
|
27 |
+
end
|
28 |
+
|
29 |
+
include("cmult.jl")
|
30 |
+
include("ncmult.jl")
|
31 |
+
|
32 |
+
MP.multconstant(α, x::Monomial) = Term(α, x)
|
33 |
+
MP.mapcoefficientsnz(f::Function, p::Polynomial) = Polynomial(f.(p.a), p.x)
|
34 |
+
|
35 |
+
# I do not want to cast x to TermContainer because that would force the promotion of eltype(q) with Int
|
36 |
+
function Base.:(*)(x::DMonomialLike, p::Polynomial)
|
37 |
+
# /!\ No copy of a is done
|
38 |
+
Polynomial(p.a, x*p.x)
|
39 |
+
end
|
40 |
+
function Base.:(*)(x::DMonomialLike{false}, p::Polynomial)
|
41 |
+
# /!\ No copy of a is done
|
42 |
+
# Order may change, e.g. y * (x + y) = y^2 + yx
|
43 |
+
Polynomial(monovec(p.a, [x*m for m in p.x])...)
|
44 |
+
end
|
45 |
+
function Base.:(*)(p::Polynomial, x::DMonomialLike)
|
46 |
+
# /!\ No copy of a is done
|
47 |
+
Polynomial(p.a, p.x*x)
|
48 |
+
end
|
49 |
+
|
50 |
+
function _term_poly_mult(t::Term{C, S}, p::Polynomial{C, T}, op::Function) where {C, S, T}
|
51 |
+
U = Base.promote_op(op, S, T)
|
52 |
+
if iszero(t)
|
53 |
+
zero(Polynomial{C, U})
|
54 |
+
else
|
55 |
+
n = nterms(p)
|
56 |
+
allvars, maps = mergevars([t.x.vars, p.x.vars])
|
57 |
+
nv = length(allvars)
|
58 |
+
# Necessary to annotate the type in case it is empty
|
59 |
+
Z = Vector{Int}[zeros(Int, nv) for i in 1:n]
|
60 |
+
for i in 1:n
|
61 |
+
Z[i][maps[1]] = t.x.z
|
62 |
+
Z[i][maps[2]] += p.x.Z[i]
|
63 |
+
end
|
64 |
+
Polynomial(op.(t.α, p.a), MonomialVector(allvars, Z))
|
65 |
+
end
|
66 |
+
end
|
67 |
+
Base.:(*)(p::Polynomial, t::Term) = _term_poly_mult(t, p, (α, β) -> β * α)
|
68 |
+
Base.:(*)(t::Term, p::Polynomial) = _term_poly_mult(t, p, *)
|
69 |
+
_sumprod(a, b) = a * b + a * b
|
70 |
+
function Base.:(*)(p::Polynomial{C, S}, q::Polynomial{C, T}) where {C, S, T}
|
71 |
+
U = Base.promote_op(_sumprod, S, T)
|
72 |
+
if iszero(p) || iszero(q)
|
73 |
+
zero(Polynomial{C, U})
|
74 |
+
else
|
75 |
+
samevars = _vars(p) == _vars(q)
|
76 |
+
if samevars
|
77 |
+
allvars = _vars(p)
|
78 |
+
else
|
79 |
+
allvars, maps = mergevars([_vars(p), _vars(q)])
|
80 |
+
end
|
81 |
+
N = length(p)*length(q)
|
82 |
+
Z = Vector{Vector{Int}}(undef, N)
|
83 |
+
a = Vector{U}(undef, N)
|
84 |
+
i = 0
|
85 |
+
for u in p
|
86 |
+
for v in q
|
87 |
+
if samevars
|
88 |
+
z = u.x.z + v.x.z
|
89 |
+
else
|
90 |
+
z = zeros(Int, length(allvars))
|
91 |
+
z[maps[1]] += u.x.z
|
92 |
+
z[maps[2]] += v.x.z
|
93 |
+
end
|
94 |
+
i += 1
|
95 |
+
Z[i] = z
|
96 |
+
a[i] = u.α * v.α
|
97 |
+
end
|
98 |
+
end
|
99 |
+
polynomialclean(allvars, a, Z)
|
100 |
+
end
|
101 |
+
end
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
function Base.:(*)(x::PolyVar{false}, y::PolyVar{false})
|
2 |
+
if x === y
|
3 |
+
Monomial{false}([x], [2])
|
4 |
+
else
|
5 |
+
Monomial{false}([x, y], [1, 1])
|
6 |
+
end
|
7 |
+
end
|
8 |
+
|
9 |
+
function multiplyvar(v::Vector{PolyVar{false}}, z::Vector{Int}, x::PolyVar{false})
|
10 |
+
i = length(v)
|
11 |
+
while i > 0 && z[i] == 0
|
12 |
+
i -= 1
|
13 |
+
end
|
14 |
+
if v[i] == x
|
15 |
+
multiplyexistingvar(v, x, i)
|
16 |
+
else
|
17 |
+
# ---->
|
18 |
+
# \ |\ |\
|
19 |
+
# \ | \ | \
|
20 |
+
# \| \| \
|
21 |
+
# If z[i] > x, we wait either for a rise (v[i] > v[i-1]) or v[i] < x
|
22 |
+
# Otherwise, we first wait for a drop and then wait for the same thing
|
23 |
+
ndrop = 0
|
24 |
+
if v[i] > x
|
25 |
+
droplim1 = 0
|
26 |
+
droplim2 = 1
|
27 |
+
else
|
28 |
+
droplim1 = 1
|
29 |
+
droplim2 = 2
|
30 |
+
end
|
31 |
+
i += 1
|
32 |
+
while i <= length(v) && v[i] != x
|
33 |
+
if v[i] > v[i-1]
|
34 |
+
ndrop += 1
|
35 |
+
end
|
36 |
+
if ndrop >= droplim2 || (ndrop >= droplim1 && v[i] < x)
|
37 |
+
break
|
38 |
+
end
|
39 |
+
i += 1
|
40 |
+
end
|
41 |
+
|
42 |
+
if i <= length(v) && v[i] == x
|
43 |
+
multiplyexistingvar(v, x, i)
|
44 |
+
else
|
45 |
+
insertvar(v, x, i)
|
46 |
+
end
|
47 |
+
end
|
48 |
+
end
|
49 |
+
function multiplyvar(x::PolyVar{false}, v::Vector{PolyVar{false}}, z::Vector{Int})
|
50 |
+
i = 1
|
51 |
+
while i <= length(v) && z[i] == 0
|
52 |
+
i += 1
|
53 |
+
end
|
54 |
+
if v[i] == x
|
55 |
+
multiplyexistingvar(v, x, i)
|
56 |
+
else
|
57 |
+
# <----
|
58 |
+
# \ |\ |\
|
59 |
+
# \ | \ | \
|
60 |
+
# \| \| \
|
61 |
+
# If z[i] < x, we wait either for a drop (v[i] < v[i+1]) or v[i] > x
|
62 |
+
# Otherwise, we first wait for a drop and then wait for the same thing
|
63 |
+
ndrop = 0
|
64 |
+
if v[i] < x
|
65 |
+
droplim1 = 0
|
66 |
+
droplim2 = 1
|
67 |
+
else
|
68 |
+
droplim1 = 1
|
69 |
+
droplim2 = 2
|
70 |
+
end
|
71 |
+
i -= 1
|
72 |
+
while i > 0 && v[i] != x
|
73 |
+
if v[i] < v[i+1]
|
74 |
+
ndrop += 1
|
75 |
+
end
|
76 |
+
if ndrop >= droplim2 || (ndrop >= droplim1 && v[i] > x)
|
77 |
+
break
|
78 |
+
end
|
79 |
+
i -= 1
|
80 |
+
end
|
81 |
+
if i > 0 && v[i] == x
|
82 |
+
multiplyexistingvar(v, x, i)
|
83 |
+
else
|
84 |
+
insertvar(v, x, i+1)
|
85 |
+
end
|
86 |
+
end
|
87 |
+
end
|
88 |
+
function Base.:(*)(x::PolyVar{false}, y::Monomial{false})
|
89 |
+
w, updatez = multiplyvar(x, y.vars, y.z)
|
90 |
+
Monomial{false}(w, updatez(y.z))
|
91 |
+
end
|
92 |
+
function Base.:(*)(y::Monomial{false}, x::PolyVar{false})
|
93 |
+
w, updatez = multiplyvar(y.vars, y.z, x)
|
94 |
+
Monomial{false}(w, updatez(y.z))
|
95 |
+
end
|
96 |
+
|
97 |
+
function Base.:(*)(x::Monomial{false}, y::Monomial{false})
|
98 |
+
i = findlast(z -> z > 0, x.z)
|
99 |
+
if i == nothing || i == 0
|
100 |
+
return y
|
101 |
+
end
|
102 |
+
j = findfirst(z -> z > 0, y.z)
|
103 |
+
if j == nothing || j == 0
|
104 |
+
return x
|
105 |
+
end
|
106 |
+
if x.vars[i] == y.vars[j]
|
107 |
+
w = [x.vars[1:i]; y.vars[j+1:end]]
|
108 |
+
z = [x.z[1:i-1]; x.z[i] + y.z[j]; y.z[j+1:end]]
|
109 |
+
else
|
110 |
+
w = [x.vars[1:i]; y.vars[j:end]]
|
111 |
+
z = [x.z[1:i]; y.z[j:end]]
|
112 |
+
end
|
113 |
+
return Monomial{false}(w, z)
|
114 |
+
end
|
115 |
+
|
116 |
+
function Base.:(*)(y::MonomialVector{false}, x::DMonomialLike{false})
|
117 |
+
MonomialVector{false}([yi * x for yi in y])
|
118 |
+
end
|
119 |
+
function Base.:(*)(x::DMonomialLike{false}, y::MonomialVector{false})
|
120 |
+
# The order may change
|
121 |
+
# Example: y * [x^2, y^2] == [y^3, yx^2]
|
122 |
+
MonomialVector{false}([x * yi for yi in y])
|
123 |
+
end
|
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# In Base/intfuncs.jl, x^p returns zero(x) when p == 0
|
2 |
+
# Since one(PolyVar) and one(Monomial) do not return
|
3 |
+
# a PolyVar and a Monomial, this results in type instability
|
4 |
+
# Defining the specific methods solve this problem and also make
|
5 |
+
# them a lot faster
|
6 |
+
Base.:(^)(x::PolyVar{C}, i::Int) where {C} = Monomial{C}([x], [i])
|
7 |
+
Base.:(^)(x::Monomial{true}, i::Int) = Monomial{true}(x.vars, i*x.z)
|
8 |
+
|
9 |
+
myminivect(x::T, y::T) where {T} = [x, y]
|
10 |
+
function myminivect(x::S, y::T) where {S,T}
|
11 |
+
U = promote_type(S, T)
|
12 |
+
[U(x), U(y)]
|
13 |
+
end
|
14 |
+
|
15 |
+
Base.:(+)(x::DMonomialLike, y::DMonomialLike) = Term(x) + Term(y)
|
16 |
+
Base.:(-)(x::DMonomialLike, y::DMonomialLike) = Term(x) - Term(y)
|
17 |
+
|
18 |
+
_getindex(p::Polynomial, i) = p[i]
|
19 |
+
_getindex(t::Term, i) = t
|
20 |
+
function plusorminus(p::TermPoly{C, S}, q::TermPoly{C, T}, op) where {C, S, T}
|
21 |
+
varsvec = [_vars(p), _vars(q)]
|
22 |
+
allvars, maps = mergevars(varsvec)
|
23 |
+
nvars = length(allvars)
|
24 |
+
U = Base.promote_op(op, S, T)
|
25 |
+
a = Vector{U}()
|
26 |
+
Z = Vector{Vector{Int}}()
|
27 |
+
i = j = 1
|
28 |
+
while i <= nterms(p) || j <= nterms(q)
|
29 |
+
z = zeros(Int, nvars)
|
30 |
+
if j > nterms(q) || (i <= nterms(p) && _getindex(p, i).x > _getindex(q, j).x)
|
31 |
+
t = _getindex(p, i)
|
32 |
+
z[maps[1]] = t.x.z
|
33 |
+
α = convert(U, t.α)
|
34 |
+
i += 1
|
35 |
+
elseif i > nterms(p) || _getindex(q, j).x > _getindex(p, i).x
|
36 |
+
t = _getindex(q, j)
|
37 |
+
z[maps[2]] = t.x.z
|
38 |
+
α = convert(U, op(t.α))
|
39 |
+
j += 1
|
40 |
+
else
|
41 |
+
t = _getindex(p, i)
|
42 |
+
z[maps[1]] = t.x.z
|
43 |
+
s = _getindex(q, j)
|
44 |
+
α = op(t.α, s.α)
|
45 |
+
i += 1
|
46 |
+
j += 1
|
47 |
+
end
|
48 |
+
push!(a, α)
|
49 |
+
push!(Z, z)
|
50 |
+
end
|
51 |
+
|
52 |
+
Polynomial(a, MonomialVector{C}(allvars, Z))
|
53 |
+
end
|
54 |
+
|
55 |
+
|
56 |
+
Base.:(+)(x::TermPoly{C}, y::TermPoly{C}) where C = plusorminus(x, y, +)
|
57 |
+
Base.:(-)(x::TermPoly{C}, y::TermPoly{C}) where C = plusorminus(x, y, -)
|
58 |
+
Base.:(+)(x::TermPoly{C}, y::Union{Monomial,PolyVar}) where C = x + Term{C}(y)
|
59 |
+
Base.:(+)(x::Union{Monomial,PolyVar}, y::TermPoly{C}) where C = Term{C}(x) + y
|
60 |
+
|
61 |
+
Base.:(-)(x::TermPoly{T}, y::DMonomialLike) where T = x - Term{T}(y)
|
62 |
+
Base.:(-)(x::DMonomialLike, y::TermPoly{T}) where T = Term{T}(x) - y
|
63 |
+
|
64 |
+
Base.:(-)(p::Polynomial) = Polynomial(-p.a, p.x)
|
65 |
+
|
66 |
+
include("mult.jl")
|
@@ -0,0 +1,230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export Polynomial
|
2 |
+
|
3 |
+
# Invariant:
|
4 |
+
# a and x might be empty: meaning it is the zero polynomial
|
5 |
+
# a does not contain any zeros
|
6 |
+
# x is increasing in the monomial order (i.e. grlex)
|
7 |
+
struct Polynomial{C, T} <: AbstractPolynomial{T}
|
8 |
+
a::Vector{T}
|
9 |
+
x::MonomialVector{C}
|
10 |
+
|
11 |
+
function Polynomial{C, T}(a::Vector{T}, x::MonomialVector{C}) where {C, T}
|
12 |
+
length(a) == length(x) || throw(ArgumentError("There should be as many coefficient than monomials"))
|
13 |
+
zeroidx = Int[]
|
14 |
+
for (i,α) in enumerate(a)
|
15 |
+
if iszero(α)
|
16 |
+
push!(zeroidx, i)
|
17 |
+
end
|
18 |
+
end
|
19 |
+
if !isempty(zeroidx)
|
20 |
+
isnz = ones(Bool, length(a))
|
21 |
+
isnz[zeroidx] .= false
|
22 |
+
nzidx = findall(isnz)
|
23 |
+
a = a[nzidx]
|
24 |
+
x = x[nzidx]
|
25 |
+
end
|
26 |
+
new{C, T}(a, x)
|
27 |
+
end
|
28 |
+
end
|
29 |
+
|
30 |
+
iscomm(::Type{Polynomial{C, T}}) where {C, T} = C
|
31 |
+
|
32 |
+
Base.broadcastable(p::Polynomial) = Ref(p)
|
33 |
+
Base.copy(p::Polynomial{C, T}) where {C, T} = Polynomial{C, T}(copy(p.a), copy(p.x))
|
34 |
+
Base.zero(::Type{Polynomial{C, T}}) where {C, T} = Polynomial(T[], MonomialVector{C}())
|
35 |
+
Base.one(::Type{Polynomial{C, T}}) where {C, T} = Polynomial([one(T)], MonomialVector{C}(PolyVar{C}[], [Int[]]))
|
36 |
+
Base.zero(p::Polynomial{C, T}) where {C, T} = Polynomial(T[], emptymonovec(_vars(p)))
|
37 |
+
Base.one(p::Polynomial{C, T}) where {C, T} = Polynomial([one(T)], MonomialVector(_vars(p), [zeros(Int, nvariables(p))]))
|
38 |
+
|
39 |
+
Polynomial{C, T}(a::AbstractVector, x::MonomialVector) where {C, T} = Polynomial{C, T}(Vector{T}(a), x)
|
40 |
+
Polynomial{C, T}(a::AbstractVector, X::DMonoVec) where {C, T} = Polynomial{C, T}(monovec(a, X)...)
|
41 |
+
Polynomial{C}(a::Vector{T}, x) where {C, T} = Polynomial{C, T}(a, x)
|
42 |
+
Polynomial(af::Union{Function, Vector}, x::DMonoVec{C}) where {C} = Polynomial{C}(af, x)
|
43 |
+
|
44 |
+
# TODO Remove with MP v0.2.8
|
45 |
+
Polynomial{C, T}(p::Polynomial{C, T}) where {C, T} = p
|
46 |
+
|
47 |
+
Base.convert(::Type{Polynomial{C, T}}, p::Polynomial{C, T}) where {C, T} = p
|
48 |
+
function Base.convert(::Type{Polynomial{C, T}},
|
49 |
+
p::Polynomial{C, S}) where {C, S, T}
|
50 |
+
return Polynomial{C}(convert(Vector{T}, p.a), p.x)
|
51 |
+
end
|
52 |
+
#function convert(::Type{Polynomial{C, T}},
|
53 |
+
# p::AbstractPolynomialLike) where {C, T}
|
54 |
+
# return convert(Polynomial{C, T}, polynomial(p, T))
|
55 |
+
#end
|
56 |
+
function Base.convert(::Type{Polynomial{C, T}}, t::Term{C}) where {C, T}
|
57 |
+
return Polynomial{C, T}(T[t.α], [t.x])
|
58 |
+
end
|
59 |
+
function Base.convert(::Type{Polynomial{C, T}}, m::DMonomialLike{C}) where {C, T}
|
60 |
+
return Polynomial(convert(Term{C, T}, m))
|
61 |
+
end
|
62 |
+
function MP.convertconstant(::Type{Polynomial{C, T}}, α) where {C, T}
|
63 |
+
return Polynomial(convert(Term{C, T}, α))
|
64 |
+
end
|
65 |
+
|
66 |
+
Polynomial{C}(p::Union{Polynomial{C}, Term{C}, Monomial{C}, PolyVar{C}}) where {C} = Polynomial(p)
|
67 |
+
Polynomial{C}(α) where {C} = Polynomial(Term{C}(α))
|
68 |
+
|
69 |
+
Polynomial(p::Polynomial) = p
|
70 |
+
Polynomial(t::Term{C, T}) where {C, T} = Polynomial{C, T}([t.α], [t.x])
|
71 |
+
Polynomial(x::Union{PolyVar{C}, Monomial{C}}) where {C} = Polynomial(Term{C}(x))
|
72 |
+
|
73 |
+
#Base.convert(::Type{TermContainer{C, T}}, p::Polynomial{C}) where {C, T} = Polynomial{C, T}(p)
|
74 |
+
|
75 |
+
function Polynomial{C, T}(f::Function, x::MonomialVector{C}) where {C, T}
|
76 |
+
a = T[f(i) for i in 1:length(x)]
|
77 |
+
Polynomial{C, T}(a, x)
|
78 |
+
end
|
79 |
+
function Polynomial{C, T}(f::Function, x::AbstractVector) where {C, T}
|
80 |
+
σ, X = sortmonovec(x)
|
81 |
+
a = T[f(i) for i in σ]
|
82 |
+
Polynomial{C, T}(a, X)
|
83 |
+
end
|
84 |
+
Polynomial{C}(f::Function, x) where {C} = Polynomial{C, Base.promote_op(f, Int)}(f, x)
|
85 |
+
|
86 |
+
#Base.convert(::Type{PolyType{C}}, p::TermContainer{C}) where {C} = p
|
87 |
+
|
88 |
+
# needed to build [p Q; Q p] where p is a polynomial and Q is a matpolynomial in Julia v0.5
|
89 |
+
#Base.convert(::Type{TermType{C}}, p::TermContainer{C}) where {C} = p
|
90 |
+
#Base.convert(::Type{TermType{C, T}}, p::TermContainer{C, T}) where {C, T} = p
|
91 |
+
|
92 |
+
Base.length(p::Polynomial) = length(p.a)
|
93 |
+
Base.isempty(p::Polynomial) = isempty(p.a)
|
94 |
+
Base.iterate(p::Polynomial) = isempty(p) ? nothing : (p[1], 1)
|
95 |
+
function Base.iterate(p::Polynomial, state::Int)
|
96 |
+
state < length(p) ? (p[state+1], state+1) : nothing
|
97 |
+
end
|
98 |
+
#eltype(::Type{Polynomial{C, T}}) where {C, T} = T
|
99 |
+
Base.getindex(p::Polynomial, I::Int) = Term(p.a[I[1]], p.x[I[1]])
|
100 |
+
|
101 |
+
#Base.transpose(p::Polynomial) = Polynomial(map(transpose, p.a), p.x) # FIXME invalid age range update
|
102 |
+
|
103 |
+
struct TermIterator{C, T} <: AbstractVector{Term{C, T}}
|
104 |
+
p::Polynomial{C, T}
|
105 |
+
end
|
106 |
+
Base.firstindex(p::TermIterator) = firstindex(p.p.a)
|
107 |
+
Base.lastindex(p::TermIterator) = lastindex(p.p.a)
|
108 |
+
Base.length(p::TermIterator) = length(p.p.a)
|
109 |
+
Base.size(p::TermIterator) = (length(p),)
|
110 |
+
Base.isempty(p::TermIterator) = isempty(p.p.a)
|
111 |
+
Base.iterate(p::TermIterator) = isempty(p) ? nothing : (p[1], 1)
|
112 |
+
function Base.iterate(p::TermIterator, state::Int)
|
113 |
+
state < length(p) ? (p[state+1], state+1) : nothing
|
114 |
+
end
|
115 |
+
|
116 |
+
Base.getindex(p::TermIterator, I::Int) = Term(p.p.a[I[1]], p.p.x[I[1]])
|
117 |
+
|
118 |
+
MP.terms(p::Polynomial) = TermIterator(p)
|
119 |
+
MP.coefficients(p::Polynomial) = p.a
|
120 |
+
MP.monomials(p::Polynomial) = p.x
|
121 |
+
_vars(p::Polynomial) = _vars(p.x)
|
122 |
+
|
123 |
+
MP.extdegree(p::Polynomial) = extdegree(p.x)
|
124 |
+
MP.mindegree(p::Polynomial) = mindegree(p.x)
|
125 |
+
MP.maxdegree(p::Polynomial) = maxdegree(p.x)
|
126 |
+
|
127 |
+
MP.leadingcoefficient(p::Polynomial{C, T}) where {C, T} = iszero(p) ? zero(T) : first(p.a)
|
128 |
+
MP.leadingmonomial(p::Polynomial) = iszero(p) ? constantmonomial(p) : first(p.x)
|
129 |
+
MP.leadingterm(p::Polynomial) = iszero(p) ? zeroterm(p) : first(terms(p))
|
130 |
+
|
131 |
+
function MP.removeleadingterm(p::Polynomial)
|
132 |
+
Polynomial(p.a[2:end], p.x[2:end])
|
133 |
+
end
|
134 |
+
function MP.removemonomials(p::Polynomial, x::MonomialVector)
|
135 |
+
# use the fact that monomials are sorted to do this O(n) instead of O(n^2)
|
136 |
+
j = 1
|
137 |
+
I = Int[]
|
138 |
+
for (i,t) in enumerate(p)
|
139 |
+
while j <= length(x) && x[j] > t.x
|
140 |
+
j += 1
|
141 |
+
end
|
142 |
+
if j > length(x) || x[j] != t.x
|
143 |
+
push!(I, i)
|
144 |
+
end
|
145 |
+
end
|
146 |
+
Polynomial(p.a[I], p.x[I])
|
147 |
+
end
|
148 |
+
MP.removemonomials(p::Polynomial, x::Vector) = removemonomials(p, MonomialVector(x))
|
149 |
+
|
150 |
+
function removedups(adup::Vector{T}, Zdup::Vector{Vector{Int}}) where {T}
|
151 |
+
σ = sortperm(Zdup, rev=true, lt=grlex)
|
152 |
+
Z = Vector{Vector{Int}}()
|
153 |
+
a = Vector{T}()
|
154 |
+
i = 0
|
155 |
+
j = 1
|
156 |
+
while j <= length(adup)
|
157 |
+
k = σ[j]
|
158 |
+
if j == 1 || Zdup[k] != Zdup[σ[j-1]]
|
159 |
+
push!(Z, Zdup[k])
|
160 |
+
push!(a, adup[k])
|
161 |
+
i += 1
|
162 |
+
else
|
163 |
+
a[i] += adup[k]
|
164 |
+
end
|
165 |
+
j += 1
|
166 |
+
end
|
167 |
+
a, Z
|
168 |
+
end
|
169 |
+
function polynomialclean(vars::Vector{PolyVar{C}}, adup::Vector{T}, Zdup::Vector{Vector{Int}}) where {C, T}
|
170 |
+
a, Z = removedups(adup, Zdup)
|
171 |
+
Polynomial{C, T}(a, MonomialVector{C}(vars, Z))
|
172 |
+
end
|
173 |
+
|
174 |
+
MP.polynomial(a::AbstractVector, x::DMonoVec, s::MP.ListState) = Polynomial(collect(a), x)
|
175 |
+
|
176 |
+
#MP.polynomial(f::Function, x::AbstractVector) = Polynomial(f, x)
|
177 |
+
#MP.polynomial(ts::AbstractVector{Term{C, T}}) where {C, T} = Polynomial(coefficient.(ts), monomial.(ts)) # FIXME invalid age range update
|
178 |
+
|
179 |
+
# i < j
|
180 |
+
function trimap(i, j, n)
|
181 |
+
div(n*(n+1), 2) - div((n-i+1)*(n-i+2), 2) + j-i+1
|
182 |
+
end
|
183 |
+
MP.polynomial(Q::AbstractMatrix{T}, mv::MonomialVector) where T = MP.polynomial(Q, mv, Base.promote_op(+, T, T))
|
184 |
+
function MP.polynomial(Q::AbstractMatrix, mv::MonomialVector{C}, ::Type{T}) where {C, T}
|
185 |
+
if isempty(Q)
|
186 |
+
zero(Polynomial{C, T})
|
187 |
+
else
|
188 |
+
n = length(mv)
|
189 |
+
if C
|
190 |
+
N = trimap(n, n, n)
|
191 |
+
Z = Vector{Vector{Int}}(undef, N)
|
192 |
+
a = Vector{T}(undef, N)
|
193 |
+
for i in 1:n
|
194 |
+
for j in i:n
|
195 |
+
k = trimap(i, j, n)
|
196 |
+
Z[k] = mv.Z[i] + mv.Z[j]
|
197 |
+
if i == j
|
198 |
+
a[k] = Q[i, j]
|
199 |
+
else
|
200 |
+
a[k] = Q[i, j] + Q[j, i]
|
201 |
+
end
|
202 |
+
end
|
203 |
+
end
|
204 |
+
v = _vars(mv)
|
205 |
+
else
|
206 |
+
N = n^2
|
207 |
+
x = Vector{Monomial{C}}(undef, N)
|
208 |
+
a = Vector{T}(undef, N)
|
209 |
+
offset = 0
|
210 |
+
for i in 1:n
|
211 |
+
# for j in 1:n wouldn't be cache friendly for Q
|
212 |
+
for j in i:n
|
213 |
+
k = trimap(i, j, n)
|
214 |
+
q = Q[i, j]
|
215 |
+
x[offset+k] = mv[i] * mv[j]
|
216 |
+
a[offset+k] = q
|
217 |
+
if i != j
|
218 |
+
offset += 1
|
219 |
+
x[offset+k] = mv[j] * mv[i]
|
220 |
+
a[offset+k] = q
|
221 |
+
end
|
222 |
+
end
|
223 |
+
end
|
224 |
+
a, X = monovec(a, x)
|
225 |
+
v = _vars(X)
|
226 |
+
Z = X.Z
|
227 |
+
end
|
228 |
+
polynomialclean(v, a, Z)
|
229 |
+
end
|
230 |
+
end
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Promotion with PolyVar and Monomial
|
2 |
+
Base.promote_rule(::Type{PolyVar{C}}, ::Type{PolyVar{C}}) where {C} = PolyVar{C}
|
3 |
+
Base.promote_rule(::Type{<:DMonomialLike{C}}, ::Type{<:DMonomialLike{C}}) where {C} = Monomial{C}
|
4 |
+
#promote_rule{S<:Union{Monomial, PolyVar}, T<:Union{Monomial, PolyVar}}(::Type{S}, ::Type{T}) = Monomial{iscomm{S}}
|
5 |
+
|
6 |
+
Base.promote_rule(::Type{Polynomial{C, S}}, ::Type{Polynomial{C, T}}) where {S, C, T} = Polynomial{C, promote_type(S, T)}
|
7 |
+
Base.promote_rule(::Type{<:AbstractPolynomialLike{S}}, ::Type{Polynomial{C, T}}) where {S, C, T} = Polynomial{C, promote_type(S, T)}
|
8 |
+
Base.promote_rule(::Type{Polynomial{C, T}}, ::Type{<:AbstractPolynomialLike{S}}) where {S, C, T} = Polynomial{C, promote_type(S, T)}
|
9 |
+
Base.promote_rule(::Type{<:DMonomialLike{S}}, ::Type{Polynomial{C, T}}) where {S, C, T} = Polynomial{C, promote_type(T, Int)}
|
10 |
+
Base.promote_rule(::Type{Polynomial{C, T}}, ::Type{<:DMonomialLike{S}}) where {S, C, T} = Polynomial{C, promote_type(T, Int)}
|
11 |
+
|
12 |
+
MP.promote_rule_constant(::Type{T}, ::Type{<:DMonomialLike{C}}) where {C, T} = Term{C, promote_type(T, Int)}
|
13 |
+
MP.promote_rule_constant(::Type{S}, ::Type{Term{C, T}}) where {S, C, T} = Term{C, promote_type(S, T)}
|
14 |
+
MP.promote_rule_constant(::Type{S}, ::Type{<:TermPoly{C, T}}) where {S, C, T} = Polynomial{C, promote_type(S, T)}
|
15 |
+
|
16 |
+
# Promotion with Term
|
17 |
+
Base.promote_rule(::Type{Term{C, S}}, ::Type{Term{C, T}}) where {C,S,T} = Term{C, promote_type(S, T)}
|
18 |
+
Base.promote_rule(::Type{<:DMonomialLike{C}}, ::Type{Term{C, T}}) where {C,T} = Term{C, promote_type(T, Int)}
|
19 |
+
Base.promote_rule(::Type{Term{C, T}}, ::Type{<:DMonomialLike{C}}) where {C,T} = Term{C, promote_type(T, Int)}
|
20 |
+
|
21 |
+
# Promotion with Polynomial
|
22 |
+
#Base.promote_rule(::Type{Polynomial{C, S}}, ::Type{Term{C, T}}) where {C, S, T} = Polynomial{C, promote_type(S, T)}
|
23 |
+
#Base.promote_rule(::Type{Term{C, T}}, ::Type{Polynomial{C, S}}) where {C, S, T} = Polynomial{C, promote_type(S, T)}
|
24 |
+
|
25 |
+
#Base.promote_rule(::Type{<:TermPoly{C, S}}, ::Type{<:TermPoly{C, T}}) where {C, S, T} = Polynomial{C, promote_type(S, T)}
|
26 |
+
#Base.promote_rule(::Type{<:TermPoly{C, T}}, ::Type{<:DMonomialLike{C}}) where {C, T} = Polynomial{C, promote_type(T, Int)}
|
27 |
+
#Base.promote_rule(::Type{<:DMonomialLike{C}}, ::Type{<:TermPoly{C, T}}) where {C, T} = Polynomial{C, promote_type(T, Int)}
|
The diff for this file is too large to render.
See raw diff
|
|
The diff for this file is too large to render.
See raw diff
|
|
The diff for this file is too large to render.
See raw diff
|
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
function fillmap!(vals, vars, s::MP.Substitution)
|
2 |
+
j = findfirst(isequal(s.first), vars)
|
3 |
+
if j !== nothing
|
4 |
+
vals[j] = s.second
|
5 |
+
end
|
6 |
+
end
|
7 |
+
function fillmap!(vals, vars, s::MP.AbstractMultiSubstitution)
|
8 |
+
for (v, x) in zip(s.first, s.second)
|
9 |
+
fillmap!(vals, vars, v => x)
|
10 |
+
end
|
11 |
+
end
|
12 |
+
|
13 |
+
function fillmap!(vals, vars, s1::MP.AbstractSubstitution, s2::MP.AbstractSubstitution...)
|
14 |
+
fillmap!(vals, vars, s1)
|
15 |
+
fillmap!(vals, vars, s2...)
|
16 |
+
end
|
17 |
+
|
18 |
+
_eltype(::T) where {T} = T
|
19 |
+
_eltype(t::Tuple) = Base.promote_typeof(t...)
|
20 |
+
_eltype(::Tuple{Vararg{T}}) where {T} = T
|
21 |
+
_eltype(::AbstractVector{T}) where {T} = T
|
22 |
+
_substype(s::MP.AbstractSubstitution) = _eltype(s.second)
|
23 |
+
_substype(s1::MP.AbstractSubstitution, s2::MP.AbstractSubstitution...) = promote_type(_substype(s1), _substype(s2...))
|
24 |
+
_substype(s::MP.Substitutions) = _substype(s...)
|
25 |
+
|
26 |
+
function _subsmap(::MP.Eval, vars, s::MP.Substitutions)
|
27 |
+
# Every variable will be replaced by some value of type T
|
28 |
+
vals = Vector{_substype(s)}(undef, length(vars))
|
29 |
+
fillmap!(vals, vars, s...)
|
30 |
+
for i in 1:length(vals)
|
31 |
+
@assert isassigned(vals, i) "Variable $(vars[i]) was not assigned a value"
|
32 |
+
end
|
33 |
+
vals
|
34 |
+
end
|
35 |
+
function _subsmap(::MP.Subs, vars::Vector{PolyVar{C}}, s::MP.Substitutions) where {C}
|
36 |
+
# Some variable may not be replaced
|
37 |
+
vals = Vector{promote_type(_substype(s), PolyVar{C})}(undef, length(vars))
|
38 |
+
copyto!(vals, vars)
|
39 |
+
fillmap!(vals, vars, s...)
|
40 |
+
vals
|
41 |
+
end
|
42 |
+
|
43 |
+
subsmap(st, vars, s::MP.Substitutions) = _subsmap(st, vars, s)
|
44 |
+
_vec(a::AbstractVector) = a
|
45 |
+
_vec(a::Tuple) = [a...]
|
46 |
+
function subsmap(st, vars, s::Tuple{MP.VectorMultiSubstitution})
|
47 |
+
if vars === s[1].first || vars == s[1].first # shortcut, === happens when the user do p(variables(p) => ...)
|
48 |
+
_vec(s[1].second)
|
49 |
+
else
|
50 |
+
_subsmap(st, vars, s)
|
51 |
+
end
|
52 |
+
end
|
53 |
+
|
54 |
+
function monoeval(z::Vector{Int}, vals::AbstractVector)
|
55 |
+
@assert length(z) == length(vals)
|
56 |
+
@assert !isempty(z)
|
57 |
+
val = vals[1]^z[1]
|
58 |
+
for i in 2:length(vals)
|
59 |
+
if z[i] > 0
|
60 |
+
val *= vals[i]^z[i]
|
61 |
+
end
|
62 |
+
end
|
63 |
+
val
|
64 |
+
end
|
65 |
+
|
66 |
+
_subs(st, ::PolyVar, vals) = monoeval([1], vals::AbstractVector)
|
67 |
+
_subs(st, m::Monomial, vals) = monoeval(m.z, vals::AbstractVector)
|
68 |
+
_subs(st, t::Term, vals) = t.α * monoeval(t.x.z, vals::AbstractVector)
|
69 |
+
function _subs(::MP.Eval, p::Polynomial{C, T}, vals::AbstractVector{S}) where {C, T, S}
|
70 |
+
# I need to check for iszero otherwise I get : ArgumentError: reducing over an empty collection is not allowed
|
71 |
+
if iszero(p)
|
72 |
+
zero(Base.promote_op(*, S, T))
|
73 |
+
else
|
74 |
+
sum(i -> p.a[i] * monoeval(p.x.Z[i], vals), 1:length(p))
|
75 |
+
end
|
76 |
+
end
|
77 |
+
function _subs(::MP.Subs, p::Polynomial{C, T}, vals::AbstractVector{S}) where {C, T, S}
|
78 |
+
Tout = Base.promote_op(*, T, MP.coefficienttype(S))
|
79 |
+
# I need to check for iszero otherwise I get : ArgumentError: reducing over an empty collection is not allowed
|
80 |
+
if iszero(p)
|
81 |
+
zero(Polynomial{C, Tout})
|
82 |
+
else
|
83 |
+
convert(Polynomial{C, Tout}, sum(i -> p.a[i] * monoeval(p.x.Z[i], vals), 1:length(p)))
|
84 |
+
end
|
85 |
+
|
86 |
+
end
|
87 |
+
|
88 |
+
function MP.substitute(st::MP.AbstractSubstitutionType, p::PolyType, s::MP.Substitutions)
|
89 |
+
_subs(st, p, subsmap(st, _vars(p), s))
|
90 |
+
end
|
91 |
+
|
92 |
+
(v::PolyVar)(s::MP.AbstractSubstitution...) = MP.substitute(MP.Eval(), v, s)
|
93 |
+
(m::Monomial)(s::MP.AbstractSubstitution...) = MP.substitute(MP.Eval(), m, s)
|
94 |
+
(t::Term)(s::MP.AbstractSubstitution...) = MP.substitute(MP.Eval(), t, s)
|
95 |
+
(p::Polynomial)(s::MP.AbstractSubstitution...) = MP.substitute(MP.Eval(), p, s)
|
96 |
+
|
97 |
+
(p::PolyVar)(x::Number) = x
|
98 |
+
(p::Monomial)(x::NTuple{N, <:Number}) where N = MP.substitute(MP.Eval(), p, variables(p)=>x)
|
99 |
+
(p::Monomial)(x::AbstractVector{<:Number}) = MP.substitute(MP.Eval(), p, variables(p)=>x)
|
100 |
+
(p::Monomial)(x::Number...) = MP.substitute(MP.Eval(), p, variables(p)=>x)
|
101 |
+
(p::Term)(x::NTuple{N, <:Number}) where N = MP.substitute(MP.Eval(), p, variables(p)=>x)
|
102 |
+
(p::Term)(x::AbstractVector{<:Number}) = MP.substitute(MP.Eval(), p, variables(p)=>x)
|
103 |
+
(p::Term)(x::Number...) = MP.substitute(MP.Eval(), p, variables(p)=>x)
|
104 |
+
(p::Polynomial)(x::NTuple{N, <:Number}) where N = MP.substitute(MP.Eval(), p, variables(p)=>x)
|
105 |
+
(p::Polynomial)(x::AbstractVector{<:Number}) = MP.substitute(MP.Eval(), p, variables(p)=>x)
|
106 |
+
(p::Polynomial)(x::Number...) = MP.substitute(MP.Eval(), p, variables(p)=>x)
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export Term
|
2 |
+
|
3 |
+
struct Term{C, T} <: AbstractTerm{T}
|
4 |
+
α::T
|
5 |
+
x::Monomial{C}
|
6 |
+
end
|
7 |
+
|
8 |
+
iscomm(::Type{Term{C, T}}) where {C, T} = C
|
9 |
+
|
10 |
+
Base.convert(::Type{Term{C, T}}, t::Term{C, T}) where {C, T} = t
|
11 |
+
function Base.convert(::Type{Term{C, T}}, t::Term{C}) where {C, T}
|
12 |
+
return Term{C, T}(T(t.α), t.x)
|
13 |
+
end
|
14 |
+
Term(t::Term) = t
|
15 |
+
|
16 |
+
function Base.convert(::Type{Term{C, T}}, x::Monomial{C}) where {C, T}
|
17 |
+
return Term{C, T}(one(T), x)
|
18 |
+
end
|
19 |
+
Term{C}(x::Monomial{C}) where C = convert(Term{C, Int}, x)
|
20 |
+
Term(x::Monomial{C}) where C = Term{C}(x)
|
21 |
+
|
22 |
+
function Base.convert(::Type{Term{C, T}}, x::PolyVar{C}) where {C, T}
|
23 |
+
return convert(Term{C, T}, convert(Monomial{C}, x))
|
24 |
+
end
|
25 |
+
Term{C}(x::PolyVar{C}) where C = Term{C}(convert(Monomial{C}, x))
|
26 |
+
Term(x::PolyVar{C}) where C = Term{C}(x)
|
27 |
+
|
28 |
+
function MP.convertconstant(::Type{Term{C, T}}, α) where {C, T}
|
29 |
+
return Term{C}(convert(T, α))
|
30 |
+
end
|
31 |
+
Term{C}(α::T) where {C, T} = Term{C, T}(α, Monomial{C}())
|
32 |
+
|
33 |
+
Base.broadcastable(t::Term) = Ref(t)
|
34 |
+
#(::Type{TermContainer{C}}){C}(x::PolyVar{C}) = Term(x)
|
35 |
+
#(::Type{TermContainer{C}}){C}(x::Monomial{C}) = Term(x)
|
36 |
+
#(::Type{TermContainer{C}}){C}(t::TermContainer{C}) = t
|
37 |
+
#TermContainer(x::PolyVar) = Term(x)
|
38 |
+
#TermContainer(x::Monomial) = Term(x)
|
39 |
+
#TermContainer(t::TermContainer) = t
|
40 |
+
|
41 |
+
#Base.convert{C, T}(::Type{TermContainer{C, T}}, x::Union{Monomial{C},PolyVar{C}}) = Term{C, T}(x)
|
42 |
+
#Base.convert{C, T}(::Type{TermContainer{C, T}}, α::T) = Term{C, T}(α, Monomial{C}())
|
43 |
+
#Base.convert{C, S, T}(::Type{TermContainer{C, T}}, α::S) = TermContainer{C, T}(T(α))
|
44 |
+
#(::Type{TermContainer{C}}){C, T}(α::T) = TermContainer{C, T}(α)
|
45 |
+
|
46 |
+
#Base.convert{C, T}(::Type{TermContainer{C, T}}, t::Term{C}) = Term{C, T}(t)
|
47 |
+
|
48 |
+
Base.copy(t::T) where {T<:Term} = T(copy(t.α), copy(t.x))
|
49 |
+
|
50 |
+
MP.coefficient(t::Term) = t.α
|
51 |
+
MP.monomial(t::Term) = t.x
|
52 |
+
_vars(t) = _vars(t.x)
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export PolyVar, @polyvar, @ncpolyvar
|
2 |
+
export polyvecvar
|
3 |
+
|
4 |
+
|
5 |
+
function polyarrayvar(::Type{PV}, prefix, indices...) where {PV}
|
6 |
+
map(i -> PV("$(prefix)[$(join(i, ","))]"), Iterators.product(indices...))
|
7 |
+
end
|
8 |
+
|
9 |
+
function buildpolyvar(::Type{PV}, var) where {PV}
|
10 |
+
if isa(var, Symbol)
|
11 |
+
var, :($(esc(var)) = $PV($"$var"))
|
12 |
+
else
|
13 |
+
isa(var, Expr) || error("Expected $var to be a variable name")
|
14 |
+
Base.Meta.isexpr(var, :ref) || error("Expected $var to be of the form varname[idxset]")
|
15 |
+
(2 ≤ length(var.args)) || error("Expected $var to have at least one index set")
|
16 |
+
varname = var.args[1]
|
17 |
+
prefix = string(varname)
|
18 |
+
varname, :($(esc(varname)) = polyarrayvar($PV, $prefix, $(esc.(var.args[2:end])...)))
|
19 |
+
end
|
20 |
+
end
|
21 |
+
|
22 |
+
function buildpolyvars(::Type{PV}, args) where {PV}
|
23 |
+
vars = Symbol[]
|
24 |
+
exprs = []
|
25 |
+
for arg in args
|
26 |
+
var, expr = buildpolyvar(PV, arg)
|
27 |
+
push!(vars, var)
|
28 |
+
push!(exprs, expr)
|
29 |
+
end
|
30 |
+
vars, exprs
|
31 |
+
end
|
32 |
+
|
33 |
+
# Variable vector x returned garanteed to be sorted so that if p is built with x then vars(p) == x
|
34 |
+
macro polyvar(args...)
|
35 |
+
vars, exprs = buildpolyvars(PolyVar{true}, args)
|
36 |
+
:($(foldl((x,y) -> :($x; $y), exprs, init=:())); $(Expr(:tuple, esc.(vars)...)))
|
37 |
+
end
|
38 |
+
|
39 |
+
macro ncpolyvar(args...)
|
40 |
+
vars, exprs = buildpolyvars(PolyVar{false}, args)
|
41 |
+
:($(foldl((x,y) -> :($x; $y), exprs, init=:())); $(Expr(:tuple, esc.(vars)...)))
|
42 |
+
end
|
43 |
+
|
44 |
+
struct PolyVar{C} <: AbstractVariable
|
45 |
+
id::Int
|
46 |
+
name::String
|
47 |
+
|
48 |
+
function PolyVar{C}(name::AbstractString) where {C}
|
49 |
+
# gensym returns something like Symbol("##42")
|
50 |
+
# we first remove "##" and then parse it into an Int
|
51 |
+
id = parse(Int, string(gensym())[3:end])
|
52 |
+
new(id, convert(String, name))
|
53 |
+
end
|
54 |
+
end
|
55 |
+
|
56 |
+
Base.hash(x::PolyVar, u::UInt) = hash(x.id, u)
|
57 |
+
Base.broadcastable(x::PolyVar) = Ref(x)
|
58 |
+
|
59 |
+
MP.name(v::PolyVar) = v.name
|
60 |
+
function MP.name_base_indices(v::PolyVar)
|
61 |
+
splits = split(v.name, r"[\[,\]]\s*", keepempty=false)
|
62 |
+
if length(splits) == 1
|
63 |
+
return v.name, Int[]
|
64 |
+
else
|
65 |
+
return splits[1], parse.(Int, splits[2:end])
|
66 |
+
end
|
67 |
+
end
|
68 |
+
|
69 |
+
MP.monomial(v::PolyVar) = Monomial(v)
|
70 |
+
_vars(v::PolyVar) = [v]
|
71 |
+
|
72 |
+
iscomm(::Type{PolyVar{C}}) where {C} = C
|
73 |
+
|
74 |
+
function mergevars(varsvec::Vector{Vector{PV}}) where {PV<:PolyVar}
|
75 |
+
n = length(varsvec)
|
76 |
+
is = ones(Int, n)
|
77 |
+
maps = zeros.(Int, length.(varsvec))
|
78 |
+
nonempty = BitSet(findall(!isempty, varsvec))
|
79 |
+
vars = Vector{PV}()
|
80 |
+
while !isempty(nonempty)
|
81 |
+
imin = 0
|
82 |
+
for i in nonempty
|
83 |
+
if imin == 0 || varsvec[i][is[i]] > varsvec[imin][is[imin]]
|
84 |
+
imin = i
|
85 |
+
end
|
86 |
+
end
|
87 |
+
var = varsvec[imin][is[imin]]
|
88 |
+
push!(vars, var)
|
89 |
+
for i in nonempty
|
90 |
+
if var == varsvec[i][is[i]]
|
91 |
+
maps[i][is[i]] = length(vars)
|
92 |
+
if is[i] == length(varsvec[i])
|
93 |
+
pop!(nonempty, i)
|
94 |
+
else
|
95 |
+
is[i] += 1
|
96 |
+
end
|
97 |
+
end
|
98 |
+
end
|
99 |
+
end
|
100 |
+
vars, maps
|
101 |
+
end
|