Skip to content

Commit 33d65dc

Browse files
committed
updated from Atlas repo
1 parent dcd59ee commit 33d65dc

21 files changed

+361
-301
lines changed
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
99
"""
1010

11-
import array
1211
from collections import abc
1312

13+
1414
class ArithmeticProgression:
1515

1616
def __init__(self, begin, step, end):
@@ -29,7 +29,8 @@ def __init__(self, arithmetic_progression):
2929
self._index = 0
3030

3131
def __next__(self):
32-
result = self._ap.begin + self._ap.step * self._index
32+
first = type(self._ap.begin + self._ap.step)(self._ap.begin)
33+
result = first + self._ap.step * self._index
3334
if result < self._ap.end:
3435
self._index += 1
3536
return result

iterables/almost_aritprog_v6.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""
2+
Arithmetic progression generator function.
3+
4+
This is almost correct. The only problem is that the first
5+
item in the series may not be of the same type as the rest,
6+
an this may be important to the user::
7+
8+
>>> ap = aritprog_gen(1, .5, 3)
9+
>>> list(ap)
10+
[1, 1.5, 2.0, 2.5]
11+
>>> ap = aritprog_gen(0, 1/3, 1)
12+
>>> list(ap)
13+
[0, 0.3333333333333333, 0.6666666666666666]
14+
>>> from fractions import Fraction
15+
>>> ap = aritprog_gen(0, Fraction(1, 3), 1)
16+
>>> list(ap)
17+
[0, Fraction(1, 3), Fraction(2, 3)]
18+
>>> from decimal import Decimal
19+
>>> ap = aritprog_gen(0, Decimal('.1'), .3)
20+
>>> list(ap)
21+
[0, Decimal('0.1'), Decimal('0.2')]
22+
23+
24+
"""
25+
26+
# BEGIN ALMOST_ARITPROG_ITERTOOLS
27+
import itertools
28+
29+
30+
def aritprog_gen(begin, step, end=None):
31+
ap_gen = itertools.count(begin, step)
32+
if end is not None:
33+
ap_gen = itertools.takewhile(lambda n: n < end, ap_gen)
34+
return ap_gen
35+
# END ALMOST_ARITPROG_ITERTOOLS

iterables/aritprog.rst

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
===========================================
2+
Tests for arithmetic progression generators
3+
===========================================
4+
5+
Tests with built-in numeric types::
6+
7+
>>> ap = aritprog_gen(1, .5, 3)
8+
>>> list(ap)
9+
[1.0, 1.5, 2.0, 2.5]
10+
>>> ap = aritprog_gen(0, 1/3, 1)
11+
>>> list(ap)
12+
[0.0, 0.3333333333333333, 0.6666666666666666]
13+
14+
15+
Tests with standard library numeric types::
16+
17+
>>> from fractions import Fraction
18+
>>> ap = aritprog_gen(0, Fraction(1, 3), 1)
19+
>>> list(ap)
20+
[Fraction(0, 1), Fraction(1, 3), Fraction(2, 3)]
21+
>>> from decimal import Decimal
22+
>>> ap = aritprog_gen(0, Decimal('.1'), .3)
23+
>>> list(ap)
24+
[Decimal('0'), Decimal('0.1'), Decimal('0.2')]
25+
26+
27+
Test producing an empty series::
28+
29+
>>> ap = aritprog_gen(0, 1, 0)
30+
>>> list(ap)
31+
[]

