Hi Burcin,

> The error I get when I try to load the .sobj file linked above in
> Sage-3.3 is:
>
> ...
> /home/burcin/sage/sage-3.3/local/lib/python2.5/site-packages/sage/structure/sage_object.so
> in sage.structure.sage_object.loads
> (sage/structure/sage_object.c:6156)()
>
> RuntimeError: (None, <function PolynomialRing at 0x1355e60>, (Fraction
> Field of Univariate Polynomial Ring in t over Finite Field of size 13,
> 'T', None, False)) invalid data stream
> invalid load key, 'x'.
> Unable to load pickled data.
>

Yep, this is the same error we had with the other pickles. This is a
wildly uninformative error message, which I think I know enough to fix
at this point (someone should file a ticket and assign it to me). All
this error really means is that cPickle ran into an error trying to
unpickle the object.

In more detail: Both Pickle and cPickle keep a stream of arguments as
they load an object, which is what gets stored in a pickle. They just
run in a loop, that basically says: if there's anything left in the
stream, pop off an argument, which is a key telling it what kind of
object is next, dispatch to a method that knows how to recreate that
object, pop the appropriate number of arguments off the stream, use
those to reconstruct the object, and then loop. I'm pretty sure what's
happening here is that a correct load key gets popped off the stream,
and the attempt to reconstruct that part of the object fails, at which
point the *key* is gone from the stream, but not all of the arguments,
and the exception we raise gets caught, so the attempt to unpickle
continues. However, now the stream has nonsense (specifically leftover
arguments) at the front of it, so on the next loop, we see the
"Invalid load key: 'x'" error. So all this error means is that
something went wrong unpickling.

Here's what's happening with Alex's 3.1.1 pickle. Actually, in the
process of explaining what happens in this case, I've realized it's
slightly more subtle than I thought (and in particular, some of these
details should be added to the trac ticket).

 - The FractionField object Alex pickled in 3.1.1 was a pre-coercion
FractionField. So it doesn't have _element_class and
_element_constructor attributes, and it was created when FractionField
had no __reduce__ method -- so it just calls __new__ on the class, and
tries to start filling in the dict for the object. This goes fine,
actually -- the FractionField unpickles okay. Keep in mind, though,
that it's now an instance of the *new* FractionField class (i.e. one
with the new coercion stuff in place) that happens to be missing some
key attributes (like _element_class and _element_constructor -- which
are set to None).

 - The next thing Alex's code tries to unpickle is a polynomial ring
over the FractionField. This has always had a __reduce__ method, which
stores a call to the PolynomialRing function in
sage.rings.polynomial.polynomial_ring_constructor.

 - The polynomial ring constructor always creates a polynomial in the
process of initializing, namely its generator. This is accomplished by
calling self([0,1], is_gen=True), which ultimately calls [ R(z) for z
in [0,1] ], where R is self.base_ring().

 - Since self.base_ring() is the fraction field, we try to dispatch
__call__ on that. Of course, the new FractionField class doesn't have
a __call__ method -- that's in Parent now. So it goes up the class
hierarchy and dispatches that __call__.

 - The first thing that method does is say "if
self._element_constructor is None: raise NotImplementedError." This is
the error we hit, because our 3.1.1 FractionField object has this set
to None. Boom.

This could explain why you didn't hit this in testing the new code --
did you create some polynomial rings over fraction fields with the old
class, then try to unpickle them with the new one? I bet this would
fail.

> I don't have so much time to investigate this either, but if you
> already found the cause then I could probably write a clean patch. Can
> you explain how you managed to load the old files, or send your hackish
> patch to me?
>

So that's a pretty longwinded explanation for what's happening. Now,
the fix was easy: I commented out the two lines in Parent.__call__
which raise the NotImplementedError, and I copy-pasted the code for
FractionField.__call__ back in place. This is clearly a hack. :) In
fact, it's bad -- the new objects I create don't pickle correctly, or
even if they did, we'd have the same problem trying to load them.
However, they loaded their coefficients just fine -- so I'm going to
write something that will instantiate correctly formed classes, coerce
the old values over via lists, and then finally save the new,
correctly structured objects. A mild pain, but it seems
straightforward enough, and I didn't think of anything easier.

Hopefully that makes sense -- but it's 2:30AM here, so feel free to
write back and say "that didn't make any sense ... try again." :)

-cc

--~--~---------~--~----~------------~-------~--~----~
To post to this group, send email to sage-support@googlegroups.com
To unsubscribe from this group, send email to 
sage-support-unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sage-support
URLs: http://www.sagemath.org
-~----------~----~----~----~------~----~------~--~---

Reply via email to