| 1 | r""" |
|---|
| 2 | Set Partitions |
|---|
| 3 | |
|---|
| 4 | A set partition s of a set set is a partition of set, into subsets called parts and represented as a set of sets. By extension, a set partition of a nonnegative integer n is the set partition of the integers from 1 to n. The number of set partitions of n is called the n-th Bell number. |
|---|
| 5 | |
|---|
| 6 | There is a natural integer partition associated with a set partition, that is the non-decreasing sequence of sizes of all its parts. |
|---|
| 7 | |
|---|
| 8 | There is a classical lattice associated with all set partitions of n. The infimum of two set partitions is the set partition obtained by intersecting all the parts of both set partitions. The supremum is obtained by transitive closure of the relation i related to j iff they are in the same part in at least one of the set partitions. |
|---|
| 9 | |
|---|
| 10 | EXAMPLES: |
|---|
| 11 | There are 5 set partitions of the set {1,2,3}. |
|---|
| 12 | |
|---|
| 13 | sage: SetPartitions(3).count() |
|---|
| 14 | 5 |
|---|
| 15 | |
|---|
| 16 | Here is the list of them: |
|---|
| 17 | |
|---|
| 18 | sage: SetPartitions(3).list() #random due to the sets |
|---|
| 19 | [{{1, 2, 3}}, {{2, 3}, {1}}, {{1, 3}, {2}}, {{1, 2}, {3}}, {{2}, {3}, {1}}] |
|---|
| 20 | |
|---|
| 21 | There are 6 set partitions of {1,2,3,4} whose underlying partition |
|---|
| 22 | is [2, 1, 1]: |
|---|
| 23 | |
|---|
| 24 | sage: SetPartitions(4, [2,1,1]).list() #random due to the sets |
|---|
| 25 | [{{3, 4}, {2}, {1}}, |
|---|
| 26 | {{2, 4}, {3}, {1}}, |
|---|
| 27 | {{4}, {2, 3}, {1}}, |
|---|
| 28 | {{1, 4}, {2}, {3}}, |
|---|
| 29 | {{1, 3}, {4}, {2}}, |
|---|
| 30 | {{1, 2}, {4}, {3}}] |
|---|
| 31 | |
|---|
| 32 | AUTHORS: |
|---|
| 33 | --Mike Hansen |
|---|
| 34 | --MuPAD-Combinat developers (for algorithms and design inspiration). |
|---|
| 35 | |
|---|
| 36 | """ |
|---|
| 37 | #***************************************************************************** |
|---|
| 38 | # Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>, |
|---|
| 39 | # |
|---|
| 40 | # Distributed under the terms of the GNU General Public License (GPL) |
|---|
| 41 | # |
|---|
| 42 | # This code is distributed in the hope that it will be useful, |
|---|
| 43 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 44 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 45 | # General Public License for more details. |
|---|
| 46 | # |
|---|
| 47 | # The full text of the GPL is available at: |
|---|
| 48 | # |
|---|
| 49 | # http://www.gnu.org/licenses/ |
|---|
| 50 | #***************************************************************************** |
|---|
| 51 | |
|---|
| 52 | from sage.sets.set import Set, EnumeratedSet, is_Set |
|---|
| 53 | import sage.combinat.partition as partition |
|---|
| 54 | import sage.rings.integer |
|---|
| 55 | import __builtin__ |
|---|
| 56 | import itertools |
|---|
| 57 | from cartesian_product import CartesianProduct |
|---|
| 58 | import sage.combinat.subset as subset |
|---|
| 59 | import sage.combinat.set_partition_ordered as set_partition_ordered |
|---|
| 60 | import copy |
|---|
| 61 | from combinat import CombinatorialClass, CombinatorialObject, bell_number, stirling_number2 |
|---|
| 62 | from subword import Subwords |
|---|
| 63 | |
|---|
| 64 | |
|---|
| 65 | def SetPartitions(s, part=None): |
|---|
| 66 | """ |
|---|
| 67 | An {\it unordered partition} of a set $S$ is a set of pairwise disjoint |
|---|
| 68 | nonempty subsets with union $S$ and is represented by a sorted |
|---|
| 69 | list of such subsets. |
|---|
| 70 | |
|---|
| 71 | partitions_set returns the set of all unordered partitions of the |
|---|
| 72 | list $S$ of increasing positive integers into k pairwise disjoint |
|---|
| 73 | nonempty sets. If k is omitted then all partitions are returned. |
|---|
| 74 | |
|---|
| 75 | The Bell number $B_n$, named in honor of Eric Temple Bell, is |
|---|
| 76 | the number of different partitions of a set with n elements. |
|---|
| 77 | |
|---|
| 78 | EXAMPLES: |
|---|
| 79 | sage: S = [1,2,3,4] |
|---|
| 80 | sage: SetPartitions(S,2) |
|---|
| 81 | Set partitions of [1, 2, 3, 4] with 2 parts |
|---|
| 82 | |
|---|
| 83 | |
|---|
| 84 | REFERENCES: |
|---|
| 85 | http://en.wikipedia.org/wiki/Partition_of_a_set |
|---|
| 86 | |
|---|
| 87 | """ |
|---|
| 88 | if isinstance(s, (int, sage.rings.integer.Integer)): |
|---|
| 89 | set = range(1, s+1) |
|---|
| 90 | elif isinstance(s, str): |
|---|
| 91 | set = [x for x in s] |
|---|
| 92 | else: |
|---|
| 93 | set = s |
|---|
| 94 | |
|---|
| 95 | if part is not None: |
|---|
| 96 | if isinstance(part, (int, sage.rings.integer.Integer)): |
|---|
| 97 | if len(set) < part: |
|---|
| 98 | raise ValueError, "part must be <= len(set)" |
|---|
| 99 | else: |
|---|
| 100 | return SetPartitions_setn(set,part) |
|---|
| 101 | else: |
|---|
| 102 | if part not in partition.Partitions(len(set)): |
|---|
| 103 | raise ValueError, "part must be a partition of %s"%len(set) |
|---|
| 104 | else: |
|---|
| 105 | return SetPartitions_setparts(set, [partition.Partition(part)]) |
|---|
| 106 | else: |
|---|
| 107 | return SetPartitions_set(set) |
|---|
| 108 | |
|---|
| 109 | |
|---|
| 110 | |
|---|
| 111 | class SetPartitions_setparts(CombinatorialClass): |
|---|
| 112 | def __init__(self, set, parts): |
|---|
| 113 | """ |
|---|
| 114 | TESTS: |
|---|
| 115 | sage: S = SetPartitions(4, [2,2]) |
|---|
| 116 | sage: S == loads(dumps(S)) |
|---|
| 117 | True |
|---|
| 118 | """ |
|---|
| 119 | self.set = set |
|---|
| 120 | self.parts = parts |
|---|
| 121 | |
|---|
| 122 | def __repr__(self): |
|---|
| 123 | """ |
|---|
| 124 | TESTS: |
|---|
| 125 | sage: repr(SetPartitions(4, [2,2])) |
|---|
| 126 | 'Set partitions of [1, 2, 3, 4] with sizes in [[2, 2]]' |
|---|
| 127 | """ |
|---|
| 128 | return "Set partitions of %s with sizes in %s"%(self.set, self.parts) |
|---|
| 129 | |
|---|
| 130 | def __contains__(self, x): |
|---|
| 131 | """ |
|---|
| 132 | TESTS: |
|---|
| 133 | sage: S = SetPartitions(4, [2,2]) |
|---|
| 134 | sage: all([sp in S for sp in S]) |
|---|
| 135 | True |
|---|
| 136 | """ |
|---|
| 137 | #x must be a set |
|---|
| 138 | if not is_Set(x): |
|---|
| 139 | return False |
|---|
| 140 | |
|---|
| 141 | #Make sure that the number of elements match up |
|---|
| 142 | if sum(map(len, x)) != len(self.set): |
|---|
| 143 | return False |
|---|
| 144 | |
|---|
| 145 | #Check to make sure each element of x |
|---|
| 146 | #is a set |
|---|
| 147 | u = Set([]) |
|---|
| 148 | for s in x: |
|---|
| 149 | if not is_Set(s): |
|---|
| 150 | return False |
|---|
| 151 | u = u.union(s) |
|---|
| 152 | |
|---|
| 153 | #Make sure that the union of all the |
|---|
| 154 | #sets is the original set |
|---|
| 155 | if u != Set(self.set): |
|---|
| 156 | return False |
|---|
| 157 | |
|---|
| 158 | return True |
|---|
| 159 | |
|---|
| 160 | def count(self): |
|---|
| 161 | """ |
|---|
| 162 | Returns the number of set partitions of set. This |
|---|
| 163 | number is given by the n-th Bell number where n is |
|---|
| 164 | the number of elements in the set. |
|---|
| 165 | |
|---|
| 166 | If a partition or partition length is specified, then |
|---|
| 167 | count will generate all of the set partitions. |
|---|
| 168 | |
|---|
| 169 | EXAMPLES: |
|---|
| 170 | sage: SetPartitions([1,2,3,4]).count() |
|---|
| 171 | 15 |
|---|
| 172 | sage: SetPartitions(3).count() |
|---|
| 173 | 5 |
|---|
| 174 | sage: SetPartitions(3,2).count() |
|---|
| 175 | 3 |
|---|
| 176 | sage: SetPartitions([]).count() |
|---|
| 177 | 1 |
|---|
| 178 | """ |
|---|
| 179 | return len(self.list()) |
|---|
| 180 | |
|---|
| 181 | |
|---|
| 182 | def __iterator_part(self, part): |
|---|
| 183 | set = self.set |
|---|
| 184 | |
|---|
| 185 | nonzero = [] |
|---|
| 186 | p = partition.Partition(part) |
|---|
| 187 | expo = p.to_exp() |
|---|
| 188 | |
|---|
| 189 | for i in range(len(expo)): |
|---|
| 190 | if expo[i] != 0: |
|---|
| 191 | nonzero.append([i, expo[i]]) |
|---|
| 192 | |
|---|
| 193 | taillesblocs = map(lambda x: (x[0])*(x[1]), nonzero) |
|---|
| 194 | |
|---|
| 195 | blocs = set_partition_ordered.OrderedSetPartitions(copy.copy(set), taillesblocs).list() |
|---|
| 196 | |
|---|
| 197 | for b in blocs: |
|---|
| 198 | lb = [ _listbloc(nonzero[i][0], nonzero[i][1], b[i]) for i in range(len(nonzero)) ] |
|---|
| 199 | for x in itertools.imap(lambda x: _union(x), CartesianProduct( *lb )): |
|---|
| 200 | yield x |
|---|
| 201 | |
|---|
| 202 | |
|---|
| 203 | |
|---|
| 204 | def iterator(self): |
|---|
| 205 | """ |
|---|
| 206 | An iterator for all the set partitions of the set. |
|---|
| 207 | |
|---|
| 208 | EXAMPLES: |
|---|
| 209 | sage: SetPartitions(3).list() |
|---|
| 210 | [{{1, 2, 3}}, {{2, 3}, {1}}, {{1, 3}, {2}}, {{1, 2}, {3}}, {{2}, {3}, {1}}] |
|---|
| 211 | """ |
|---|
| 212 | for p in self.parts: |
|---|
| 213 | for sp in self.__iterator_part(p): |
|---|
| 214 | yield sp |
|---|
| 215 | |
|---|
| 216 | |
|---|
| 217 | class SetPartitions_setn(SetPartitions_setparts): |
|---|
| 218 | def __init__(self, set, n): |
|---|
| 219 | """ |
|---|
| 220 | TESTS: |
|---|
| 221 | sage: S = SetPartitions(5, 3) |
|---|
| 222 | sage: S == loads(dumps(S)) |
|---|
| 223 | True |
|---|
| 224 | """ |
|---|
| 225 | self.n = n |
|---|
| 226 | SetPartitions_setparts.__init__(self, set, partition.Partitions(len(set), length=n).list()) |
|---|
| 227 | |
|---|
| 228 | def __repr__(self): |
|---|
| 229 | """ |
|---|
| 230 | TESTS: |
|---|
| 231 | sage: repr(SetPartitions(5, 3)) |
|---|
| 232 | 'Set partitions of [1, 2, 3, 4, 5] with 3 parts' |
|---|
| 233 | """ |
|---|
| 234 | return "Set partitions of %s with %s parts"%(self.set,self.n) |
|---|
| 235 | |
|---|
| 236 | def count(self): |
|---|
| 237 | """ |
|---|
| 238 | The Stirling number of the second kind is the number |
|---|
| 239 | of partitions of a set of size n into k blocks. |
|---|
| 240 | |
|---|
| 241 | EXAMPLES: |
|---|
| 242 | sage: SetPartitions(5, 3).count() |
|---|
| 243 | 25 |
|---|
| 244 | sage: stirling_number2(5,3) |
|---|
| 245 | 25 |
|---|
| 246 | """ |
|---|
| 247 | return stirling_number2(len(self.set), self.n) |
|---|
| 248 | |
|---|
| 249 | class SetPartitions_set(SetPartitions_setparts): |
|---|
| 250 | def __init__(self, set): |
|---|
| 251 | """ |
|---|
| 252 | TESTS: |
|---|
| 253 | sage: S = SetPartitions([1,2,3]) |
|---|
| 254 | sage: S == loads(dumps(S)) |
|---|
| 255 | True |
|---|
| 256 | """ |
|---|
| 257 | SetPartitions_setparts.__init__(self, set, partition.Partitions(len(set))) |
|---|
| 258 | |
|---|
| 259 | def __repr__(self): |
|---|
| 260 | """ |
|---|
| 261 | TESTS: |
|---|
| 262 | sage: repr( SetPartitions([1,2,3]) ) |
|---|
| 263 | 'Set partitions of [1, 2, 3]' |
|---|
| 264 | """ |
|---|
| 265 | return "Set partitions of %s"%(self.set) |
|---|
| 266 | |
|---|
| 267 | def count(self): |
|---|
| 268 | """ |
|---|
| 269 | EXAMPLES: |
|---|
| 270 | sage: SetPartitions(4).count() |
|---|
| 271 | 15 |
|---|
| 272 | sage: bell_number(4) |
|---|
| 273 | 15 |
|---|
| 274 | """ |
|---|
| 275 | return bell_number(len(self.set)) |
|---|
| 276 | |
|---|
| 277 | |
|---|
| 278 | |
|---|
| 279 | def _listbloc(n, nbrepets, listint=None): |
|---|
| 280 | """ |
|---|
| 281 | listbloc decomposes a set of n*nbrepets integers (the list listint) |
|---|
| 282 | in nbrepets parts. |
|---|
| 283 | |
|---|
| 284 | It is used in the algorithm to generate all set partitions. |
|---|
| 285 | |
|---|
| 286 | Not to be called by the user. |
|---|
| 287 | |
|---|
| 288 | EXAMPLES: |
|---|
| 289 | sage: sage.combinat.set_partition._listbloc(2,1) |
|---|
| 290 | [{{1, 2}}] |
|---|
| 291 | sage: l = [Set([Set([3, 4]), Set([1, 2])]), Set([Set([2, 4]), Set([1, 3])]), Set([Set([2, 3]), Set([1, 4])])] |
|---|
| 292 | sage: sage.combinat.set_partition._listbloc(2,2,[1,2,3,4]) == l |
|---|
| 293 | True |
|---|
| 294 | |
|---|
| 295 | |
|---|
| 296 | """ |
|---|
| 297 | if isinstance(listint, (int, sage.rings.integer.Integer)) or listint is None: |
|---|
| 298 | listint = Set(range(1,n+1)) |
|---|
| 299 | |
|---|
| 300 | |
|---|
| 301 | if nbrepets == 1: |
|---|
| 302 | return [Set([listint])] |
|---|
| 303 | |
|---|
| 304 | l = __builtin__.list(listint) |
|---|
| 305 | l.sort() |
|---|
| 306 | smallest = Set(l[:1]) |
|---|
| 307 | new_listint = Set(l[1:]) |
|---|
| 308 | |
|---|
| 309 | f = lambda u, v: u.union(_set_union([smallest,v])) |
|---|
| 310 | res = [] |
|---|
| 311 | |
|---|
| 312 | for ssens in subset.Subsets(new_listint, n-1): |
|---|
| 313 | for z in _listbloc(n, nbrepets-1, new_listint-ssens): |
|---|
| 314 | res.append(f(z,ssens)) |
|---|
| 315 | |
|---|
| 316 | return res |
|---|
| 317 | |
|---|
| 318 | def _union(s): |
|---|
| 319 | """ |
|---|
| 320 | TESTS: |
|---|
| 321 | sage: s = Set([ Set([1,2]), Set([3,4]) ]) |
|---|
| 322 | sage: sage.combinat.set_partition._union(s) |
|---|
| 323 | {1, 2, 3, 4} |
|---|
| 324 | """ |
|---|
| 325 | result = Set([]) |
|---|
| 326 | for ss in s: |
|---|
| 327 | result = result.union(ss) |
|---|
| 328 | return result |
|---|
| 329 | |
|---|
| 330 | def _set_union(s): |
|---|
| 331 | """ |
|---|
| 332 | TESTS: |
|---|
| 333 | sage: s = Set([ Set([1,2]), Set([3,4]) ]) |
|---|
| 334 | sage: sage.combinat.set_partition._set_union(s) |
|---|
| 335 | {{1, 2, 3, 4}} |
|---|
| 336 | """ |
|---|
| 337 | result = Set([]) |
|---|
| 338 | for ss in s: |
|---|
| 339 | result = result.union(ss) |
|---|
| 340 | return EnumeratedSet([result]) |
|---|
| 341 | |
|---|
| 342 | def inf(s,t): |
|---|
| 343 | """ |
|---|
| 344 | Returns the infimum of the two set partitions s and t. |
|---|
| 345 | |
|---|
| 346 | EXAMPLES: |
|---|
| 347 | sage: sp1 = Set([Set([2,3,4]),Set([1])]) |
|---|
| 348 | sage: sp2 = Set([Set([1,3]), Set([2,4])]) |
|---|
| 349 | sage: s = Set([ Set([2,4]), Set([3]), Set([1])]) #{{2, 4}, {3}, {1}} |
|---|
| 350 | sage: sage.combinat.set_partition.inf(sp1, sp2) == s |
|---|
| 351 | True |
|---|
| 352 | |
|---|
| 353 | """ |
|---|
| 354 | temp = [ss.intersection(ts) for ss in s for ts in t] |
|---|
| 355 | temp = filter(lambda x: x != Set([]), temp) |
|---|
| 356 | return EnumeratedSet(temp) |
|---|
| 357 | |
|---|
| 358 | def sup(s,t): |
|---|
| 359 | """ |
|---|
| 360 | Returns the supremum of the two set partitions s and t. |
|---|
| 361 | |
|---|
| 362 | EXAMPLES: |
|---|
| 363 | sage: sp1 = Set([Set([2,3,4]),Set([1])]) |
|---|
| 364 | sage: sp2 = Set([Set([1,3]), Set([2,4])]) |
|---|
| 365 | sage: s = Set([ Set([1,2,3,4]) ]) |
|---|
| 366 | sage: sage.combinat.set_partition.sup(sp1, sp2) == s |
|---|
| 367 | True |
|---|
| 368 | |
|---|
| 369 | """ |
|---|
| 370 | res = s |
|---|
| 371 | for p in t: |
|---|
| 372 | inters = Set(filter(lambda x: x.intersection(p) != Set([]), __builtin__.list(res))) |
|---|
| 373 | res = res.difference(inters).union(_set_union(inters)) |
|---|
| 374 | |
|---|
| 375 | return res |
|---|
| 376 | |
|---|
| 377 | |
|---|
| 378 | def standard_form(sp): |
|---|
| 379 | """ |
|---|
| 380 | Returns the set partition as a list of lists. |
|---|
| 381 | |
|---|
| 382 | EXAMPLES: |
|---|
| 383 | sage: map(sage.combinat.set_partition.standard_form, SetPartitions(4, [2,2])) |
|---|
| 384 | [[[3, 4], [1, 2]], [[2, 4], [1, 3]], [[2, 3], [1, 4]]] |
|---|
| 385 | """ |
|---|
| 386 | |
|---|
| 387 | return [__builtin__.list(x) for x in sp] |
|---|
| 388 | |
|---|
| 389 | |
|---|
| 390 | def less(s, t): |
|---|
| 391 | """ |
|---|
| 392 | Returns True if s < t otherwise it returns False. |
|---|
| 393 | |
|---|
| 394 | EXAMPLES: |
|---|
| 395 | sage: z = SetPartitions(3).list() |
|---|
| 396 | sage: sage.combinat.set_partition.less(z[0], z[1]) |
|---|
| 397 | False |
|---|
| 398 | sage: sage.combinat.set_partition.less(z[4], z[1]) |
|---|
| 399 | True |
|---|
| 400 | sage: sage.combinat.set_partition.less(z[4], z[0]) |
|---|
| 401 | True |
|---|
| 402 | sage: sage.combinat.set_partition.less(z[3], z[0]) |
|---|
| 403 | True |
|---|
| 404 | sage: sage.combinat.set_partition.less(z[2], z[0]) |
|---|
| 405 | True |
|---|
| 406 | sage: sage.combinat.set_partition.less(z[1], z[0]) |
|---|
| 407 | True |
|---|
| 408 | sage: sage.combinat.set_partition.less(z[0], z[0]) |
|---|
| 409 | False |
|---|
| 410 | """ |
|---|
| 411 | |
|---|
| 412 | if _union(s) != _union(t): |
|---|
| 413 | raise ValueError, "cannont compare partitions of different sets" |
|---|
| 414 | |
|---|
| 415 | if s == t: |
|---|
| 416 | return False |
|---|
| 417 | |
|---|
| 418 | for p in s: |
|---|
| 419 | f = lambda z: z.intersection(p) != Set([]) |
|---|
| 420 | if len(filter(f, __builtin__.list(t)) ) != 1: |
|---|
| 421 | return False |
|---|
| 422 | |
|---|
| 423 | return True |
|---|
| 424 | |
|---|