iterables/aritprog_float_error.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""
2+
Demonstrate difference between Arithmetic Progression calculated
3+
as a series of increments accumulating errors versus one addition
4+
and one multiplication.
5+
"""
6+
7+
from fractions import Fraction
8+
from aritprog_v0 import ArithmeticProgression as APv0
9+
from aritprog_v1 import ArithmeticProgression as APv1
10+
11+
if __name__ == '__main__':
12+
13+
ap0 = iter(APv0(1, .1))
14+
ap1 = iter(APv1(1, .1))
15+
ap_frac = iter(APv1(Fraction(1, 1), Fraction(1, 10)))
16+
epsilon = 10**-10
17+
iteration = 0
18+
delta = next(ap0) - next(ap1)
19+
frac = next(ap_frac)
20+
while abs(delta) <= epsilon:
21+
delta = next(ap0) - next(ap1)
22+
frac = next(ap_frac)
23+
iteration +=1
24+
25+
print('iteration: {}\tfraction: {}\tepsilon: {}\tdelta: {}'.
26+
format(iteration, frac, epsilon, delta))

iterables/aritprog_runner.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import doctest
2+
import importlib
3+
import glob
4+
5+
6+
TARGET_GLOB = 'aritprog*.py'
7+
TEST_FILE = 'aritprog.rst'
8+
TEST_MSG = '{0:16} {1.attempted:2} tests, {1.failed:2} failed - {2}'
9+
10+
11+
def main(argv):
12+
verbose = '-v' in argv
13+
for module_file_name in sorted(glob.glob(TARGET_GLOB)):
14+
module_name = module_file_name.replace('.py', '')
15+
module = importlib.import_module(module_name)
16+
gen_factory = getattr(module, 'ArithmeticProgression', None)
17+
if gen_factory is None:
18+
gen_factory = getattr(module, 'aritprog_gen', None)
19+
if gen_factory is None:
20+
continue
21+
22+
test(gen_factory, verbose)
23+
24+
25+
def test(gen_factory, verbose=False):
26+
res = doctest.testfile(
27+
TEST_FILE,
28+
globs={'aritprog_gen': gen_factory},
29+
verbose=verbose,
30+
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
31+
tag = 'FAIL' if res.failed else 'OK'
32+
print(TEST_MSG.format(gen_factory.__module__, res, tag))
33+
34+
35+
if __name__ == '__main__':
36+
import sys
37+
main(sys.argv)

iterables/aritprog_v0.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""
2+
Arithmetic progression class
3+
4+
>>> ap = ArithmeticProgression(1, .5, 3)
5+
>>> list(ap)
6+
[1.0, 1.5, 2.0, 2.5]
7+
8+
9+
"""
10+
11+
12+
class ArithmeticProgression:
13+
14+
def __init__(self, begin, step, end=None):
15+
self.begin = begin
16+
self.step = step
17+
self.end = end # None -> "infinite" series
18+
19+
def __iter__(self):
20+
result = type(self.begin + self.step)(self.begin)
21+
forever = self.end is None
22+
while forever or result < self.end:
23+
yield result
24+
result += self.step

iterables/aritprog_v1.py

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,44 @@
11
"""
22
Arithmetic progression class
33
4+
# BEGIN ARITPROG_CLASS_DEMO
5+
6+
>>> ap = ArithmeticProgression(0, 1, 3)
7+
>>> list(ap)
8+
[0, 1, 2]
49
>>> ap = ArithmeticProgression(1, .5, 3)
510
>>> list(ap)
611
[1.0, 1.5, 2.0, 2.5]
12+
>>> ap = ArithmeticProgression(0, 1/3, 1)
13+
>>> list(ap)
14+
[0.0, 0.3333333333333333, 0.6666666666666666]
15+
>>> from fractions import Fraction
16+
>>> ap = ArithmeticProgression(0, Fraction(1, 3), 1)
17+
>>> list(ap)
18+
[Fraction(0, 1), Fraction(1, 3), Fraction(2, 3)]
19+
>>> from decimal import Decimal
20+
>>> ap = ArithmeticProgression(0, Decimal('.1'), .3)
21+
>>> list(ap)
22+
[Decimal('0.0'), Decimal('0.1'), Decimal('0.2')]
723
8-
24+
# END ARITPROG_CLASS_DEMO
925
"""
1026

11-
import array
12-
from collections import abc
1327

28+
# BEGIN ARITPROG_CLASS
1429
class ArithmeticProgression:
1530

16-
def __init__(self, begin, step, end):
31+
def __init__(self, begin, step, end=None): # <1>
1732
self.begin = begin
1833
self.step = step
19-
self.end = end
20-
self._build()
21-
22-
def _build(self):
23-
self._numbers = array.array('d')
24-
n = self.begin
25-
while n < self.end:
26-
self._numbers.append(n)
27-
n += self.step
34+
self.end = end # None -> "infinite" series
2835

2936
def __iter__(self):
30-
return ArithmeticProgressionIterator(self._numbers)
31-
32-
33-
class ArithmeticProgressionIterator(abc.Iterator):
34-
35-
def __init__(self, series):
36-
self._series = series
37-
self._index = 0
38-
39-
def __next__(self):
40-
if self._index < len(self._series):
41-
item = self._series[self._index]
42-
self._index += 1
43-
return item
44-
else:
45-
raise StopIteration
46-
47-
48-
37+
result = type(self.begin + self.step)(self.begin) # <2>
38+
forever = self.end is None # <3>
39+
index = 0
40+
while forever or result < self.end: # <4>
41+
yield result # <5>
42+
index += 1
43+
result = self.begin + self.step * index # <6>
44+
# END ARITPROG_CLASS

