Skip to content

Commit d977823

Browse files
committed
-
1 parent 430dd84 commit d977823

File tree

24 files changed

+2749
-39
lines changed

24 files changed

+2749
-39
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import math
2+
from layout_rabbit import shy_cute_iter_tools
3+
from python_toolbox import cute_testing
4+
from python_toolbox.math_tools import binomial # Making it easy to find
5+
6+
from .chain_space import ChainSpace
7+
from .product_space import ProductSpace
8+
from .map_space import MapSpace
9+
from .selection_space import SelectionSpace
10+
from .perm_space import PermSpace, infinite_pure_perm_space
11+
from .comb_space import CombSpace
12+
from .perm import Perm
13+
from .comb import Comb
14+
15+
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import collections
2+
import types
3+
import sys
4+
import math
5+
import numbers
6+
7+
from python_toolbox import misc_tools
8+
from python_toolbox import binary_search
9+
from python_toolbox import dict_tools
10+
from python_toolbox import nifty_collections
11+
from python_toolbox import caching
12+
13+
from layout_rabbit import shy_math_tools
14+
from layout_rabbit import shy_sequence_tools
15+
from layout_rabbit import shy_cute_iter_tools
16+
from layout_rabbit import shy_nifty_collections
17+
18+
from . import misc
19+
from layout_rabbit import shy_misc_tools
20+
21+
infinity = float('inf')
22+
23+
24+
25+
class ChainSpace(shy_sequence_tools.CuteSequenceMixin, collections.Sequence):
26+
'''
27+
A space of sequences chained together.
28+
29+
This is similar to `itertools.chain`, except that items can be fetched by
30+
index number rather than just iteration.
31+
'''
32+
def __init__(self, sequences):
33+
34+
self.sequences = nifty_collections.LazyTuple(
35+
(shy_sequence_tools.ensure_iterable_is_immutable_sequence(
36+
sequence, default_type=nifty_collections.LazyTuple)
37+
for sequence in sequences)
38+
)
39+
40+
41+
@caching.CachedProperty
42+
@nifty_collections.LazyTuple.factory()
43+
def accumulated_lengths(self):
44+
'''
45+
A sequence of the accumulated length as every sequence is added.
46+
47+
For example, if this chain space has sequences with lengths of 10, 100
48+
and 1000, this would be `[0, 10, 110, 1110]`.
49+
'''
50+
total = 0
51+
yield 0
52+
for sequence in self.sequences:
53+
total += shy_sequence_tools.get_length(sequence)
54+
yield total
55+
56+
57+
length = caching.CachedProperty(lambda self: self.accumulated_lengths[-1])
58+
59+
60+
def __repr__(self):
61+
return '<%s: %s>' % (
62+
type(self).__name__,
63+
'+'.join(str(len(sequence)) for sequence in sequences),
64+
)
65+
66+
def __getitem__(self, i):
67+
if isinstance(i, slice):
68+
raise NotImplementedError
69+
assert isinstance(i, int)
70+
sequence_index = binary_search.binary_search_by_index(
71+
self.accumulated_lengths, lambda x: x,
72+
i, rounding=binary_search.LOW_IF_BOTH
73+
)
74+
if sequence_index is None:
75+
raise IndexError
76+
sequence_start = self.accumulated_lengths[sequence_index]
77+
return self.sequences[sequence_index][i - sequence_start]
78+
79+
80+
def __iter__(self):
81+
for sequence in self.sequences:
82+
# yield from sequence Commenting for fucking Pypy
83+
for i in sequence: yield i
84+
85+
_reduced = property(lambda self: (type(self), self.sequences))
86+
87+
__eq__ = lambda self, other: (isinstance(other, ChainSpace) and
88+
self._reduced == other._reduced)
89+
90+
def __contains__(self, item):
91+
return any(item in sequence for sequence in self.sequences
92+
if (not isinstance(sequence, str) or isinstance(item, str)))
93+
94+
def index(self, item):
95+
for sequence, accumulated_length in zip(self.sequences,
96+
self.accumulated_lengths):
97+
try:
98+
return sequence.index(item) + accumulated_length
99+
except IndexError:
100+
pass
101+
else:
102+
raise IndexError
103+
104+
def __bool__(self):
105+
try:
106+
next(iter(self))
107+
except StopIteration:
108+
return False
109+
else:
110+
return True
111+
112+
113+
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
from layout_rabbit import shy_math_tools
2+
from python_toolbox import caching
3+
4+
from .perm import Perm
5+
from .comb_space import CombSpace
6+
7+
8+
class Comb(Perm):
9+
def __init__(self, number_or_perm_sequence, perm_space):
10+
assert isinstance(perm_space, CombSpace)
11+
Perm.__init__(self, number_or_perm_sequence=number_or_perm_sequence,
12+
perm_space=perm_space)
13+
14+
@caching.CachedProperty
15+
def _perm_sequence(self):
16+
assert (0 <= self.number <
17+
self.just_dapplied_rapplied_perm_space.length)
18+
wip_number = (self.just_dapplied_rapplied_perm_space.length - 1 -
19+
self.number)
20+
wip_perm_sequence = []
21+
for i in range(self.just_dapplied_rapplied_perm_space.n_elements,
22+
0, -1):
23+
for j in range(self.just_dapplied_rapplied_perm_space.
24+
sequence_length, i - 2, -1):
25+
candidate = shy_math_tools.binomial(j, i)
26+
if candidate <= wip_number:
27+
wip_perm_sequence.append(
28+
self.just_dapplied_rapplied_perm_space.sequence[-(j+1)]
29+
)
30+
wip_number -= candidate
31+
break
32+
else:
33+
raise RuntimeError
34+
result = tuple(wip_perm_sequence)
35+
assert len(result) == self.length
36+
return result
37+
38+
39+
@caching.CachedProperty
40+
def number(self):
41+
'''
42+
43+
The number here is not necessarily the number with which the perm was
44+
fetched from the perm space; it's the number of the perm in a perm
45+
space that is neither degreed, fixed or sliced.
46+
'''
47+
if self.is_rapplied or self.is_dapplied:
48+
return self.unrapplied.undapplied.number
49+
50+
processed_perm_sequence = tuple(
51+
self.just_dapplied_rapplied_perm_space.sequence_length - 1 -
52+
item for item in self._perm_sequence[::-1]
53+
)
54+
return self.just_dapplied_rapplied_perm_space.length - 1 - sum(
55+
(shy_math_tools.binomial(item, i) for i, item in
56+
enumerate(processed_perm_sequence, start=1)),
57+
0
58+
)
59+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
3+
from .perm_space import PermSpace
4+
5+
class CombSpace(PermSpace):
6+
'''
7+
A space of combinations.
8+
9+
10+
11+
Every item in a `CombSpace` is a `Comb`.
12+
'''
13+
def __init__(self, iterable_or_length, n_elements,
14+
slice_=None, _domain_for_checking=None,
15+
_degrees_for_checking=None):
16+
PermSpace.__init__(
17+
self, iterable_or_length=iterable_or_length, n_elements=n_elements,
18+
is_combination=True, slice_=slice_,
19+
domain=_domain_for_checking, degrees=_degrees_for_checking
20+
)
21+
22+
23+
def __repr__(self):
24+
sequence_repr = repr(self.sequence)
25+
if len(sequence_repr) > 40:
26+
sequence_repr = \
27+
''.join((sequence_repr[:35], ' ... ', sequence_repr[-1]))
28+
29+
return '<%s: %s%s%s>%s' % (
30+
type(self).__name__,
31+
sequence_repr,
32+
(', n_elements=%s' % (self.n_elements,)) if self.is_partial
33+
else '',
34+
(', fixed_map=%s' % (self.fixed_map,)) if self.is_fixed else '',
35+
('[%s:%s]' % (self.slice_.start, self.slice_.stop)) if
36+
self.is_sliced else ''
37+
)
38+
39+
40+
41+
from .comb import Comb
42+
43+
# Must set this after-the-fact because of import loop:
44+
CombSpace.perm_type = Comb
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import collections
2+
import types
3+
import sys
4+
import math
5+
import numbers
6+
7+
from python_toolbox import misc_tools
8+
from python_toolbox import binary_search
9+
from python_toolbox import dict_tools
10+
from python_toolbox import nifty_collections
11+
from python_toolbox import caching
12+
13+
from layout_rabbit import shy_math_tools
14+
from layout_rabbit import shy_sequence_tools
15+
from layout_rabbit import shy_cute_iter_tools
16+
from layout_rabbit import shy_nifty_collections
17+
from layout_rabbit import shy_misc_tools
18+
19+
from . import misc
20+
21+
infinity = float('inf')
22+
23+
24+
25+
class MapSpace(shy_sequence_tools.CuteSequenceMixin, collections.Sequence):
26+
def __init__(self, function, sequence):
27+
28+
self.function = function
29+
self.sequence = shy_sequence_tools. \
30+
ensure_iterable_is_immutable_sequence(
31+
sequence,
32+
default_type=nifty_collections.LazyTuple
33+
)
34+
35+
36+
length = caching.CachedProperty(
37+
lambda self: shy_sequence_tools.get_length(self.sequence)
38+
)
39+
40+
def __repr__(self):
41+
return '%s(%s, %s)' % (
42+
type(self).__name__,
43+
self.function,
44+
self.sequence
45+
)
46+
47+
def __getitem__(self, i):
48+
if isinstance(i, slice):
49+
return type(self)(self.function, self.sequence[i])
50+
assert isinstance(i, int)
51+
return self.function(self.sequence[i]) # Propagating `IndexError`.
52+
53+
54+
def __iter__(self):
55+
for item in self.sequence:
56+
yield self.function(item)
57+
58+
_reduced = property(
59+
lambda self: (type(self), self.function, self.sequence)
60+
)
61+
62+
__eq__ = lambda self, other: (isinstance(other, MapSpace) and
63+
self._reduced == other._reduced)
64+
65+
__bool__ = lambda self: bool(self.sequence)
66+
67+
68+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import collections
2+
import types
3+
import sys
4+
import math
5+
import numbers
6+
7+
from python_toolbox import dict_tools
8+
from python_toolbox import nifty_collections
9+
from python_toolbox import caching
10+
11+
from layout_rabbit import shy_math_tools
12+
from layout_rabbit import shy_sequence_tools
13+
from layout_rabbit import shy_cute_iter_tools
14+
15+
infinity = float('inf')
16+
17+
18+
19+
20+
def get_short_factorial_string(number, minus_one=False):
21+
assert number >= 0 and \
22+
isinstance(number, shy_math_tools.PossiblyInfiniteIntegral)
23+
if number == infinity:
24+
return "float('inf')"
25+
elif number <= 10:
26+
return str(math.factorial(number) - int(minus_one))
27+
else:
28+
assert number > 10
29+
return '%s!%s' % (number, ' - 1' if minus_one else '')
30+
31+
32+

0 commit comments

Comments
 (0)