Nemocas / Nemo.jl

Julia bindings for the FLINT number theory C library
http://nemocas.github.io/Nemo.jl/
Other
191 stars 58 forks source link

Introduce set_coefficient! which is user safe #811

Open zhaoli-IHEP opened 4 years ago

zhaoli-IHEP commented 4 years ago

We were testing some native functions. And we just found a confusing behavior. As shown in the following code, after setting the coefficient zero as "setcoeff!( x, 0, zero(CC) )", but the valuation of x is still 0. Then we have to use "x += zero(x)" to change valuation to 1. However, outside of the function trim_zero!, the valuation changed back to 0 again. How is this happening? And what is the more proper approach to this?

using Nemo

const prec = 512::Int64
RR = RealField(prec)
CC = ComplexField(prec)

const ep_len = 5::Int64
LSF, ep = LaurentSeriesField(CC, ep_len, "ep")
const lsfe = Generic.LaurentSeriesFieldElem{acb}

function test()

  function is_zero( x::acb, bound::arb )::Bool
    return real(x) < bound && imag(x) < bound
  end # function is_zero

  function trim_zero!( x::lsfe, bound::arb )
    val = valuation( x )
    cff = coeff( x, val )
    if is_zero( cff, bound )
      setcoeff!( x, 0, zero(CC) )
      x += zero(x) # this is used to change the valuation to 1 inside function
    end # if
    println( "inside valuation(x) = ", valuation(x) )

    nothing
  end # function trim_zero!

  expr = 1e-50 + ep::lsfe + ep::lsfe^2
  println( "expr = ", expr )
  println( "valuation(expr) = ", valuation(expr) )

  trim_zero!(expr,RR(1e-30))

  println( "expr = ", expr )
  println( "valuation(expr) = ", valuation(expr) ) # however, valuation is changed back to 0 outside

end # function test

test()
thofma commented 4 years ago

x += zero(x) lowers to x = x + zero(x), which creates a new element and then assigns x to this newly created element. You are never changing the object x refers to at the beginning of trim_zero!.

zhaoli-IHEP commented 4 years ago

x += zero(x) lowers to x = x + zero(x), which creates a new element and then assigns x to this newly created element. You are never changing the object x refers to at the beginning of trim_zero!.

Does it mean that we have to use for example "set_val!( x, valuation(x)+1 )"?

thofma commented 4 years ago

First, what you experienced is not special to Nemo types. It happens for all julia types:

julia> function g(x, n)
         x += n
         return x
       end 

julia> x = [1, 2]
2-element Array{Int64,1}:
 1
 2

julia> y = [3, 4]
2-element Array{Int64,1}:
 3
 4

julia> g(x, y)
2-element Array{Int64,1}:
 4
 6

julia> x
2-element Array{Int64,1}:
 1
 2

So one solution would be to replace x += zero(x) by addeq!(x, zero(x)), which changes x itself by adding zero(x). But I think this is not the proper solution. I am not too familiar with the Series code, but after skimming over the code base, I think that set_coeff! does not adjust the valuation. So you end up with an element with weird internal state that could blow up anytime. I think one has to adjust the valuation by hand as you did. Maybe @wbhart has an idea on how to do this properly.

wbhart commented 4 years ago

Yes, if you mess around with the internal state of a series, you also have to set the length, precision and valuation as necessary.

set_coeff! is certainly one of those functions which looks like a user function but is mainly intended to be used internally. I've toyed with the idea of making a set_coefficient! function which is perfectly safe for the user, but I'm not sure it would be used appropriately, so I've so far not added such a function.

zhaoli-IHEP commented 4 years ago

Yes, if you mess around with the internal state of a series, you also have to set the length, precision and valuation as necessary.

set_coeff! is certainly one of those functions which looks like a user function but is mainly intended to be used internally. I've toyed with the idea of making a set_coefficient! function which is perfectly safe for the user, but I'm not sure it would be used appropriately, so I've so far not added such a function.

Thank you for the explanation. But I think it would be better to have official safe function to allow user to operate the coefficients.

wbhart commented 3 years ago

I've implemented a user facing set_coefficient! for univariate polynomials. We need similar for AbsSeries, RelSeries, LaurentSeries, PuiseuxSeries, etc.