#14711: Memleak when creating QuadraticField
-------------------------------------------------+-------------------------
Reporter: jpflori | Owner:
Type: defect | davidloeffler
Priority: critical | Status: new
Component: number fields | Milestone: sage-5.13
Keywords: memleak, number field, | Resolution:
QuadraticField | Merged in:
Authors: | Reviewers:
Report Upstream: N/A | Work issues:
Branch: u/SimonKing/ticket/14711 | Commit:
Dependencies: | Stopgaps:
-------------------------------------------------+-------------------------
Comment (by SimonKing):
With my current not yet published code, I get errors only in one file,
namely with scheme morphisms. And this actually isn't a surprise, since
scheme morphisms almost completely ignore the existing methods they
inherit from `sage.categories.map.Map`. They have a custom `__init__`
doing more or less the same what the ''old'' version of `Map.__init__`
used to do, and they even override `domain()` and `codomain()`.
So, this should be fixable, and I suppose I will be able to post a commit
so that all tests pass, later today.
Replying to [comment:83 nbruin]:
> Replying to [comment:82 SimonKing]:
> > - Maps registered by `P.register_coercion(mor)` are the backbone of
the discover_coercion algorithm. Hence, they need to be kept healthy as
long as `P` lives.
>
> It's not clear to me this is the case. If `mor` is a map from S to P
then `P.register_coercion(mor)` ensures the coercion system knows how to
map an element from S into P. Why is it important to maintain this
information for the lifetime of P? If S ceases to exist, then one would
not need to map elements from S to P.
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.
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.
How does the coercion system find "directed paths with short-cuts" from Q
to P?
- Of course, it would be impossible to just guess a parent S such that Q
has a short-cut into S and S has a short-cut into P.
- One could search through all paths alpha (paths without shortcuts, I
mean) starting at Q and simultaneously through all paths beta ending at P,
and then test whether there is a short-cut from the endpoint of alpha to
the startpoint of beta. It would work, but I guess it would be very time
consuming.
- The current coercion system will therefore just search (by backtracking)
through all shortcut-free paths beta ending at P, end then test whether
there is a short-cut from Q to the startpoint of beta. In addition, the
coerce embedding registered for Q will be considered in forward direction.
__Remark__
Perhaps in the long run, we could actually use a proper digraph (with a
lightning fast backend) to keep track of coercions.
Now for garbage collection:
> Why do we need to ensure S keeps existing? Shouldn't P have a reference
to S independent of the coercion system if P's health depends on the
existence of S? I think the coercion system is there to keep track of
relations between existing objects, not to keep objects in existence
(although this might be a side-effect of keeping track of relations
between other objects).
I think that in many cases it would indeed be the case that P should
reference S independent of coercions (say, if S is the base ring of P).
However, it is conceivable (and I think I've met such cases in failing
doctests) that P can remain perfectly healthy without S, but still we
would like to find coercions from Q to P via S.
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.
> > - If P has a coerce embedding then this embedding needs to be kept
healthy as long as P lives.
>
> I presume this is the function of the `_embedding` coercion attribute?
So it looks like we already have that. What if we want multiple
embeddings?
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.
> > - `P.register_coercion(mor)` keeps a strong reference to
`mor.domain()` in a new attribute `P._registered_domains` (which is a
list). All other maps in the coercion system will be weakened.
>
> So what means are there available to add a coercion without tying the
lifespan of one to the other?
Note that after `P.register_coercion(mor)`, `mor.domain()` will live at
least as long as P. But `mor.domain()` would not be enough to keep P
alive.
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`.
> Shouldn't it be possible to specify such things too?
Perhaps in the long run? I wouldn't like to do those things (such as:
Rewrite the coercion system to use a proper digraph backend) here.
--
Ticket URL: <http://trac.sagemath.org/ticket/14711#comment:84>
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.