Ranges and the [1,2,..,n] notation

AUTHORS:

  • Jeroen Demeyer (2016-02-22): moved here from misc.py and cleaned up.

sage.arith.srange.ellipsis_iter(step=None, *args)[source]

Same as ellipsis_range, but as an iterator (and may end with an Ellipsis).

See also ellipsis_range.

Use (1,2,…) notation.

EXAMPLES:

sage: A = ellipsis_iter(1,2,Ellipsis)
sage: [next(A) for _ in range(10)]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
sage: next(A)
11
sage: A = ellipsis_iter(1,3,5,Ellipsis)
sage: [next(A) for _ in range(10)]
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
sage: A = ellipsis_iter(1,2,Ellipsis,5,10,Ellipsis)
sage: [next(A) for _ in range(10)]
[1, 2, 3, 4, 5, 10, 11, 12, 13, 14]
>>> from sage.all import *
>>> A = ellipsis_iter(Integer(1),Integer(2),Ellipsis)
>>> [next(A) for _ in range(Integer(10))]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> next(A)
11
>>> A = ellipsis_iter(Integer(1),Integer(3),Integer(5),Ellipsis)
>>> [next(A) for _ in range(Integer(10))]
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
>>> A = ellipsis_iter(Integer(1),Integer(2),Ellipsis,Integer(5),Integer(10),Ellipsis)
>>> [next(A) for _ in range(Integer(10))]
[1, 2, 3, 4, 5, 10, 11, 12, 13, 14]
sage.arith.srange.ellipsis_range(step=None, *args)[source]

Return arithmetic sequence determined by the numeric arguments and ellipsis. Best illustrated by examples.

Use [1,2,..,n] notation.

EXAMPLES:

sage: ellipsis_range(1,Ellipsis,11,100)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 100]
sage: ellipsis_range(0,2,Ellipsis,10,Ellipsis,20)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
sage: ellipsis_range(0,2,Ellipsis,11,Ellipsis,20)
[0, 2, 4, 6, 8, 10, 11, 13, 15, 17, 19]
sage: ellipsis_range(0,2,Ellipsis,11,Ellipsis,20, step=3)
[0, 2, 5, 8, 11, 14, 17, 20]
sage: ellipsis_range(10,Ellipsis,0)
[]
>>> from sage.all import *
>>> ellipsis_range(Integer(1),Ellipsis,Integer(11),Integer(100))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 100]
>>> ellipsis_range(Integer(0),Integer(2),Ellipsis,Integer(10),Ellipsis,Integer(20))
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
>>> ellipsis_range(Integer(0),Integer(2),Ellipsis,Integer(11),Ellipsis,Integer(20))
[0, 2, 4, 6, 8, 10, 11, 13, 15, 17, 19]
>>> ellipsis_range(Integer(0),Integer(2),Ellipsis,Integer(11),Ellipsis,Integer(20), step=Integer(3))
[0, 2, 5, 8, 11, 14, 17, 20]
>>> ellipsis_range(Integer(10),Ellipsis,Integer(0))
[]
sage.arith.srange.srange(*args, **kwds)[source]

Return a list of numbers start, start+step, ..., start+k*step, where start+k*step < end and start+(k+1)*step >= end.

This provides one way to iterate over Sage integers as opposed to Python int’s. It also allows you to specify step sizes for such an iteration.

INPUT:

  • start – number (default: 0)

  • end – number

  • step – number (default: 1)

  • universe -- parent or type where all the elements should live (default: deduce from inputs). This is only used if ``coerce is true.

  • coerce – convert start, end and step to the same universe (either the universe given in universe or the automatically detected universe)

  • include_endpoint – whether or not to include the endpoint (default: False). This is only relevant if end is actually of the form start + k*step for some integer \(k\).

