Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/combinat/cartesian_product.py
4058 views
1
r"""
2
Cartesian Products
3
"""
4
#*****************************************************************************
5
# Copyright (C) 2007 Mike Hansen <[email protected]>,
6
#
7
# Distributed under the terms of the GNU General Public License (GPL)
8
#
9
# This code is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
# General Public License for more details.
13
#
14
# The full text of the GPL is available at:
15
#
16
# http://www.gnu.org/licenses/
17
#*****************************************************************************
18
19
import sage.misc.prandom as rnd
20
import __builtin__
21
from combinat import CombinatorialClass
22
from sage.rings.integer import Integer
23
24
def CartesianProduct(*iters):
25
"""
26
Returns the combinatorial class of the Cartesian product of
27
\*iters.
28
29
EXAMPLES::
30
31
sage: cp = CartesianProduct([1,2], [3,4]); cp
32
Cartesian product of [1, 2], [3, 4]
33
sage: cp.list()
34
[[1, 3], [1, 4], [2, 3], [2, 4]]
35
36
Note that if you have a generator-type object that is returned by a
37
function, then you should use IterableFunctionCall class defined in
38
sage.combinat.misc.
39
40
::
41
42
sage: def a(n): yield 1*n; yield 2*n
43
sage: def b(): yield 'a'; yield 'b'
44
sage: CartesianProduct(a(3), b()).list()
45
[[3, 'a'], [3, 'b']]
46
sage: from sage.combinat.misc import IterableFunctionCall
47
sage: CartesianProduct(IterableFunctionCall(a, 3), IterableFunctionCall(b)).list()
48
[[3, 'a'], [3, 'b'], [6, 'a'], [6, 'b']]
49
50
See the documentation for IterableFunctionCall for more information.
51
"""
52
return CartesianProduct_iters(*iters)
53
54
class CartesianProduct_iters(CombinatorialClass):
55
def __init__(self, *iters):
56
"""
57
TESTS::
58
59
sage: import sage.combinat.cartesian_product as cartesian_product
60
sage: cp = cartesian_product.CartesianProduct_iters([1,2],[3,4]); cp
61
Cartesian product of [1, 2], [3, 4]
62
sage: loads(dumps(cp)) == cp
63
True
64
"""
65
self.iters = iters
66
67
def __contains__(self, x):
68
"""
69
EXAMPLES::
70
71
sage: cp = CartesianProduct([1,2],[3,4])
72
sage: [1,3] in cp
73
True
74
sage: [1,2] in cp
75
False
76
sage: [1, 3, 1] in cp
77
False
78
"""
79
try:
80
return len(x) == len(self.iters) and all(x[i] in self.iters[i] for i in range(len(self.iters)))
81
except (TypeError, IndexError):
82
return False
83
84
def __repr__(self):
85
"""
86
EXAMPLES::
87
88
sage: CartesianProduct(range(2), range(3))
89
Cartesian product of [0, 1], [0, 1, 2]
90
"""
91
return "Cartesian product of " + ", ".join(map(str, self.iters))
92
93
def cardinality(self):
94
"""
95
Returns the number of elements in the cartesian product of
96
everything in \*iters.
97
98
EXAMPLES::
99
100
sage: CartesianProduct(range(2), range(3)).cardinality()
101
6
102
sage: CartesianProduct(range(2), xrange(3)).cardinality()
103
6
104
sage: CartesianProduct(range(2), xrange(3), xrange(4)).cardinality()
105
24
106
"""
107
total = 1
108
for it in self.iters:
109
try:
110
total *= len(it) # may not work when it is a CClass.
111
except AttributeError:
112
total *= it.cardinality()
113
return Integer(total)
114
115
116
def list(self):
117
"""
118
Returns
119
120
EXAMPLES::
121
122
sage: CartesianProduct(range(3), range(3)).list()
123
[[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]
124
sage: CartesianProduct('dog', 'cat').list()
125
[['d', 'c'],
126
['d', 'a'],
127
['d', 't'],
128
['o', 'c'],
129
['o', 'a'],
130
['o', 't'],
131
['g', 'c'],
132
['g', 'a'],
133
['g', 't']]
134
"""
135
return [e for e in self]
136
137
138
def __iter__(self):
139
"""
140
An iterator for the elements in the cartesian product of the
141
iterables \*iters.
142
143
From Recipe 19.9 in the Python Cookbook by Alex Martelli and David
144
Ascher.
145
146
EXAMPLES::
147
148
sage: [e for e in CartesianProduct(range(3), range(3))]
149
[[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]
150
sage: [e for e in CartesianProduct('dog', 'cat')]
151
[['d', 'c'],
152
['d', 'a'],
153
['d', 't'],
154
['o', 'c'],
155
['o', 'a'],
156
['o', 't'],
157
['g', 'c'],
158
['g', 'a'],
159
['g', 't']]
160
"""
161
162
# visualize an odometer, with "wheels" displaying "digits"...:
163
wheels = map(iter, self.iters)
164
digits = [it.next() for it in wheels]
165
while True:
166
yield __builtin__.list(digits)
167
for i in range(len(digits)-1, -1, -1):
168
try:
169
digits[i] = wheels[i].next()
170
break
171
except StopIteration:
172
wheels[i] = iter(self.iters[i])
173
digits[i] = wheels[i].next()
174
else:
175
break
176
177
def random_element(self):
178
"""
179
Returns a random element from the cartesian product of \*iters.
180
181
EXAMPLES::
182
183
sage: CartesianProduct('dog', 'cat').random_element()
184
['d', 'a']
185
"""
186
return list(map(rnd.choice, self.iters))
187
188