"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