` endpoint_tolerance – used to determine whether or not the

endpoint is hit for inexact rings (default: 1e-5)

OUTPUT: list

Note

This function is called srange to distinguish it from the built-in Python range command. The s at the beginning of the name stands for “Sage”.

See also

xsrange() – iterator which is used to implement srange().

EXAMPLES:

sage: v = srange(5); v
[0, 1, 2, 3, 4]
sage: type(v[2])
<class 'sage.rings.integer.Integer'>
sage: srange(1, 10)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
sage: srange(10, 1, -1)
[10, 9, 8, 7, 6, 5, 4, 3, 2]
sage: srange(10,1,-1, include_endpoint=True)
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
sage: srange(1, 10, universe=RDF)
[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]

sage: srange(1, 10, 1/2)
[1, 3/2, 2, 5/2, 3, 7/2, 4, 9/2, 5, 11/2, 6, 13/2, 7, 15/2, 8, 17/2, 9, 19/2]

sage: # needs sage.rings.real_mpfr
sage: srange(1, 5, 0.5)
[1.00000000000000, 1.50000000000000, 2.00000000000000, 2.50000000000000,
 3.00000000000000, 3.50000000000000, 4.00000000000000, 4.50000000000000]
sage: srange(0, 1, 0.4)
[0.000000000000000, 0.400000000000000, 0.800000000000000]
sage: srange(1.0, 5.0, include_endpoint=True)
[1.00000000000000, 2.00000000000000, 3.00000000000000, 4.00000000000000,
 5.00000000000000]
sage: srange(1.0, 1.1)
[1.00000000000000]
sage: srange(1.0, 1.0)
[]

sage: V = VectorSpace(QQ, 2)                                                    # needs sage.modules
sage: srange(V([0,0]), V([5,5]), step=V([2,2]))                                 # needs sage.modules
[(0, 0), (2, 2), (4, 4)]
>>> from sage.all import *
>>> v = srange(Integer(5)); v
[0, 1, 2, 3, 4]
>>> type(v[Integer(2)])
<class 'sage.rings.integer.Integer'>
>>> srange(Integer(1), Integer(10))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> srange(Integer(10), Integer(1), -Integer(1))
[10, 9, 8, 7, 6, 5, 4, 3, 2]
>>> srange(Integer(10),Integer(1),-Integer(1), include_endpoint=True)
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> srange(Integer(1), Integer(10), universe=RDF)
[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]

>>> srange(Integer(1), Integer(10), Integer(1)/Integer(2))
[1, 3/2, 2, 5/2, 3, 7/2, 4, 9/2, 5, 11/2, 6, 13/2, 7, 15/2, 8, 17/2, 9, 19/2]

>>> # needs sage.rings.real_mpfr
>>> srange(Integer(1), Integer(5), RealNumber('0.5'))
[1.00000000000000, 1.50000000000000, 2.00000000000000, 2.50000000000000,
 3.00000000000000, 3.50000000000000, 4.00000000000000, 4.50000000000000]
>>> srange(Integer(0), Integer(1), RealNumber('0.4'))
[0.000000000000000, 0.400000000000000, 0.800000000000000]
>>> srange(RealNumber('1.0'), RealNumber('5.0'), include_endpoint=True)
[1.00000000000000, 2.00000000000000, 3.00000000000000, 4.00000000000000,
 5.00000000000000]
>>> srange(RealNumber('1.0'), RealNumber('1.1'))
[1.00000000000000]
>>> srange(RealNumber('1.0'), RealNumber('1.0'))
[]

>>> V = VectorSpace(QQ, Integer(2))                                                    # needs sage.modules
>>> srange(V([Integer(0),Integer(0)]), V([Integer(5),Integer(5)]), step=V([Integer(2),Integer(2)]))                                 # needs sage.modules
[(0, 0), (2, 2), (4, 4)]

Including the endpoint:

sage: srange(0, 10, step=2, include_endpoint=True)
[0, 2, 4, 6, 8, 10]
sage: srange(0, 10, step=3, include_endpoint=True)
[0, 3, 6, 9]
>>> from sage.all import *
>>> srange(Integer(0), Integer(10), step=Integer(2), include_endpoint=True)
[0, 2, 4, 6, 8, 10]
>>> srange(Integer(0), Integer(10), step=Integer(3), include_endpoint=True)
[0, 3, 6, 9]

Try some inexact rings:

sage: srange(0.5, 1.1, 0.1, universe=RDF, include_endpoint=False)
[0.5, 0.6, 0.7, 0.7999999999999999, 0.8999999999999999, 0.9999999999999999]
sage: srange(0.5, 1, 0.1, universe=RDF, include_endpoint=False)
[0.5, 0.6, 0.7, 0.7999999999999999, 0.8999999999999999]
sage: srange(0.5, 0.9, 0.1, universe=RDF, include_endpoint=False)
[0.5, 0.6, 0.7, 0.7999999999999999]
sage: srange(0, 1.1, 0.1, universe=RDF, include_endpoint=True)
[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6, 0.7,
 0.7999999999999999, 0.8999999999999999, 0.9999999999999999, 1.1]
sage: srange(0, 0.2, 0.1, universe=RDF, include_endpoint=True)
[0.0, 0.1, 0.2]
sage: srange(0, 0.3, 0.1, universe=RDF, include_endpoint=True)
[0.0, 0.1, 0.2, 0.3]
>>> from sage.all import *
>>> srange(RealNumber('0.5'), RealNumber('1.1'), RealNumber('0.1'), universe=RDF, include_endpoint=False)
[0.5, 0.6, 0.7, 0.7999999999999999, 0.8999999999999999, 0.9999999999999999]
>>> srange(RealNumber('0.5'), Integer(1), RealNumber('0.1'), universe=RDF, include_endpoint=False)
[0.5, 0.6, 0.7, 0.7999999999999999, 0.8999999999999999]
>>> srange(RealNumber('0.5'), RealNumber('0.9'), RealNumber('0.1'), universe=RDF, include_endpoint=False)
[0.5, 0.6, 0.7, 0.7999999999999999]
>>> srange(Integer(0), RealNumber('1.1'), RealNumber('0.1'), universe=RDF, include_endpoint=True)
[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6, 0.7,
 0.7999999999999999, 0.8999999999999999, 0.9999999999999999, 1.1]
>>> srange(Integer(0), RealNumber('0.2'), RealNumber('0.1'), universe=RDF, include_endpoint=True)
[0.0, 0.1, 0.2]
>>> srange(Integer(0), RealNumber('0.3'), RealNumber('0.1'), universe=RDF, include_endpoint=True)
[0.0, 0.1, 0.2, 0.3]

More examples:

sage: Q = RationalField()
sage: srange(1, 10, Q('1/2'))
[1, 3/2, 2, 5/2, 3, 7/2, 4, 9/2, 5, 11/2, 6, 13/2, 7, 15/2, 8, 17/2, 9, 19/2]
sage: srange(1, 5, 0.5)                                                         # needs sage.rings.real_mpfr
[1.00000000000000, 1.50000000000000, 2.00000000000000, 2.50000000000000,
 3.00000000000000, 3.50000000000000, 4.00000000000000, 4.50000000000000]
sage: srange(0, 1, 0.4)                                                         # needs sage.rings.real_mpfr
[0.000000000000000, 0.400000000000000, 0.800000000000000]
>>> from sage.all import *
>>> Q = RationalField()
>>> srange(Integer(1), Integer(10), Q('1/2'))
[1, 3/2, 2, 5/2, 3, 7/2, 4, 9/2, 5, 11/2, 6, 13/2, 7, 15/2, 8, 17/2, 9, 19/2]
>>> srange(Integer(1), Integer(5), RealNumber('0.5'))                                                         # needs sage.rings.real_mpfr
[1.00000000000000, 1.50000000000000, 2.00000000000000, 2.50000000000000,
 3.00000000000000, 3.50000000000000, 4.00000000000000, 4.50000000000000]
>>> srange(Integer(0), Integer(1), RealNumber('0.4'))                                                         # needs sage.rings.real_mpfr
[0.000000000000000, 0.400000000000000, 0.800000000000000]

Negative steps are also allowed:

sage: srange(4, 1, -1)
[4, 3, 2]
sage: srange(4, 1, -1/2)
[4, 7/2, 3, 5/2, 2, 3/2]
>>> from sage.all import *
>>> srange(Integer(4), Integer(1), -Integer(1))
[4, 3, 2]
>>> srange(Integer(4), Integer(1), -Integer(1)/Integer(2))
[4, 7/2, 3, 5/2, 2, 3/2]
sage.arith.srange.xsrange(start, end=None, step=1, universe=None, coerce=True, include_endpoint=False, endpoint_tolerance=1e-05)[source]

Return an iterator over numbers start, start+step, ..., start+k*step, where start+k*step < end and start+(k+1)*step >= end.

This provides one way to iterate over Sage integers as opposed to Python int’s. It also allows you to specify step sizes for such an iteration.

INPUT:

  • start – number (default: 0)

  • end – number

  • step – number (default: 1)

  • universe – parent or type where all the elements should live (default: deduce from inputs)

  • coerce – convert start, end and step to the same universe (either the universe given in universe or the automatically detected universe)

  • include_endpoint – whether or not to include the endpoint (default: False). This is only relevant if end is actually of the form start + k*step for some integer \(k\).

` endpoint_tolerance – used to determine whether or not the

endpoint is hit for inexact rings (default: 1e-5)

OUTPUT: iterator

Unlike range(), start and end can be any type of numbers, and the resulting iterator involves numbers of that type.

Warning

You need to be careful when using this function over inexact rings: the elements are computed via repeated addition rather than multiplication, which may produce slightly different results. For example:

sage: sum([1.1] * 10) == 1.1 * 10
False
>>> from sage.all import *
>>> sum([RealNumber('1.1')] * Integer(10)) == RealNumber('1.1') * Integer(10)
False

Also, the question of whether the endpoint is hit exactly for a given start + k*step is fuzzy for an inexact ring. If start + k*step = end for some \(k\) within endpoint_tolerance of being integral, it is considered an exact hit, thus avoiding spurious values falling just below the endpoint.

EXAMPLES:

sage: xsrange(10)
<...generator object at 0x...>
sage: for i in xsrange(1,5):
....:     print(i)
1
2
3
4
>>> from sage.all import *
>>> xsrange(Integer(10))
<...generator object at 0x...>
>>> for i in xsrange(Integer(1),Integer(5)):
...     print(i)
1
2
3
4

See srange() for more examples.