iterables/aritprog_v2.py

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,31 @@
11
"""
2-
Arithmetic progression class
2+
Arithmetic progression generator function::
33
4-
>>> ap = ArithmeticProgression(1, .5, 3)
4+
>>> ap = aritprog_gen(1, .5, 3)
55
>>> list(ap)
66
[1.0, 1.5, 2.0, 2.5]
7-
7+
>>> ap = aritprog_gen(0, 1/3, 1)
8+
>>> list(ap)
9+
[0.0, 0.3333333333333333, 0.6666666666666666]
10+
>>> from fractions import Fraction
11+
>>> ap = aritprog_gen(0, Fraction(1, 3), 1)
12+
>>> list(ap)
13+
[Fraction(0, 1), Fraction(1, 3), Fraction(2, 3)]
14+
>>> from decimal import Decimal
15+
>>> ap = aritprog_gen(0, Decimal('.1'), .3)
16+
>>> list(ap)
17+
[Decimal('0.0'), Decimal('0.1'), Decimal('0.2')]
818
919
"""
1020

11-
import array
12-
from collections import abc
13-
14-
class ArithmeticProgression:
15-
16-
def __init__(self, begin, step, end):
17-
self.begin = begin
18-
self.step = step
19-
self.end = end
20-
self._build()
21-
22-
def _build(self):
23-
self._numbers = array.array('d')
24-
n = self.begin
25-
while n < self.end:
26-
self._numbers.append(n)
27-
n += self.step
2821

29-
def __iter__(self):
30-
for item in self._numbers:
31-
yield item
32-
return StopIteration
22+
# BEGIN ARITPROG_GENFUNC
23+
def aritprog_gen(begin, step, end=None):
24+
result = type(begin + step)(begin)
25+
forever = end is None
26+
index = 0
27+
while forever or result < end:
28+
yield result
29+
index += 1
30+
result = begin + step * index
31+
# END ARITPROG_GENFUNC

iterables/aritprog_v3.py

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,11 @@
1-
"""
2-
Arithmetic progression class
1+
# BEGIN ARITPROG_ITERTOOLS
2+
import itertools
33

4-
>>> ap = ArithmeticProgression(1, .5, 3)
5-
>>> list(ap)
6-
[1.0, 1.5, 2.0, 2.5]
74

8-
9-
"""
10-
11-
import array
12-
from collections import abc
13-
14-
class ArithmeticProgression:
15-
16-
def __init__(self, begin, step, end=None):
17-
self.begin = float(begin)
18-
self.step = float(step)
19-
self.end = end # None -> "infinite" series
20-
21-
def __iter__(self):
22-
result = self.begin
23-
forever = self.end is None
24-
while forever or result < self.end:
25-
yield result
26-
result += self.step
27-
raise StopIteration
5+
def aritprog_gen(begin, step, end=None):
6+
first = type(begin + step)(begin)
7+
ap_gen = itertools.count(first, step)
8+
if end is not None:
9+
ap_gen = itertools.takewhile(lambda n: n < end, ap_gen)
10+
return ap_gen
11+
# END ARITPROG_ITERTOOLS

iterables/aritprog_v4.py

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,14 @@
1-
"""
2-
Arithmetic progression class
3-
4-
>>> ap = ArithmeticProgression(1, .5, 3)
5-
>>> list(ap)
6-
[1.0, 1.5, 2.0, 2.5]
7-
8-
9-
"""
10-
11-
import array
12-
from collections import abc
13-
14-
class ArithmeticProgression:
15-
16-
def __init__(self, begin, step, end=None):
17-
self.begin = begin
18-
self.step = step
19-
self.end = end # None -> "infinite" series
20-
21-
def __iter__(self):
22-
result = type(self.step)(self.begin)
23-
forever = self.end is None
24-
index = 0
25-
while forever or result < self.end:
26-
yield result
27-
index += 1
28-
result = self.begin + self.step * index
29-
raise StopIteration
1+
# BEGIN ARITPROG_ITERTOOLS
2+
import itertools
3+
4+
5+
def aritprog_gen(begin, step, end=None):
6+
if end is not None and begin >= end:
7+
return
8+
yield type(begin + step)(begin)
9+
tail_gen = itertools.count(begin+step, step)
10+
if end is not None:
11+
tail_gen = itertools.takewhile(lambda n: n < end, tail_gen)
12+
for x in tail_gen:
13+
yield x
14+
# END ARITPROG_ITERTOOLS

0 commit comments

Comments
 (0)