Ticket #11657: trac_11657-rewrite.patch

File trac_11657-rewrite.patch, 7.8 KB (added by was, 11 years ago)

apply only this; total rewrite of the previous patch

  • sage/modules/free_module.py

    # HG changeset patch
    # User Rob Beezer <beezer@ups.edu> and William Stein <wstein@gmail.com>
    # Date 1314215239 25200
    # Node ID dce2284d9d9d627905f0ff021011ecff3f28a26f
    # Parent  a2e494273d2099d9c646e42ba9f5e235918e6631
    11657: speed-up zero vector creation
    
    diff --git a/sage/modules/free_module.py b/sage/modules/free_module.py
    a b  
    332332        :meth:`_test_pickling` will test unique representation and not
    333333        only equality.
    334334        """
    335         rank = int(rank)
     335        rank = int(sage.rings.integer.Integer(rank))
    336336
    337337        if not (inner_product_matrix is None):
    338338            inner_product_matrix = sage.matrix.matrix_space.MatrixSpace(base_ring, rank)(inner_product_matrix)
  • sage/modules/free_module_element.pyx

    diff --git a/sage/modules/free_module_element.pyx b/sage/modules/free_module_element.pyx
    a b  
    110110
    111111import sage.rings.arith
    112112
    113 from sage.rings.ring import is_Ring
    114113from sage.rings.infinity import Infinity
    115 import sage.rings.integer_ring
    116114import sage.rings.integer
     115from sage.rings.integer_ring import ZZ
    117116from sage.rings.real_double import RDF
    118117from sage.rings.complex_double import CDF
    119 from sage.misc.derivative import multi_derivative
    120 
    121 #from sage.matrix.matrix cimport Matrix
     118from sage.misc.derivative import multi_derivative
     119
     120
     121# We use some cimports for very quick checking of Integer and Ring
     122# type to optimize vector(ring,n) for creating the zero vector.
     123from sage.rings.ring cimport Ring
     124from sage.rings.integer cimport Integer
     125
     126# We define our own faster is_Ring since is_Ring in the
     127# sage.rings.ring module is slowedue to it doing an import every time,
     128# and creating a category.  We should rarely hit the second case
     129# (is_Ring_slow below).  Note that this function will slightly slow
     130# down in the very rare case when R is not of type Ring, but it is in
     131# the category of rings.  But it gives a big speedup for the most
     132# common case when R is a Ring.
     133from sage.rings.ring import is_Ring as is_Ring_slow
     134cdef is_Ring(R):
     135    return isinstance(R, Ring) or is_Ring_slow(R)
    122136
    123137def is_FreeModuleElement(x):
    124138    """
     
    261275        (0, 0, 0, 0)
    262276        sage: w.parent()
    263277        Vector space of dimension 4 over Finite Field of size 7
     278       
     279    The fastest method to construct a zero vector is to call the
     280    :meth:`~sage.modules.free_module.FreeModule_generic.zero_vector`
     281    method directly on a free module or vector space, since
     282    vector(...)  must do a small amount of type checking.  Almost as
     283    fast as the ``zero_vector()`` method is the
     284    :func:`~sage.modules.free_module_element.zero_vector` constructor,
     285    which defaults to the integers.  ::
     286
     287        sage: vector(ZZ, 5)          # works fine
     288        (0, 0, 0, 0, 0)
     289        sage: (ZZ^5).zero_vector()   # very tiny bit faster
     290        (0, 0, 0, 0, 0)
     291        sage: zero_vector(ZZ, 5)     # similar speed to vector(...)
     292        (0, 0, 0, 0, 0)
     293        sage: z = zero_vector(5); z
     294        (0, 0, 0, 0, 0)
     295        sage: z.parent()
     296        Ambient free module of rank 5 over
     297        the principal ideal domain Integer Ring
    264298
    265299    Here we illustrate the creation of sparse vectors by using a
    266300    dictionary. ::
     
    289323        Traceback (most recent call last):
    290324        ...
    291325        ValueError: cannot specify the degree of a vector as a negative integer (-4)
    292 
     326       
     327    It is an error to create a zero vector but not provide
     328    a ring as the first argument.  ::
     329   
     330        sage: vector('junk', 20)
     331        Traceback (most recent call last):
     332        ...
     333        TypeError: first argument must be base ring of zero vector, not junk
     334       
    293335    And it is an error to specify an index in a dictionary
    294336    that is greater than or equal to a requested degree. ::
    295337
     
    370412        sage: x.parent()
    371413        Ambient free module of rank 0 over the principal ideal domain Integer Ring
    372414    """
     415    # We first efficiently handle the important special case of the zero vector
     416    # over a ring. See trac 11657.
     417    # !! PLEASE DO NOT MOVE THIS CODE LOWER IN THIS FUNCTION !!
     418    if arg2 is None and is_Ring(arg0) and (isinstance(arg1, (int, long, Integer))):
     419        return (arg0**arg1).zero_vector()
     420
     421    # WARNING TO FUTURE OPTIMIZERS: The following two hasattr's take
     422    # quite a significant amount of time.
    373423    if hasattr(arg0, '_vector_'):
    374424        return arg0._vector_(arg1)
    375425
     
    387437            if not maxindex < arg1:
    388438                raise ValueError("dictionary of entries has a key (index) exceeding the requested degree")
    389439        # arg1 is now a legitimate degree
    390         # replace it with a zero list or a dictionary, or a size-checked iterable
    391         # so then down to just two arguments
     440        # With no arg2, we can try to return a zero vector
     441        #   else we size-check arg2 and slide it into arg1
    392442        degree = arg1
    393443        if arg2 is None:
    394             arg1 = [0]*degree
     444            if not is_Ring(arg0):
     445                msg = "first argument must be base ring of zero vector, not {0}"
     446                raise TypeError(msg.format(arg0))
     447            return (arg0**degree).zero_vector()
    395448        else:
    396449            if not isinstance(arg2, dict) and len(arg2) != degree:
    397450                raise ValueError, "incompatible degrees in vector constructor"
     
    527580    if R is None:
    528581        try:
    529582            if len(v) == 0:
    530                 R = sage.rings.integer_ring.IntegerRing()
     583                R = ZZ
    531584        except TypeError:
    532585            pass
    533586    v = Sequence(v, universe=R, use_sage_types=True)
     
    589642        sage: zero_vector(5.6)
    590643        Traceback (most recent call last):
    591644        ...
    592         ValueError: constructing a zero vector requires the degree as an integer, not 5.60000000000000
     645        TypeError: Attempt to coerce non-integral RealNumber to Integer
    593646
    594647    Negative degrees also give an error. ::
    595648
    596649        sage: zero_vector(-3)
    597650        Traceback (most recent call last):
    598651        ...
    599         ValueError: cannot specify the degree of a vector as a negative integer (-3)
     652        ValueError: rank (=-3) must be nonnegative
    600653
    601654    Garbage instead of a ring will be recognized as such. ::
    602655
    603656        sage: zero_vector(x^2, 5)
    604657        Traceback (most recent call last):
    605658        ...
    606         ValueError: elements of a zero vector belong in a ring, not x^2
     659        TypeError: arg0 must be a ring
    607660    """
    608     # default to a zero vector over the integers (ZZ) if no ring given
    609661    if arg1 is None:
    610         arg1 = arg0
    611         arg0 = sage.rings.integer_ring.IntegerRing()
    612     if not (sage.rings.integer.is_Integer(arg1) or isinstance(arg1,(int,long))):
    613         raise ValueError("constructing a zero vector requires the degree as an integer, not %s" % arg1)
    614     if not is_Ring(arg0):
    615         raise ValueError("elements of a zero vector belong in a ring, not %s" % arg0)
    616     return vector(arg0, arg1)
     662        # default to a zero vector over the integers (ZZ) if no ring given
     663        return (ZZ**arg0).zero_vector()
     664    if is_Ring(arg0):
     665        # NOTE: The "or" above is for speed reasons: is_Ring only called in
     666        # when not a ring (slow path, get error), or when is_Ring would do
     667        # some slow category-theoretic check anyways.  We want to avoid
     668        # calling is_Ring.
     669        return (arg0**arg1).zero_vector()
     670    raise TypeError, "arg0 must be a ring"
    617671
    618672def random_vector(ring, degree=None, *args, **kwds):
    619673    r"""
     
    733787            arglist.insert(0, degree)
    734788            args = tuple(arglist)
    735789        degree = ring
    736         ring = sage.rings.integer_ring.IntegerRing()
     790        ring = ZZ
    737791    if not (sage.rings.integer.is_Integer(degree) or isinstance(degree,(int,long))):
    738792        raise TypeError("degree of a random vector must be an integer, not %s" % degree)
    739793    if degree < 0: