|
| 1 | +import msolve_jll: libneogb |
| 2 | + |
| 3 | +export normal_form |
| 4 | + |
| 5 | +@doc Markdown.doc""" |
| 6 | + normal_form( |
| 7 | + f::T, |
| 8 | + I::Ideal{T}; |
| 9 | + nr_thrds::Int=1, |
| 10 | + info_level::Int=0 |
| 11 | + ) where T <: MPolyRingElem |
| 12 | +
|
| 13 | +Compute the normal forms of the elements of `F` w.r.t. a degree reverse |
| 14 | +lexicographical Gröbner basis of `I`. |
| 15 | +
|
| 16 | +**Note:** If `I` has not already cached a degree reverse lexicographical |
| 17 | +Gröbner basis, then this one is first computed. |
| 18 | +
|
| 19 | +# Arguments |
| 20 | +- `F::Vector{T} where T <: MPolyRingElem`: elements to be reduced. |
| 21 | +- `I::Ideal{T} where T <: MPolyRingElem`: ideal data to reduce with. |
| 22 | +- `nr_thrds::Int=1`: number of threads for parallel linear algebra. |
| 23 | +- `info_level::Int=0`: info level printout: off (`0`, default), summary (`1`), detailed (`2`). |
| 24 | +
|
| 25 | +# Examples |
| 26 | +```jldoctest |
| 27 | +julia> using AlgebraicSolving |
| 28 | +
|
| 29 | +julia> R, (x,y) = polynomial_ring(GF(101),["x","y"]) |
| 30 | +(Multivariate polynomial ring in 2 variables over GF(101), fpMPolyRingElem[x, y]) |
| 31 | +
|
| 32 | +julia> I = Ideal([y*x^3+12-y, x+y]) |
| 33 | +fpMPolyRingElem[x^3*y + 100*y + 12, x + y] |
| 34 | +
|
| 35 | +julia> f = 2*x^2+7*x*y |
| 36 | +2*x^2 + 7*x*y |
| 37 | +
|
| 38 | +julia> normal_form(f, I) |
| 39 | +96*y^2 |
| 40 | +``` |
| 41 | +""" |
| 42 | +function normal_form( |
| 43 | + f::T, |
| 44 | + I::Ideal{T}; |
| 45 | + nr_thrds::Int=1, |
| 46 | + info_level::Int=0 |
| 47 | + ) where T <: MPolyRingElem |
| 48 | + nf = _core_normal_form([f], I; nr_thrds, info_level) |
| 49 | + return nf[1] |
| 50 | +end |
| 51 | + |
| 52 | +@doc Markdown.doc""" |
| 53 | + normal_form( |
| 54 | + F::Vector{T}, |
| 55 | + I::Ideal{T}; |
| 56 | + nr_thrds::Int=1, |
| 57 | + info_level::Int=0 |
| 58 | + ) where T <: MPolyRingElem |
| 59 | +
|
| 60 | +Compute the normal forms of the elements of `F` w.r.t. a degree reverse |
| 61 | +lexicographical Gröbner basis of `I`. |
| 62 | +
|
| 63 | +**Note:** If `I` has not already cached a degree reverse lexicographical |
| 64 | +Gröbner basis, then this one is first computed. |
| 65 | +
|
| 66 | +# Arguments |
| 67 | +- `F::Vector{T} where T <: MPolyRingElem`: elements to be reduced. |
| 68 | +- `I::Ideal{T} where T <: MPolyRingElem`: ideal data to reduce with. |
| 69 | +- `nr_thrds::Int=1`: number of threads for parallel linear algebra. |
| 70 | +- `info_level::Int=0`: info level printout: off (`0`, default), summary (`1`), detailed (`2`). |
| 71 | +
|
| 72 | +# Examples |
| 73 | +```jldoctest |
| 74 | +julia> using AlgebraicSolving |
| 75 | +
|
| 76 | +julia> R, (x,y) = polynomial_ring(GF(101),["x","y"]) |
| 77 | +(Multivariate polynomial ring in 2 variables over GF(101), fpMPolyRingElem[x, y]) |
| 78 | +
|
| 79 | +julia> I = Ideal([y*x^3+12-y, x+y]) |
| 80 | +fpMPolyRingElem[x^3*y + 100*y + 12, x + y] |
| 81 | +
|
| 82 | +julia> F = [2*x^2+7*x*y, x+y] |
| 83 | +2-element Vector{fpMPolyRingElem}: |
| 84 | + 2*x^2 + 7*x*y |
| 85 | + x + y |
| 86 | +
|
| 87 | +julia> normal_form(F,I) |
| 88 | +2-element Vector{fpMPolyRingElem}: |
| 89 | + 96*y^2 |
| 90 | + 0 |
| 91 | +``` |
| 92 | +""" |
| 93 | +function normal_form( |
| 94 | + F::Vector{T}, |
| 95 | + I::Ideal{T}; |
| 96 | + nr_thrds::Int=1, |
| 97 | + info_level::Int=0 |
| 98 | + ) where T <: MPolyRingElem |
| 99 | + return _core_normal_form(F, I; nr_thrds, info_level) |
| 100 | +end |
| 101 | + |
| 102 | +function _core_normal_form( |
| 103 | + F::Vector{T}, |
| 104 | + I::Ideal{T}; |
| 105 | + nr_thrds::Int=1, |
| 106 | + info_level::Int=0 |
| 107 | + ) where T <: MPolyRingElem |
| 108 | + |
| 109 | + |
| 110 | + if (length(F) == 0 || length(I.gens) == 0) |
| 111 | + error("Input data not valid.") |
| 112 | + end |
| 113 | + |
| 114 | + R = first(F).parent |
| 115 | + nr_vars = nvars(R) |
| 116 | + field_char = Int(characteristic(R)) |
| 117 | + |
| 118 | + if !(is_probable_prime(field_char)) |
| 119 | + error("At the moment we only supports finite fields.") |
| 120 | + end |
| 121 | + |
| 122 | + #= first get a degree reverse lexicographical Gröbner basis for I =# |
| 123 | + G = groebner_basis(I, eliminate = 0, la_option = 44, info_level = info_level) |
| 124 | + |
| 125 | + tbr_nr_gens = length(F) |
| 126 | + bs_nr_gens = length(G) |
| 127 | + is_gb = 1 |
| 128 | + |
| 129 | + # convert ideal to flattened arrays of ints |
| 130 | + tbr_lens, tbr_cfs, tbr_exps = _convert_to_msolve(F) |
| 131 | + bs_lens, bs_cfs, bs_exps = _convert_to_msolve(G) |
| 132 | + |
| 133 | + nf_ld = Ref(Cint(0)) |
| 134 | + nf_len = Ref(Ptr{Cint}(0)) |
| 135 | + nf_exp = Ref(Ptr{Cint}(0)) |
| 136 | + nf_cf = Ref(Ptr{Cvoid}(0)) |
| 137 | + |
| 138 | + nr_terms = ccall((:export_nf, libneogb), Int, |
| 139 | + (Ptr{Nothing}, Ptr{Cint}, Ptr{Ptr{Cint}}, Ptr{Ptr{Cint}}, Ptr{Ptr{Cvoid}}, |
| 140 | + Cint, Ptr{Cint}, Ptr{Cint}, Ptr{Cvoid}, Cint, Ptr{Cint}, Ptr{Cint}, Ptr{Cvoid}, |
| 141 | + Cint, Cint, Cint, Cint, Cint, Cint, Cint), |
| 142 | + cglobal(:jl_malloc), nf_ld, nf_len, nf_exp, nf_cf, tbr_nr_gens, tbr_lens, tbr_exps, |
| 143 | + tbr_cfs, bs_nr_gens, bs_lens, bs_exps, bs_cfs, field_char, 0, 0, nr_vars, is_gb, |
| 144 | + nr_thrds, info_level) |
| 145 | + |
| 146 | + # convert to julia array, also give memory management to julia |
| 147 | + jl_ld = nf_ld[] |
| 148 | + jl_len = Base.unsafe_wrap(Array, nf_len[], jl_ld) |
| 149 | + jl_exp = Base.unsafe_wrap(Array, nf_exp[], nr_terms*nr_vars) |
| 150 | + ptr = reinterpret(Ptr{Int32}, nf_cf[]) |
| 151 | + jl_cf = Base.unsafe_wrap(Array, ptr, nr_terms) |
| 152 | + |
| 153 | + basis = _convert_finite_field_array_to_abstract_algebra( |
| 154 | + jl_ld, jl_len, jl_cf, jl_exp, R, 0) |
| 155 | + |
| 156 | + ccall((:free_f4_julia_result_data, libneogb), Nothing , |
| 157 | + (Ptr{Nothing}, Ptr{Ptr{Cint}}, Ptr{Ptr{Cint}}, |
| 158 | + Ptr{Ptr{Cvoid}}, Int, Int), |
| 159 | + cglobal(:jl_free), nf_len, nf_exp, nf_cf, jl_ld, field_char) |
| 160 | + |
| 161 | + return basis |
| 162 | +end |
| 163 | + |
0 commit comments