# 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
|
|
332 | 332 | :meth:`_test_pickling` will test unique representation and not |
333 | 333 | only equality. |
334 | 334 | """ |
335 | | rank = int(rank) |
| 335 | rank = int(sage.rings.integer.Integer(rank)) |
336 | 336 | |
337 | 337 | if not (inner_product_matrix is None): |
338 | 338 | inner_product_matrix = sage.matrix.matrix_space.MatrixSpace(base_ring, rank)(inner_product_matrix) |
diff --git a/sage/modules/free_module_element.pyx b/sage/modules/free_module_element.pyx
a
|
b
|
|
110 | 110 | |
111 | 111 | import sage.rings.arith |
112 | 112 | |
113 | | from sage.rings.ring import is_Ring |
114 | 113 | from sage.rings.infinity import Infinity |
115 | | import sage.rings.integer_ring |
116 | 114 | import sage.rings.integer |
| 115 | from sage.rings.integer_ring import ZZ |
117 | 116 | from sage.rings.real_double import RDF |
118 | 117 | from sage.rings.complex_double import CDF |
119 | | from sage.misc.derivative import multi_derivative |
120 | | |
121 | | #from sage.matrix.matrix cimport Matrix |
| 118 | from 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. |
| 123 | from sage.rings.ring cimport Ring |
| 124 | from 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. |
| 133 | from sage.rings.ring import is_Ring as is_Ring_slow |
| 134 | cdef is_Ring(R): |
| 135 | return isinstance(R, Ring) or is_Ring_slow(R) |
122 | 136 | |
123 | 137 | def is_FreeModuleElement(x): |
124 | 138 | """ |
… |
… |
|
261 | 275 | (0, 0, 0, 0) |
262 | 276 | sage: w.parent() |
263 | 277 | 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 |
264 | 298 | |
265 | 299 | Here we illustrate the creation of sparse vectors by using a |
266 | 300 | dictionary. :: |
… |
… |
|
289 | 323 | Traceback (most recent call last): |
290 | 324 | ... |
291 | 325 | 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 | |
293 | 335 | And it is an error to specify an index in a dictionary |
294 | 336 | that is greater than or equal to a requested degree. :: |
295 | 337 | |
… |
… |
|
370 | 412 | sage: x.parent() |
371 | 413 | Ambient free module of rank 0 over the principal ideal domain Integer Ring |
372 | 414 | """ |
| 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. |
373 | 423 | if hasattr(arg0, '_vector_'): |
374 | 424 | return arg0._vector_(arg1) |
375 | 425 | |
… |
… |
|
387 | 437 | if not maxindex < arg1: |
388 | 438 | raise ValueError("dictionary of entries has a key (index) exceeding the requested degree") |
389 | 439 | # 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 |
392 | 442 | degree = arg1 |
393 | 443 | 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() |
395 | 448 | else: |
396 | 449 | if not isinstance(arg2, dict) and len(arg2) != degree: |
397 | 450 | raise ValueError, "incompatible degrees in vector constructor" |
… |
… |
|
527 | 580 | if R is None: |
528 | 581 | try: |
529 | 582 | if len(v) == 0: |
530 | | R = sage.rings.integer_ring.IntegerRing() |
| 583 | R = ZZ |
531 | 584 | except TypeError: |
532 | 585 | pass |
533 | 586 | v = Sequence(v, universe=R, use_sage_types=True) |
… |
… |
|
589 | 642 | sage: zero_vector(5.6) |
590 | 643 | Traceback (most recent call last): |
591 | 644 | ... |
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 |
593 | 646 | |
594 | 647 | Negative degrees also give an error. :: |
595 | 648 | |
596 | 649 | sage: zero_vector(-3) |
597 | 650 | Traceback (most recent call last): |
598 | 651 | ... |
599 | | ValueError: cannot specify the degree of a vector as a negative integer (-3) |
| 652 | ValueError: rank (=-3) must be nonnegative |
600 | 653 | |
601 | 654 | Garbage instead of a ring will be recognized as such. :: |
602 | 655 | |
603 | 656 | sage: zero_vector(x^2, 5) |
604 | 657 | Traceback (most recent call last): |
605 | 658 | ... |
606 | | ValueError: elements of a zero vector belong in a ring, not x^2 |
| 659 | TypeError: arg0 must be a ring |
607 | 660 | """ |
608 | | # default to a zero vector over the integers (ZZ) if no ring given |
609 | 661 | 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" |
617 | 671 | |
618 | 672 | def random_vector(ring, degree=None, *args, **kwds): |
619 | 673 | r""" |
… |
… |
|
733 | 787 | arglist.insert(0, degree) |
734 | 788 | args = tuple(arglist) |
735 | 789 | degree = ring |
736 | | ring = sage.rings.integer_ring.IntegerRing() |
| 790 | ring = ZZ |
737 | 791 | if not (sage.rings.integer.is_Integer(degree) or isinstance(degree,(int,long))): |
738 | 792 | raise TypeError("degree of a random vector must be an integer, not %s" % degree) |
739 | 793 | if degree < 0: |