On Monday, August 22, 2016 at 12:42:26 AM UTC-7, Salvatore Stella wrote: > > At the moment the init function of :class:`ClusterAlgebra` calls > :meth:`reset_exploring_iterator` that creates an instance of :meth:`seeds` > and > stores it in an internal var ``_sd_iter``.
Are you really getting benefit from storing the state (i.e., the actual iterator) on the parent itself? (I see you haven't made ClusterAlgebra UniqueRepresentation, so it's not an immediate bug to have it this way) Perhaps it's cleaner to hand out iterator objects that are kept track of in the relevant loop. That iterator would then just die whenever the frames of a KeyboardInterrupt exception are discarded and the flawed state wouldn't persist. The iterator objects could even hold a reference to the ClusterAlgebra (they may well have to) and write back interesting finds that may benefit future computations back onto the ClusterAlgebra. If you really need to store the iterator object on the ClusterAlgebra and you're finding it needs to be resilient in the face of KeyboardInterrupts (that is to say, be able to produce a "next" element after keyboard interruption), you could write your own iterator object and store that. An iterator object is an object that implements "__iter__" returning self and "next" returning the "next" element. See https://docs.python.org/2/library/stdtypes.html#iterator-types . Using "yield" is a convenient way of writing simple iterators, but it is in no way the only way of doing it. When you explicitly store state yourself it is much easier to define the right behaviour in the face of unexpected interrupts. > The methods that need to explore > the tree just call ``next`` on this iterator till they get the data they > are > looking for. This process is potentially never ending. For this reason the > user may specify a maximum depth at which to stop. > > Since this iterator is computationally intense, it easy to imagine that > users will tend to start searching but change their mind in mid > computation > and send an interrupt. This, unfortunately, leaves ``_sd_iter`` in a > corrupted state and all future calls to it will result in a StopIteration. > > At the moment we have a warning in the docstring of each method accessing > _sd_iter to explain that after sending a KeyboardInterrupt the user needs > to > call :meth:`reset_exploring_iterator`. Do you think we should instead > catch > the interrupt, reset the iterator and then raise it again like this? > > > @@ -1999,12 +1999,17 @@ class ClusterAlgebra(Parent): > sage: len(A.g_vectors_so_far()) > 14 > """ > - while self._explored_depth <= depth: > - try: > - seed = next(self._sd_iter) > - self._explored_depth = seed.depth() > - except StopIteration: > - break > + try: > + while self._explored_depth <= depth: > + try: > + seed = next(self._sd_iter) > + self._explored_depth = seed.depth() > + except StopIteration: > + break > + except KeyboardInterrupt: > + print("Got a KeyboardInterrupt, cleaning up before > returning.") > + self.reset_exploring_iterator() > + raise KeyboardInterrupt > > The advantage of this is that the user does not have to remember an extra > (unnatural?) step. The drawback is that he/she looses any customization > that > may have been made by a previous call to :meth:`reset_exploring_iterator`. > > > On a related topic. In the situation just described, the next exploration > will have to begin from the root of the tree resulting in a lot of wasted > effort. Is there any way around this? Sending a node of the tree back to > the > iterator does not seem useful because of the breath-first search. > > Thanks > S. > > > -- You received this message because you are subscribed to the Google Groups "sage-devel" group. To unsubscribe from this group and stop receiving emails from it, send an email to sage-devel+unsubscr...@googlegroups.com. To post to this group, send email to sage-devel@googlegroups.com. Visit this group at https://groups.google.com/group/sage-devel. For more options, visit https://groups.google.com/d/optout.