#14711: Memleak when creating QuadraticField
-------------------------------------+-------------------------------------
       Reporter:  jpflori            |        Owner:  davidloeffler
           Type:  defect             |       Status:  needs_review
       Priority:  critical           |    Milestone:  sage-5.13
      Component:  number fields      |   Resolution:
       Keywords:  memleak, number    |    Merged in:
  field, QuadraticField              |    Reviewers:
        Authors:  Simon King         |  Work issues:  Fix elliptic curves
Report Upstream:  N/A                |  code
         Branch:                     |       Commit:
  u/SimonKing/ticket/14711           |     Stopgaps:
   Dependencies:                     |
-------------------------------------+-------------------------------------

Comment (by nbruin):

 Replying to [comment:84 SimonKing]:

 > One does! Namely, suppose that you first do `P.register_coercion(mor)`,
 then you allow `S` to become garbage collected, and then you create a new
 parent `Q` with an
 embedding into what looks like `S` (of course, it now is a replica of the
 original now garbage collected `S`).
 > You would want that `Q` coerces into `P` via `S`, by transitivity of
 coercions. But you collected `mor.domain()` and thus you will fail to find
 this coercion.

 I agree that there is a place for such strong connections, but I have
 severe reservations about declaring it's the only way or even the default
 way to inform the system
 about coercions.

 The following would leak memory with the model you propose:
 {{{
 M1=ZZ^1
 M2=ZZ^2
 for d in [2..100000]:
     N=ZZ^d
     m1=Hom(N,M1)([M.0 for i in range(d)])
     m2=Hom(N,M2)([M.(i % 2) for i in range(d)])
     M1.register_coercion(m1)
     M2.register_coercion(m2)
 }}}
 I have severe reservations about declaring that this code "will never be
 memory efficient" in sage. One way out is to use the (for this purpose)
 extremely inappropriately named
 {{{
     N.register_embedding(m1)
 }}}
 instead, which in your model would mean M1 lives at least as long as N
 instead. In addition, we would not be able to do this for both `M1` and
 `M2`.

 I think there's room for a `register_embedding` with those semantics
 (although it should probably have a different name, because it doesn't
 have to be an embedding)
 as well as for `register_coercion_from_while_keeping_domain_alive` with a
 catchier name, but the life-enhancing side effects are fundamentally
 separate from the fact
 that there's a coercion in the first place, and I think it should be
 possible to register a non-life-enhancing coercion as well (the main
 reason is that
 it's easily done and that I haven't seen a proof it's not necessary. We
 don't want to unnecessarily hamstring the system).

 '''philosophical ramblings'''

 The following observations are the result of trying to come up with a
 conceptual ideal/model that we could use to argue what our coercion
 framework SHOULD do. Up to
 now it seems to me people have mainly been making ad-hoc, gut feeling
 decisions about how to put together coercion. I haven't found a better
 solution here, but I
 think there are some examples may illustrate we might just have to be
 pragmatic about this.

 Your suggestion makes sense if you want to model a "permanent, unchanging
 universe" in which all possible parents, with consistent coercions,
 already exist; we're
 simply "discovering" this universe in a piecemeal fashion. It's a common
 model in modern algebra, but I think our computer algebra model is too far
 away from this
 ideal to follow this model too far. Consider:
 {{{
 Qx.<x>=QQ[]
 K.<a>=NumberField(x^4-2)
 L.<b>=NumberField(x^2-2,embedding=a^2)
 }}}
 This fits perfectly in the "unchanging universe" model. Also note that the
 coercion system does not need to let L keep K alive, since the
 construction parameters,
 which get kept alive for the life of L by `CachedRepresentation` or
 something analogous, refer to K already.

 Now consider
 {{{
 M.<b>=NumberField(x^2-2)
 }}}
 In the "unchanging universe" (and in sage as well) we have that M is
 distinct from L. However, I think it's unrealistic to expect that all
 "embeddings" etc. can be
 specified at construction time. So I think, even though it's not possible
 currently in sage, that one should allow for
 {{{
 m1=Hom(M,K)([a^2])
 m2=Hom(M,K)([-a^2])
 M.register_embedding(m1)
 }}}
 Note that the choice of `m1` or `m2` here leads to different relations
 between `M` and `K` and hence different universes.
 In other words, our concept of "globally unique" is not powerful enough to
 capture the
 full identity of objects, which would include the coercion relations with
 objects that haven't been "discovered" yet. In practice, we can usually
 work around that by
 for instance changing the names of generators and hence create
 artificially differently labelled objects but that's already not a
 possibility for creating
 different copies of `ZZ^n`, since there are no generator names to choose
 there.

 I think one has to accept the reality here: what we have is a collection
 of objects whose relations do change in time.



 '''Some particular responses''' (most of them direct corollaries from what
 is observed above).

 > Another attempt to explain why I think the explicitly registered maps
 need to be kept:
 >
 > Think of the coercions as a digraph.
 > - The vertices correspond to parents.
 > - The arrows (oriented edges) of the digraph correspond to those maps
 that are declared as coercions by `.register_coercion(...)`.
 > - In addition to the arrows created with `register_coercion`, the
 coercion system may find short-cuts by calling `._coerce_map_from_(...)`.
 For efficiency reasons,
 > these short-cuts are stored in a cache.
 > - The coercion system then tries to find directed paths between two
 given vertices, including short-cuts. For efficiency reasons, it stores
 the resulting composed
 > maps in a cache.

 That's not the only thing coercion does. It may also find "common covering
 structures", which may lead to construction of new parents. Those
 definitely don't deserve
 to get nailed into memory. Yet, the code that creates these parents will
 look (to the coercion system) as a "user", so it would be using these
 strong-referencing
 coercion registration routines.

 > So, the coercion system will not care for the health of P, but it must
 care for the connectivity of the coercion graph. And in the current
 algorithm sketched above,
 > it is of vital importance to keep arrows leading to P alive, since
 otherwise we have to live with shortcuts only.

 I think it may well be a feature, not a bug, that one at some point can
 just be left with the shortcuts and that the intermediates have fallen
 out. The natural way of
 staying close to "discovering a permanent universe" is by never throwing
 away anything that has been discovered, and I think we agree that's a
 "memory leak". So
 it's really a matter of only keeping things around that we still need. If
 we're too lax with considering what is "needed", we'll end up keeping too
 many things in
 memory.

 > Then we look into the code and see that multiple embeddings are
 explicitly excluded. A parent has precisely one embedding that is taken
 into account by the coercion
 search ''in forward direction''. You may of course register further
 embeddings as coercions, by `emb.codomain().register_coercion(emb)`, but
 they would only be used
 for search in backward direction.

 Not only that: you'd be tying different lifetime implications to that
 construction too.

 > And there surely is a means available to add a coercion that doesn't tie
 the lifespan of two parents too closely: Implement
 `P._coerce_map_from_(Q)`, which can
 > return a map or simply "True" (in the latter case, conversion is used to
 coerce Q into P). The result is cached in `P._coerce_from_hash`, but not
 in
 > `P._coerce_from_list`.

 You mean: implement `P._install_coerce_map_from_(m)`, which does:
 `_coerce_from_hash[Domain(m)]=m`. I think it is quite important to be able
 to manipulate the
 coercion graph without having to modify library code.

--
Ticket URL: <http://trac.sagemath.org/ticket/14711#comment:96>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sage-trac.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to