## "Fossies" - the Fresh Open Source Software Archive

### Member "NZMATH-1.2.0/nzmath/bigrange.py" (19 Nov 2012, 6348 Bytes) of package /linux/misc/old/NZMATH-1.2.0.tar.gz:

As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "bigrange.py" see the Fossies "Dox" file reference documentation.

```    1 """
2 bigrange
3
4 Generators for range like sequences.
5 """
6
7
8 def count(n=0):
9     """
10     Count up infinitely from 'n' (default to 0),
11
12     see itertools.count
13     """
14     while True:
15         yield n
16         n += 1
17
18
19 def range(start, stop=None, step=None):
20     """
21     Generate range like finite integer sequence but can generate more
22     than sys.maxint elements.
23     """
24     if step is None:
25         step = 1
26     elif not isinstance(step, (int, long)):
27         raise ValueError("non-integer step for range()")
28     if not isinstance(start, (int, long)):
29         raise ValueError("non-integer arg 1 for range()")
30     if stop is None:
31         start, stop = 0, start
32     elif not isinstance(stop, (int, long)):
33         raise ValueError("non-integer stop for range()")
34
35     if step > 0:
36         n = start
37         while n < stop:
38             yield n
39             n += step
40     elif step < 0:
41         n = start
42         while n > stop:
43             yield n
44             n += step
45     else:
46         raise ValueError("zero step for range()")
47
48
49 def arithmetic_progression(init, difference):
50     """
51     Generate an arithmetic progression start form 'init' and
52     'difference' step.
53     """
54     return _iterate(lambda x: x + difference, init)
55
56
57 def geometric_progression(init, ratio):
58     """
59     Generate a geometric progression start form 'init' and multiplying
60     'ratio'.
61     """
62     return _iterate(lambda x: x * ratio, init)
63
64
65 def _iterate(func, init):
66     """
67     Generate (infinitely) a sequence (init, func(init), func(func(init)), ...)
68     """
69     val = init
70     while True:
71         yield val
72         val = func(val)
73
74
75 def multirange(triples):
76     """
77     multirange(list of range triples) is an iterator over cartesian
78     product of elements of ranges.
79
80     For example, multirange([(1, 10, 3), (1, 10, 4)]) yields
81     (1, 1), (1, 5), (1, 9), (4, 1), (4, 5), (4, 9), (7, 1), (7, 5),
82     and (7, 9).
83
84     The range triples may be doubles (start, stop) or single (stop,),
85     but they have to be always tuples.
86
87     Be cautious that using this module usually means you are trying to
88     do brute force looping.
89     """
90     starts, stops, steps = _split_triples(triples)
91     if _empty(starts, stops, steps):
92         raise StopIteration("empty range")
93     i, values = len(triples) - 1, list(starts)
94     yield tuple(values)
95     while i >= 0:
96         values[i] += steps[i]
97         if _range_exhausted(i, values, steps, stops):
98             values[i] = starts[i]
99             i -= 1
100             continue
101         yield tuple(values)
102         i = len(triples) - 1
103
104 def _split_triples(triples):
105     """
106     Convert a list of triples into three lists each consists of 1st,
107     2nd and 3rd element of each triples.
108
109     The range triples may be doubles (start, stop) or single (stop,),
110     but they have to be always tuples.
111     """
112     starts, stops, steps = [], [], []
113     for triple in triples:
114         if len(triple) == 3:
115             start, stop, step = triple
116         elif len(triple) == 2:
117             start, stop, step = triple[0], triple[1], 1
118         elif len(triple) == 1:
119             start, stop, step = 0, triple[0], 1
120         else:
121             raise TypeError("tuple is longer or shorter than expected 1 to 3")
122         starts.append(start)
123         stops.append(stop)
124         steps.append(step)
125     return starts, stops, steps
126
127 def _empty(starts, stops, steps):
128     """
129     Report whether there is an empty range in the triples or not.
130     """
131     for start, stop, step in zip(starts, stops, steps):
132         if step * (stop - start) <= 0:
133             return True
134     return False
135
136 def _range_exhausted(i, values, steps, stops):
137     """
138     Check if a range at i is exhausted.
139     """
140     return steps[i] * (values[i] - stops[i]) >= 0
141
142
143 def multirange_restrictions(triples, ascending=(), descending=(), strictly_ascending=(), strictly_descending=()):
144     """
145     multirange_restrictions is an iterator similar to the multirange
146     but putting restrictions on each ranges.  A restriction ascending
147     is a sequence that specifies the indices where the number emitted
148     by the range should be greater than or equal to the number at the
149     previous index.  Other restrictions descending, strictly_ascending
150     and strictly_descending are similar.
151
152     For example, while multirange([(1, 10, 3), (1, 10, 4)]) yields
153     (1, 1), (1, 5), (1, 9), (4, 1), (4, 5), (4, 9), (7, 1), (7, 5),
154     and (7, 9),
155     multirange_restrictions([(1, 10, 3), (1, 10, 4)], ascending=(1,))
156     yields only (1, 1), (1, 5), (1, 9), (4, 5), (4, 9) and (7, 9).
157
158     The range triples may be doubles (start, stop) or single (stop,),
159     but they have to be always tuples.
160     """
161     starts, stops, steps = _split_triples(triples)
162     if _empty(starts, stops, steps):
163         raise StopIteration("empty range")
164     i, values = len(triples) - 1, list(starts)
165     while i >= 0:
166         if _range_exhausted(i, values, steps, stops):
167             values[i] = starts[i]
168             i -= 1
169         elif (strictly_ascending and _violate_strictly_ascending(values, strictly_ascending) or
170               ascending and _violate_ascending(values, ascending) or
171               strictly_descending and _violate_strictly_descending(values, strictly_descending) or
172               descending and _violate_descending(values, descending)):
173             i = min(i + 1, len(triples) - 1)
174         else:
175             yield tuple(values)
176             i = len(triples) - 1
177         values[i] += steps[i]
178
179 def _violate_ascending(values, ascending):
180     """
181     Check if values violate ascending restrictions.
182     """
183     for i in ascending:
184         if values[i - 1] > values[i]:
185             return True
186     return False
187
188 def _violate_strictly_ascending(values, ascending):
189     """
190     Check if values violate strictly-ascending restrictions.
191     """
192     for i in ascending:
193         if values[i - 1] >= values[i]:
194             return True
195     return False
196
197 def _violate_descending(values, descending):
198     """
199     Check if values violate descending restrictions.
200     """
201     for i in descending:
202         if values[i - 1] < values[i]:
203             return True
204     return False
205
206 def _violate_strictly_descending(values, descending):
207     """
208     Check if values violate strictly-descending restrictions.
209     """
210     for i in descending:
211         if values[i - 1] <= values[i]:
212             return True
213     return False
```