Ticket #2737: trac-2737-balancedsum-rebased-bug-fixed.patch

File trac-2737-balancedsum-rebased-bug-fixed.patch, 5.4 KB (added by jason, 8 months ago)

apply instead of previous patch

  • sage/misc/all.py

    # HG changeset patch
    # User Jason Grout <jason-sage@creativetrax.com>
    # Date 1247986062 25200
    # Node ID 538b09d8aea86ad2e012c5dc598236f2f9feb5d7
    # Parent  948462cfdacd8b68e44a91fe82c73646542f51b1
    Rebased and fixed a bug in a balanced sum implementation.
    
    diff -r 948462cfdacd -r 538b09d8aea8 sage/misc/all.py
    a b  
    99                  DOT_SAGE, SAGE_ROOT, SAGE_URL, SAGE_DB, SAGE_TMP, 
    1010                  is_32_bit, is_64_bit, newton_method_sizes) 
    1111 
    12 from misc_c import (prod, running_total) 
     12from misc_c import prod, running_total, balanced_sum 
    1313 
    1414from html import html 
    1515 
  • sage/misc/misc.py

    diff -r 948462cfdacd -r 538b09d8aea8 sage/misc/misc.py
    a b  
    545545        if c: return c 
    546546    return 0 
    547547 
    548 from sage.misc.misc_c import prod, running_total, is_64_bit, is_32_bit 
     548from sage.misc.misc_c import prod, running_total, balanced_sum, is_64_bit, is_32_bit 
    549549 
    550550# alternative name for prod 
    551551mul = prod 
  • sage/misc/misc_c.pyx

    diff -r 948462cfdacd -r 538b09d8aea8 sage/misc/misc_c.pyx
    a b  
    275275        """ 
    276276        return NonAssociative(self, other) 
    277277         
     278from copy import copy 
     279 
     280def balanced_sum(x, z=None, Py_ssize_t recursion_cutoff = 5): 
     281    """ 
     282    Return the sum of the elements in the list x.  If optional 
     283    argument z is not given, start the sum with the first element of 
     284    the list, otherwise use z.  The empty product is the int 0 if z is 
     285    not specified, and is z if given.  The sum is computed 
     286    recursively, where the sum is split up if the list is greater than 
     287    recursion_cutoff.  recursion_cutoff must be at least 3. 
     288 
     289    This assumes that your addition is associative; we don't promise  
     290    which end of the list we start at. 
     291 
     292     
     293    EXAMPLES: 
     294        sage: balanced_sum([1,2,34]) 
     295        37 
     296        sage: balanced_sum([2,3], 5) 
     297        10 
     298        sage: balanced_sum((1,2,3), 5) 
     299        11 
     300         
     301    Order should be preserved:: 
     302     
     303        sage: balanced_sum([[i] for i in range(10)], [], recursion_cutoff=3) 
     304        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]         
     305 
     306    We make copies when appropriate so that we don't accidentally modify the arguments. 
     307        
     308        sage: range(10e4)==balanced_sum([[i] for i in range(10e4)], []) 
     309        True 
     310        sage: range(10e4)==balanced_sum([[i] for i in range(10e4)], []) 
     311        True 
     312         
     313    TESTS: 
     314        sage: balanced_sum((1..3)) # nonempty, z=None 
     315        6 
     316        sage: balanced_sum((1..-1)) # empty, z=None 
     317        0 
     318        sage: balanced_sum((1..3), 5) # nonempty, z is not None 
     319        11 
     320        sage: balanced_sum((1..-1), 5) # empty, z is not None 
     321        5 
     322 
     323    AUTHORS: 
     324        Joel B. Mohler (2007-10-03 -- Reimplemented in Cython and optimized) 
     325        Robert Bradshaw (2007-10-26) -- Balanced product tree, other optimizations, (lazy) generator support 
     326    """ 
     327    if recursion_cutoff<3: 
     328        raise ValueError, "recursion_cutoff must be at least 3" 
     329 
     330    if not PyList_CheckExact(x) and not PyTuple_CheckExact(x): 
     331     
     332        if PyGen_Check(x): 
     333            # lazy list, do lazy product 
     334            try: 
     335                sum = copy(x.next()) if z is None else z + x.next() 
     336                for a in x: 
     337                    sum += a 
     338                return sum 
     339            except StopIteration: 
     340                x = [] 
     341        else: 
     342            try: 
     343                return x.sum() 
     344            except AttributeError: 
     345                pass 
     346 
     347            x = list(x) 
     348 
     349    cdef Py_ssize_t n = len(x) 
     350 
     351    if n == 0: 
     352        if z is None: 
     353            import sage.rings.integer 
     354            return sage.rings.integer.Integer(0) 
     355        else: 
     356            return z 
     357     
     358    sum = balanced_list_sum(x, 0, n, recursion_cutoff) 
     359     
     360    if z is not None: 
     361        sum = z+sum 
     362         
     363    return sum 
     364 
     365cdef balanced_list_sum(L, Py_ssize_t offset, Py_ssize_t count, Py_ssize_t cutoff): 
     366    """ 
     367    INPUT:  
     368        L      -- the terms (MUST be a tuple or list) 
     369        off    -- offset in the list from which to start 
     370        count  -- how many terms in the product 
     371        cutoff -- the minimum count to recurse on.  Must be at least 2 
     372         
     373    OUTPUT:  
     374        L[offset] + L[offset+1] + ... + L[offset+count-1] 
     375     
     376    NOTE: The parameter cutoff must be at least 3. However, there are 
     377          at least two advantages to setting it higher (and 
     378          consequently not recursing all the way down the 
     379          tree). First, one avoids the overhead of the function calls 
     380          at the base of the tree (which is the majority of them) and 
     381          second, it allows one to save on object creation if inplace 
     382          operations are used. The asymptotic gains should usually be 
     383          at the top of the tree anyway. 
     384    """ 
     385    cdef Py_ssize_t k 
     386    if count <= cutoff: 
     387        sum = <object>PySequence_Fast_GET_ITEM(L, offset)+<object>PySequence_Fast_GET_ITEM(L, offset+1) 
     388        for k from offset+1 < k < offset+count: 
     389            sum += <object>PySequence_Fast_GET_ITEM(L, k) 
     390        return sum 
     391    else: 
     392        k = (1+count) >> 1 
     393        return balanced_list_sum(L, offset, k, cutoff) + balanced_list_sum(L, offset+k, count-k, cutoff) 
     394 
    278395         
    279396############################################################################# 
    280397# Bitset Testing