Ticket #10296: trac10296_singular_overhead_combined.patch

File trac10296_singular_overhead_combined.patch, 26.5 KB (added by SimonKing, 7 years ago)

Modify garbage collection in Singular interface, which reduces the overhead. Synchronization of Gap interface. Cope with non-linux pexpect errors

  • sage/interfaces/axiom.py

    # HG changeset patch
    # User Simon King <simon.king@uni-jena.de>
    # Date 1290512557 -3600
    # Node ID f678f9096434bfd114e6efeeeb3bd5b113aad5de
    # Parent  e32785fc35f30cc8d2e3f73504eade76f85b7414
    #10296: Reduce overhead in Singular interface by better garbage collection. Synchronisation of GAP.
    The patch also coped with non-linux error types raised at crashed pexpect interfaces.
    
    diff --git a/sage/interfaces/axiom.py b/sage/interfaces/axiom.py
    a b  
    411411        return s
    412412
    413413    def _eval_line(self, line, reformat=True, allow_use_file=False,
    414                    wait_for_prompt=True):
     414                   wait_for_prompt=True, restart_if_needed=False):
    415415        """
    416416        EXAMPLES::
    417417       
  • sage/interfaces/expect.py

    diff --git a/sage/interfaces/expect.py b/sage/interfaces/expect.py
    a b  
    1919  which is important for forking.
    2020
    2121- Jean-Pierre Flori (2010,2011): Split non Pexpect stuff into a parent class.
     22
     23- Simon King (2010-11-23): Ensure that the interface is started again
     24  after a crash, when a command is executed in _eval_line. Allow
     25  synchronisation of the GAP interface.
     26
    2227"""
    2328
    2429#*****************************************************************************
     
    315320        pass
    316321
    317322    def pid(self):
     323        """
     324        Return the PID of the underlying sub-process.
     325
     326        REMARK:
     327
     328        If the interface terminates unexpectedly, the original
     329        PID will still be used. But if it was terminated using
     330        :meth:`quit`, a new sub-process with a new PID is
     331        automatically started.
     332
     333        EXAMPLE::
     334
     335            sage: pid = gap.pid()
     336            sage: gap.eval('quit;')
     337            ''
     338            sage: pid == gap.pid()
     339            True
     340            sage: gap.quit()
     341            sage: pid == gap.pid()
     342            False
     343
     344        """
    318345        if self._expect is None:
    319346            self._start()
    320347        return self._expect.pid
     
    642669    def _read_in_file_command(self, filename):
    643670        raise NotImplementedError
    644671
    645     def _eval_line_using_file(self, line):
     672    def _eval_line_using_file(self, line, restart_if_needed=True):
     673        """
     674        Evaluate a line of commands, using a temporary file.
     675
     676        REMARK:
     677
     678        By default, this is called when a long command is
     679        evaluated in :meth:`eval`.
     680
     681        If the command can not be evaluated since the interface
     682        has crashed, it is automatically restarted and tried
     683        again *once*.
     684
     685        INPUT:
     686
     687        - ``line`` -- (string) a command.
     688        - ``restart_if_needed`` - (optional bool, default ``True``) --
     689          If it is ``True``, the command evaluation is evaluated
     690          a second time after restarting the interface, if an
     691          ``EOFError`` occured.
     692
     693        TESTS::
     694
     695            sage: singular._eval_line_using_file('def a=3;')
     696            '< "...";'
     697            sage: singular('a')
     698            3
     699            sage: singular.eval('quit;')
     700            ''
     701            sage: singular._eval_line_using_file('def a=3;')
     702            Singular crashed -- automatically restarting.
     703            '< "...";'
     704            sage: singular('a')
     705            3
     706            sage: singular.eval('quit;')
     707            ''
     708            sage: singular._eval_line_using_file('def a=3;', restart_if_needed=False)
     709            Traceback (most recent call last):
     710            ...
     711            RuntimeError: Singular terminated unexpectedly while reading in a large line
     712
     713        We end by triggering a re-start of Singular, since otherwise
     714        the doc test of another method would fail by a side effect.
     715        ::
     716
     717            sage: singular(3)
     718            Singular crashed -- automatically restarting.
     719            3
     720
     721        """
    646722        F = open(self._local_tmpfile(), 'w')
    647723        F.write(line+'\n')
    648724        F.close()
     
    651727            self._send_tmpfile_to_server()
    652728            tmp_to_use = self._remote_tmpfile()
    653729        try:
    654             s = self._eval_line(self._read_in_file_command(tmp_to_use), allow_use_file=False)
     730            s = self._eval_line(self._read_in_file_command(tmp_to_use), allow_use_file=False, restart_if_needed=False)
    655731        except pexpect.EOF, msg:
    656732            if self._quit_string() in line:
    657733                # we expect to get an EOF if we're quitting.
    658734                return ''
     735            elif restart_if_needed==True: # the subprocess might have crashed
     736                try:
     737                    self._synchronize()
     738                    return self._post_process_from_file(self._eval_line_using_file(line, restart_if_needed=False))
     739                except RuntimeError, msg:
     740                    raise RuntimeError, '%s terminated unexpectedly while reading in a large line:\n%s'%(self,msg[0])
     741                except TypeError:
     742                    pass
    659743            raise RuntimeError, '%s terminated unexpectedly while reading in a large line'%self
     744        except RuntimeError,msg:
     745            if self._quit_string() in line:
     746                if self._expect is None or not self._expect.isalive():
     747                    return ''
     748                raise
     749            if restart_if_needed==True and (self._expect is None or not self._expect.isalive()):
     750                try:
     751                    self._synchronize()
     752                    return self._post_process_from_file(self._eval_line_using_file(line, restart_if_needed=False))
     753                except TypeError:
     754                    pass
     755                except RuntimeError, msg:
     756                    raise RuntimeError, '%s terminated unexpectedly while reading in a large line'%self
     757            if "Input/output error" in msg[0]: # This occurs on non-linux machines
     758                raise RuntimeError, '%s terminated unexpectedly while reading in a large line'%self
     759            raise RuntimeError, '%s terminated unexpectedly while reading in a large line:\n%s'%(self,msg[0])
    660760        return self._post_process_from_file(s)
    661761
    662762    def _post_process_from_file(self, s):
    663763        return s
    664764
    665     def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True):
    666         if allow_use_file and self._eval_using_file_cutoff and len(line) > self._eval_using_file_cutoff:
     765    def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=True):
     766        """
     767        Evaluate a line of commands.
     768
     769        REMARK:
     770
     771        By default, a long command (length exceeding ``self._eval_using_file_cutoff``)
     772        is evaluated using :meth:`_eval_line_using_file`.
     773
     774        If the command can not be evaluated since the interface
     775        has crashed, it is automatically restarted and tried
     776        again *once*.
     777
     778        If the optional ``wait_for_prompt`` is ``False`` then even a very
     779        long line will not be evaluated by :meth:`_eval_line_using_file`,
     780        since this does not support the ``wait_for_prompt`` option.
     781
     782        INPUT:
     783
     784        - ``line`` -- (string) a command.
     785        - ``allow_use_file`` (optional bool, default ``True``) --
     786          allow to evaluate long commands using :meth:`_eval_line_using_file`.
     787        - ``wait_for_prompt`` (optional bool, default ``True``) --
     788          wait until the prompt appears in the sub-process' output.
     789        - ``restart_if_needed`` (optional bool, default ``True``) --
     790          If it is ``True``, the command evaluation is evaluated
     791          a second time after restarting the interface, if an
     792          ``EOFError`` occured.
     793
     794        TESTS::
     795
     796            sage: singular._eval_line('def a=3;')
     797            'def a=3;'
     798            sage: singular('a')
     799            3
     800            sage: singular.eval('quit;')
     801            ''
     802            sage: singular._eval_line('def a=3;')
     803            Singular crashed -- automatically restarting.
     804            'def a=3;'
     805            sage: singular('a')
     806            3
     807            sage: singular.eval('kill a')
     808            'kill a;'
     809
     810        We are now sending a command that would run forever. But since
     811        we declare that we are not waiting for a prompt, we can interrupt
     812        it without a KeyboardInterrupt. At the same time, we test that
     813        the line is not forwarded to :meth:`_eval_line_using_file`, since
     814        that method would not support the ``wait_for_prompt`` option::
     815
     816            sage: cutoff = singular._eval_using_file_cutoff
     817            sage: singular._eval_using_file_cutoff = 4
     818            sage: singular._eval_line('for(int i=1;i<=3;i++){i=1;};', wait_for_prompt=False)
     819            ''
     820            sage: singular.interrupt(timeout=1)
     821            False
     822            sage: singular._eval_using_file_cutoff = cutoff
     823
     824        Last, we demonstrate that by default the execution of a command
     825        is tried twice if it fails the first time due to a crashed
     826        interface::
     827
     828            sage: singular.eval('quit;')
     829            ''
     830            sage: singular._eval_line_using_file('def a=3;', restart_if_needed=False)
     831            Traceback (most recent call last):
     832            ...
     833            RuntimeError: Singular terminated unexpectedly while reading in a large line
     834
     835        Since the doc test of the next method would fail, we re-start
     836        Singular now.
     837        ::
     838
     839            sage: singular(2+3)
     840            Singular crashed -- automatically restarting.
     841            5
     842
     843        """
     844        if allow_use_file and wait_for_prompt and self._eval_using_file_cutoff and len(line) > self._eval_using_file_cutoff:
    667845            return self._eval_line_using_file(line)
    668846        try:
    669847            if self._expect is None:
     
    677855                    return ''
    678856               
    679857            except OSError, msg:
     858                if not E.isalive():
     859                    if restart_if_needed==True: # the subprocess might have crashed
     860                        try:
     861                            self._synchronize()
     862                            return self._eval_line(line,allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt, restart_if_needed=False)
     863                        except (TypeError, RuntimeError):
     864                            pass
    680865                raise RuntimeError, "%s\nError evaluating %s in %s"%(msg, line, self)
    681866           
    682867            if len(line)>0:
     
    698883                    if self._quit_string() in line:
    699884                        # we expect to get an EOF if we're quitting.
    700885                        return ''
     886                    elif restart_if_needed==True: # the subprocess might have crashed
     887                        try:
     888                            self._synchronize()
     889                            return self._eval_line(line,allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt, restart_if_needed=False)
     890                        except (TypeError, RuntimeError):
     891                            pass
    701892                    raise RuntimeError, "%s\n%s crashed executing %s"%(msg,self, line)
    702893                out = E.before
    703894            else:
     
    8481039            Control-C pressed.  Interrupting PARI/GP interpreter. Please wait a few seconds...
    8491040            ...
    8501041            KeyboardInterrupt: computation timed out because alarm was set for 1 seconds
     1042
     1043        Here is a doc test related with trac ticket #10296::
     1044
     1045            sage: gap._synchronize()
     1046
    8511047        """
    8521048        if expr is None:
    853             expr = self._prompt_wait
     1049            # the following works around gap._prompt_wait not being defined
     1050            expr = (hasattr(self,'_prompt_wait') and self._prompt_wait) or self._prompt
    8541051        if self._expect is None:
    8551052            self._start()
    8561053        try:
     
    12051402       
    12061403            sage: from sage.interfaces.expect import StdOutContext
    12071404            sage: with StdOutContext(singular):
    1208             ...       singular('1+1')
     1405            ...       singular.eval('1+1')
    12091406            ...
    1210             1+...
     1407            1+1;
     1408            ...
    12111409        """
    12121410        if self.silent:
    12131411            return
  • sage/interfaces/gap.py

    diff --git a/sage/interfaces/gap.py b/sage/interfaces/gap.py
    a b  
    380380
    381381
    382382    def _execute_line(self, line, wait_for_prompt=True, expect_eof=False):
     383        if self._expect is None: # interface is down
     384            self._start()
    383385        E = self._expect
     386       
    384387        try:
    385388            if len(line) > 4095:
    386389                raise RuntimeError("Passing commands this long to gap would hang")
     
    464467        self.quit()
    465468        raise KeyboardInterrupt, "Ctrl-c pressed while running %s"%self
    466469
    467     def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True):
     470    def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=True):
    468471        """
    469         EXAMPLES::
     472        Evaluate a line of commands.
     473
     474        REMARK:
     475
     476        By default, a long command (length exceeding ``self._eval_using_file_cutoff``)
     477        is evaluated using :meth:`_eval_line_using_file`.
     478
     479        If the command can not be evaluated since the interface
     480        has crashed, it is automatically restarted and tried
     481        again *once*.
     482
     483        If the optional ``wait_for_prompt`` is ``False`` then even a very long line
     484        will not be evaluated by :meth:`_eval_line_using_file`, since this does not
     485        support the ``wait_for_prompt`` option.
     486
     487        INPUT:
     488
     489        - ``line`` -- (string) a command.
     490        - ``allow_use_file`` (optional bool, default ``True``) --
     491          allow to evaluate long commands using :meth:`_eval_line_using_file`.
     492        - ``wait_for_prompt`` (optional bool, default ``True``) --
     493          wait until the prompt appears in the sub-process' output.
     494        - ``restart_if_needed`` (optional bool, default ``True``) --
     495          If it is ``True``, the command evaluation is evaluated
     496          a second time after restarting the interface, if an
     497          ``EOFError`` occured.
     498
     499        TESTS::
    470500       
    471501            sage: gap._eval_line('2+2;')
    472502            '4'
     503
     504        We test the ``wait_for_prompt`` option by sending a command that
     505        creates an infinite loop in the GAP sub-process. But if we don't
     506        wait for the prompt to appear in the output, we can interrupt
     507        the loop without raising a KeyboardInterrupt. At the same time,
     508        we test that the line is not forwarded to :meth:`_eval_line_using_file`,
     509        since that method would not support the ``wait_for_prompt`` option::
     510
     511            sage: cutoff = gap._eval_using_file_cutoff
     512            sage: gap._eval_using_file_cutoff = 4
     513            sage: gap._eval_line('while(1=1) do i:=1;; od;', wait_for_prompt=False)
     514            ''
     515            sage: gap.interrupt(timeout=1) is not None
     516            True
     517            sage: gap._eval_using_file_cutoff = cutoff
     518
     519        The following tests against a bug fixed at trac ticket #10296:
     520
     521            sage: a = gap(3)
     522            sage: gap.eval('quit;')
     523            ''
     524            sage: a = gap(3)
     525            ** Gap crashed or quit executing '$sage...:=3;;' **
     526            Restarting Gap and trying again
     527            sage: a
     528            3
     529
    473530        """
    474531        #if line.find('\n') != -1:
    475532        #    raise ValueError, "line must not contain any newlines"
     533        E = None
    476534        try:
    477535            if self._expect is None:
    478536                self._start()
    479537            E = self._expect
    480538            #import pdb; pdb.set_trace()
    481             if allow_use_file and len(line) > self._eval_using_file_cutoff:
     539            if allow_use_file and wait_for_prompt and len(line) > self._eval_using_file_cutoff:
    482540                return self._eval_line_using_file(line)
    483             try:
    484                 (normal, error) = self._execute_line(line, wait_for_prompt=wait_for_prompt,
     541            (normal, error) = self._execute_line(line, wait_for_prompt=wait_for_prompt,
    485542                                                 expect_eof= (self._quit_string() in line))
    486543
    487                 if len(error)> 0:
    488                     if 'Error, Rebuild completion files!' in error:
    489                         error += "\nRunning gap_reset_workspace()..."
    490                         self.quit()
    491                         gap_reset_workspace()
    492                     error = error.replace('\r','')
    493                     raise RuntimeError, "%s produced error output\n%s\n   executing %s"%(self, error,line)
    494                 if len(normal) == 0:
     544            if len(error)> 0:
     545                if 'Error, Rebuild completion files!' in error:
     546                    error += "\nRunning gap_reset_workspace()..."
     547                    self.quit()
     548                    gap_reset_workspace()
     549                error = error.replace('\r','')
     550                raise RuntimeError, "%s produced error output\n%s\n   executing %s"%(self, error,line)
     551            if len(normal) == 0:
     552                return ''
     553
     554            if isinstance(wait_for_prompt, str) and normal.ends_with(wait_for_prompt):
     555                n = len(wait_for_prompt)
     556            elif normal.endswith(self._prompt):
     557                n = len(self._prompt)
     558            elif normal.endswith(self._continuation_prompt()):
     559                n = len(self._continuation_prompt())
     560            else:
     561                n = 0
     562            out = normal[:-n]
     563            if len(out) > 0 and out[-1] == "\n":
     564                out = out[:-1]
     565            return out
     566
     567        except (RuntimeError,TypeError),message:
     568            if 'EOF' in message[0] or E is None or not E.isalive():
     569                print "** %s crashed or quit executing '%s' **"%(self, line)
     570                print "Restarting %s and trying again"%self
     571                self._start()
     572                if line != '':
     573                    return self._eval_line(line, allow_use_file=allow_use_file)
     574                else:
    495575                    return ''
    496 
    497                 if isinstance(wait_for_prompt, str) and normal.ends_with(wait_for_prompt):
    498                     n = len(wait_for_prompt)
    499                 elif normal.endswith(self._prompt):
    500                     n = len(self._prompt)
    501                 elif normal.endswith(self._continuation_prompt()):
    502                     n = len(self._continuation_prompt())
    503                 else:
    504                     n = 0
    505                 out = normal[:-n]
    506                 if len(out) > 0 and out[-1] == "\n":
    507                     out = out[:-1]
    508                 return out
    509 
    510             except (RuntimeError,),message:
    511                 if 'EOF' in message:
    512                     print "** %s crashed or quit executing '%s' **"%(self, line)
    513                     print "Restarting %s and trying again"%self
    514                     self._start()
    515                     if line != '':
    516                         return self._eval_line(line, allow_use_file=allow_use_file)
    517                     else:
    518                         return ''
    519                 else:
    520                     raise RuntimeError, message
     576            else:
     577                raise RuntimeError, message
    521578
    522579        except KeyboardInterrupt:
    523580            self._keyboard_interrupt()
  • sage/interfaces/gp.py

    diff --git a/sage/interfaces/gp.py b/sage/interfaces/gp.py
    a b  
    371371        """
    372372        return self.set_default('seriesprecision', prec)
    373373
    374     def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True):
     374    def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=False):
    375375        """
    376376        EXAMPLES::
    377377       
  • sage/interfaces/kash.py

    diff --git a/sage/interfaces/kash.py b/sage/interfaces/kash.py
    a b  
    503503
    504504    # Change the default for KASH, since eval using a file doesn't
    505505    # work except for setting variables.
    506     def _eval_line(self, line, allow_use_file=False, wait_for_prompt=True):
     506    def _eval_line(self, line, allow_use_file=False, wait_for_prompt=True, restart_if_needed=False):
    507507        return Expect._eval_line(self, line, allow_use_file=allow_use_file,
    508508                                 wait_for_prompt=wait_for_prompt)
    509509
  • sage/interfaces/lie.py

    diff --git a/sage/interfaces/lie.py b/sage/interfaces/lie.py
    a b  
    609609        except KeyError:
    610610            return "Could not find help for " + command
    611611
    612     def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True):
     612    def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=False):
    613613        """
    614614        EXAMPLES:
    615615            sage: lie._eval_line('2+2') #optional -- requires LiE
  • sage/interfaces/maple.py

    diff --git a/sage/interfaces/maple.py b/sage/interfaces/maple.py
    a b  
    534534                sage.misc.persist.save(v, COMMANDS_CACHE)
    535535            return v
    536536
    537     def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True):
     537    def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=False):
    538538        """
    539539        EXAMPLES::
    540540       
  • sage/interfaces/mathematica.py

    diff --git a/sage/interfaces/mathematica.py b/sage/interfaces/mathematica.py
    a b  
    534534    #    """
    535535    #    self.eval('Clear[%s]'%var)
    536536
    537     def _eval_line(self, line,  allow_use_file=True, wait_for_prompt=True):
     537    def _eval_line(self, line,  allow_use_file=True, wait_for_prompt=True, restart_if_needed=False):
    538538        s = Expect._eval_line(self, line,
    539539             allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt)
    540540        return str(s).strip('\n')
  • sage/interfaces/maxima.py

    diff --git a/sage/interfaces/maxima.py b/sage/interfaces/maxima.py
    a b  
    714714            raise KeyboardInterrupt, msg
    715715
    716716    def _eval_line(self, line, allow_use_file=False,
    717                    wait_for_prompt=True, reformat=True, error_check=True):
     717                   wait_for_prompt=True, reformat=True, error_check=True, restart_if_needed=False):
    718718        """
    719719        Return result of line evaluation.
    720720
  • sage/interfaces/mupad.py

    diff --git a/sage/interfaces/mupad.py b/sage/interfaces/mupad.py
    a b  
    236236        return AsciiArtString(s)
    237237
    238238    def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True,
    239                    need_output=True):
     239                   need_output=True, restart_if_needed=False):
    240240        """
    241241        EXAMPLES:
    242242            sage: mupad._eval_line('2+2')  # optional - mupad
  • sage/interfaces/qepcad.py

    diff --git a/sage/interfaces/qepcad.py b/sage/interfaces/qepcad.py
    a b  
    11121112            raise AttributeError
    11131113        return QepcadFunction(self, attrname)
    11141114
    1115     def _eval_line(self, cmd):
     1115    def _eval_line(self, cmd, restart_if_needed=False):
    11161116        r"""
    11171117        Send a command to QEPCAD, wait for a prompt, and return the
    11181118        text printed by QEPCAD before the prompt.  Not intended for
  • sage/interfaces/singular.py

    diff --git a/sage/interfaces/singular.py b/sage/interfaces/singular.py
    a b  
    1919
    2020- Martin Albrecht (2006-05-18): added sage_poly.
    2121
     22- Simon King (2010-11-23): Reduce the overhead caused by waiting for
     23  the Singular prompt by doing garbage collection differently.
     24
    2225- Simon King (2011-06-06): Make conversion from Singular to Sage more flexible.
    2326
    2427Introduction
     
    549552            sage: set_verbose(0)
    550553            sage: o = s.hilb()
    551554        """
    552         # Synchronize the interface and clear any variables that are queued up to
    553         # be cleared.
    554         self._synchronize()
    555         if len(self.__to_clear) > 0:
    556             for var in self.__to_clear:
    557                 self._eval_line('if(defined(%s)>0){kill %s;};'%(var,var), wait_for_prompt=True)
    558             self.__to_clear = []
     555        # Simon King:
     556        # In previous versions, the interface was first synchronised and then
     557        # unused variables were killed. This created a considerable overhead.
     558        # By trac ticket #10296, killing unused variables is now done inside
     559        # singular.set(). Moreover, it is not done by calling a separate _eval_line.
     560        # In that way, the time spent by waiting for the singular prompt is reduced.
     561
     562        # Before #10296, it was possible that garbage collection occured inside
     563        # of _eval_line. But collection of the garbage would launch another call
     564        # to _eval_line. The result would have been a dead lock, that could only
     565        # be avoided by synchronisation. Since garbage collection is now done
     566        # without an additional call to _eval_line, synchronisation is not
     567        # needed anymore, saving even more waiting time for the prompt.
    559568       
    560569        # Uncomment the print statements below for low-level debugging of
    561570        # code that involves the singular interfaces.  Everything goes
     
    586595        """
    587596        Set the variable with given name to the given value.
    588597       
     598        REMARK:
     599
     600        If a variable in the Singular interface was previously marked for
     601        deletion, the actual deletion is done here, before the new variable
     602        is created in Singular.
     603
    589604        EXAMPLES::
    590605       
    591606            sage: singular.set('int', 'x', '2')
    592607            sage: singular.get('x')
    593608            '2'
     609
     610        We test that an unused variable is only actually deleted if this method
     611        is called::
     612
     613            sage: a = singular(3)
     614            sage: n = a.name()
     615            sage: del a
     616            sage: singular.eval(n)
     617            '3'
     618            sage: singular.set('int', 'y', '5')
     619            sage: singular.eval('defined(%s)'%n)
     620            '0'
     621
    594622        """
    595         cmd = '%s %s=%s;'%(type, name, value)
     623        cmd = ''.join('if(defined(%s)){kill %s;};'%(v,v) for v in self.__to_clear) + '%s %s=%s;'%(type, name, value)
     624        self.__to_clear = []
    596625        try:
    597626            out = self.eval(cmd)
    598627        except RuntimeError, msg:
     
    612641       
    613642    def clear(self, var):
    614643        """
    615         Clear the variable named var.
     644        Clear the variable named ``var``.
    616645       
    617646        EXAMPLES::
    618647       
     
    620649            sage: singular.get('x')
    621650            '2'
    622651            sage: singular.clear('x')
     652
     653        "Clearing the variable" means to allow to free the memory
     654        that it uses in the Singular sub-process. However, the
     655        actual deletion of the variable is only committed when
     656        the next element in the Singular interface is created::
     657
     658            sage: singular.get('x')
     659            '2'
     660            sage: a = singular(3)
    623661            sage: singular.get('x')
    624662            '`x`'
     663
    625664        """
    626665        # We add the variable to the list of vars to clear when we do an eval.
    627666        # We queue up all the clears and do them at once to avoid synchronizing