|
25 | 25 | authors, Wolfram Research, or Cambridge University Press, their licensees, |
26 | 26 | distributors and dealers shall in no event be liable for any indirect, |
27 | 27 | incidental, or consequential damages. |
| 28 | +
|
| 29 | +And for the 0.6 version: |
| 30 | + Version 0.6 6/11/90 Beta Release |
| 31 | + Copyright (c) 1990 by Steven S. Skiena |
| 32 | +
|
28 | 33 | *) |
29 | 34 |
|
30 | 35 | BeginPackage["DiscreteMath`CombinatoricaLite`"] |
|
105 | 110 | UnrankPermutation[r_Integer, n_Integer?Positive] := |
106 | 111 | UnrankPermutation[r, Range[n]] |
107 | 112 |
|
| 113 | +Compositions::usage = "Compositions[n, k] gives a list of all compositions of integer n into k parts." |
| 114 | +Compositions[n_Integer,k_Integer] := |
| 115 | + Map[ |
| 116 | + (Map[(#[[2]]-#[[1]]-1)&, Partition[Join[{0},#,{n+k}],2,1] ])&, |
| 117 | + KSubsets[Range[n+k-1],k-1] |
| 118 | + ] |
| 119 | + |
108 | 120 | Cyclic::usage = "Cyclic is an argument to the Polya-theoretic functions ListNecklaces, NumberOfNecklace, and NecklacePolynomial, which count or enumerate distinct necklaces. Cyclic refers to the cyclic group acting on necklaces to make equivalent necklaces that can be obtained from each other by rotation."; |
109 | 121 |
|
110 | 122 | CyclicGroup::usage = "CyclicGroup[n] returns the cyclic group of permutations on n symbols."; |
| 123 | +CyclicGroup[0] := {{}} |
| 124 | +CyclicGroup[n_Integer] := Table[RotateRight[Range[n], i], {i, 0, n-1}] |
111 | 125 |
|
112 | 126 | DihedralGroupIndex::usage = "DihedralGroupIndex[n, x] returns the cycle index of the dihedral group on n symbols, expressed as a polynomial in x[1], x[2], ..., x[n]."; |
113 | 127 |
|
114 | | -NecklacePolynomial::usage = "NecklacePolynomial[n, c, Cyclic] returns a polynomial in the colors in c whose coefficients represent numbers of ways of coloring an n-bead necklace with colors chosen from c, assuming that two colorings are equivalent if one can be obtained from the other by a rotation. NecklacePolynomial[n, c, Dihedral] is different in that it considers two colorings equivalent if one can be obtained from the other by a rotation or a flip or both."; |
115 | | - |
116 | | -OrbitInventory::usage = "OrbitInventory[ci, x, w] returns the value of the cycle index ci when each formal variable x[i] is replaced by w. OrbitInventory[ci, x, weights] returns the inventory of orbits induced on a set of functions by the action of a group with cycle index ci. It is assumed that each element in the range of the functions is assigned a weight in list weights."; |
| 128 | +DihedralGroupIndex[n_Integer?Positive , x_Symbol] := |
| 129 | + Expand[Simplify[CyclicGroupIndex[n, x]/2 + |
| 130 | + If[EvenQ[n], |
| 131 | + (x[2]^(n/2) + x[1]^2x[2]^(n/2-1))/4, |
| 132 | + (x[1]x[2]^((n-1)/2))/2 |
| 133 | + ] |
| 134 | + ] |
| 135 | + ] |
117 | 136 |
|
| 137 | +(* |
| 138 | +NecklacePolynomial::usage = "NecklacePolynomial[n, c, Cyclic] returns a polynomial in the colors in c whose coefficients represent numbers of ways of coloring an n-bead necklace with colors chosen from c, assuming that two colorings are equivalent if one can be obtained from the other by a rotation. NecklacePolynomial[n, c, Dihedral] is different in that it considers two colorings equivalent if one can be obtained from the other by a rotation or a flip or both."; |
118 | 139 |
|
119 | 140 | NecklacePolynomial[n_Integer?Positive, c_, Cyclic] := |
120 | 141 | OrbitInventory[CyclicGroupIndex[n, x], x, c] |
121 | 142 |
|
122 | 143 | NecklacePolynomial[n_Integer?Positive, c_, Dihedral] := |
123 | 144 | OrbitInventory[DihedralGroupIndex[n, x], x, c] |
| 145 | + *) |
| 146 | + |
| 147 | +OrbitInventory::usage = "OrbitInventory[ci, x, w] returns the value of the cycle index ci when each formal variable x[i] is replaced by w. OrbitInventory[ci, x, weights] returns the inventory of orbits induced on a set of functions by the action of a group with cycle index ci. It is assumed that each element in the range of the functions is assigned a weight in list weights."; |
| 148 | + |
124 | 149 |
|
125 | 150 | OrbitInventory[ci_?PolynomialQ, x_Symbol, weights_List] := |
126 | 151 | Expand[ci /. Table[x[i] -> Apply[Plus, Map[#^i&, weights]], |
|
131 | 156 | OrbitInventory[ci_?PolynomialQ, x_Symbol, r_] := |
132 | 157 | Expand[ci /. Table[x[i] -> r, {i, Exponent[ci, x[1]]} ]] |
133 | 158 |
|
134 | | -(*** Not working |
135 | | -RandomPermutation::usage = "RandomPermutation[n] generates a random permutation of the first n natural numbers."; |
136 | | -RP[n, _Integer] := |
137 | | - Module[{p = Range[n],i,x,t}, |
138 | | - Do [x = Random[Integer,{1,i}]; |
139 | | - t = p[[i]]; p[[i]] = p[[x]]; p[[x]] = t, |
140 | | - {i,n,2,-1} |
141 | | - ]; |
142 | | - p |
143 | | - ] |
144 | | -
|
| 159 | +(* Not working: always returns the same sorted value. |
| 160 | + We don't support Compile |
| 161 | + *) |
| 162 | +(*** |
| 163 | +RP = Compile[{{n, _Integer}}, |
| 164 | + Module[{p = Range[n],i,x,t}, |
| 165 | + Do [x = Random[Integer,{1,i}]; |
| 166 | + t = p[[i]]; p[[i]] = p[[x]]; p[[x]] = t, |
| 167 | + {i,n,2,-1} |
| 168 | + ]; |
| 169 | + p |
| 170 | + ] |
| 171 | + ] |
145 | 172 |
|
146 | 173 | RandomPermutation[n_Integer] := RP[n] |
147 | 174 | RandomPermutation[l_List] := Permute[l, RP[Length[l]]] |
|
164 | 191 | Subsets[n_Integer] := GrayCodeSubsets[Range[n]] |
165 | 192 | *) |
166 | 193 |
|
| 194 | +KSetPartitions::usage = "KSetPartitions[set, k] returns the list of set partitions of set with k blocks. KSetPartitions[n, k] returns the list of set partitions of {1, 2, ..., n} with k blocks. If all set partitions of a set are needed, use the function SetPartitions." |
| 195 | +KSetPartitions[{}, 0] := {{}} |
| 196 | +KSetPartitions[s_List, 0] := {} |
| 197 | +KSetPartitions[s_List, k_Integer] := {} /; (k > Length[s]) |
| 198 | +KSetPartitions[s_List, k_Integer] := {Map[{#} &, s]} /; (k === Length[s]) |
| 199 | +KSetPartitions[s_List, k_Integer] := |
| 200 | + Block[{$RecursionLimit = Infinity}, |
| 201 | + Join[Map[Prepend[#, {First[s]}] &, KSetPartitions[Rest[s], k - 1]], |
| 202 | + Flatten[ |
| 203 | + Map[Table[Prepend[Delete[#, j], Prepend[#[[j]], s[[1]]]], |
| 204 | + {j, Length[#]} |
| 205 | + ]&, |
| 206 | + KSetPartitions[Rest[s], k] |
| 207 | + ], 1 |
| 208 | + ] |
| 209 | + ] |
| 210 | + ] /; (k > 0) && (k < Length[s]) |
| 211 | + |
| 212 | +KSetPartitions[0, 0] := {{}} |
| 213 | +KSetPartitions[0, k_Integer?Positive] := {} |
| 214 | +KSetPartitions[n_Integer?Positive, 0] := {} |
| 215 | +KSetPartitions[n_Integer?Positive, k_Integer?Positive] := KSetPartitions[Range[n], k] |
| 216 | + |
167 | 217 | (* |
168 | 218 | KSubsets[l_List,0] := { {} } |
169 | 219 | KSubsets[l_List,1] := Partition[l,1] |
|
201 | 251 | Return[lo-1/2] |
202 | 252 | ]; |
203 | 253 |
|
| 254 | + *) |
| 255 | + |
| 256 | +TransposePartition::usage = "TransposePartition[p] reflects a partition p of k parts along the main diagonal, creating a partition with maximum part k." |
| 257 | +TransposePartition[{}] := {} |
| 258 | + |
| 259 | +TransposePartition[p_List] := |
| 260 | + Module[{s=Select[p,(#>0)&], i, row, r}, |
| 261 | + row = Length[s]; |
| 262 | + Table [r = row; While [s[[row]]<=i, row--]; r, {i,First[s]}] |
| 263 | + ] |
| 264 | + |
| 265 | + |
| 266 | +(*** FIXME: we run into recursion errors for nontrivial partitions. ***) |
| 267 | +(* |
204 | 268 | Partitions::usage = "Partitions[n] constructs all partitions of integer n in reverse lexicographic order. Partitions[n, k] constructs all partitions of the integer n with maximum part at most k, in reverse lexicographic order." |
205 | 269 |
|
206 | 270 | Partitions[n_Integer] := Partitions[n,n] |
|
218 | 282 | ] |
219 | 283 | *) |
220 | 284 |
|
| 285 | +SetPartitions[{}] := {{}} |
| 286 | +SetPartitions[s_List] := Flatten[Table[KSetPartitions[s, i], {i, Length[s]}], 1] |
| 287 | + |
| 288 | +SetPartitions[0] := {{}} |
| 289 | +SetPartitions[n_Integer?Positive] := SetPartitions[Range[n]] |
| 290 | + |
| 291 | +LastLexicographicTableau::usage = "LastLexicographicTableau[p] constructs the last Young tableau with shape described by partition p." |
| 292 | +LastLexicographicTableau[s_List] := |
| 293 | + Module[{c=0}, |
| 294 | + Map[(c+=#; Range[c-#+1,c])&, s] |
| 295 | + ] |
| 296 | + |
| 297 | +(* |
| 298 | +NumberOfTableaux::usage = "NumberOfTableaux[p] uses the hook length formula to count the number of Young tableaux with shape defined by partition p." |
| 299 | +NumberOfTableaux[{}] := 1 |
| 300 | +NumberOfTableaux[s_List] := |
| 301 | + Module[{row,col,transpose=TransposePartition[s]}, |
| 302 | + (Apply[Plus,s])! / |
| 303 | + Product [ |
| 304 | + (transpose[[col]]-row+s[[row]]-col+1), |
| 305 | + {row,Length[s]}, {col,s[[row]]} |
| 306 | + ] |
| 307 | + ] |
| 308 | +
|
| 309 | +NumberOfTableaux[n_Integer] := Apply[Plus, Map[NumberOfTableaux, Partitions[n]]] |
| 310 | + *) |
| 311 | + |
| 312 | +TransposePartition::usage = "TransposePartition[p] reflects a partition p of k parts along theg main diagonal, creating a partition with maximum part k." |
| 313 | +TransposePartition[{}] := {} |
| 314 | + |
| 315 | +(* |
| 316 | +TransposePartition[p_List] := |
| 317 | + Module[{s=Select[p,(#>0)&], i, row, r}, |
| 318 | + row = Length[s]; |
| 319 | + Table [r = row; While [s[[row]]<=i, row--]; r, {i,First[s]}] |
| 320 | + ] |
| 321 | + *) |
| 322 | + |
| 323 | + |
| 324 | +Tableaux::usage = "Tableaux[p] constructs all tableaux having a shape given by integer partition p." |
| 325 | +Tableaux[s_List] := |
| 326 | + Module[{t = LastLexicographicTableau[s]}, |
| 327 | + Table[ t = NextTableau[t], {NumberOfTableaux[s]} ] |
| 328 | + ] |
| 329 | + |
| 330 | +Tableaux[n_Integer?Positive] := Apply[ Join, Map[ Tableaux, Partitions[n] ] ] |
| 331 | + |
| 332 | + |
| 333 | +(**************************************************************************** |
| 334 | +*** Combinatorica 0.6 versions until we support more modern WL features ***** |
| 335 | +*****************************************************************************) |
| 336 | + |
| 337 | +(* Note: Until we support With[], this is the Combinatorica 0.6 version of BinarySearch *) |
| 338 | +BinarySearch::usage = "BinarySearch[l,k,f] searches sorted list l for key k and returns the the position of l containing k, with f a function which extracts the key from an element of l." |
| 339 | +BinarySearch[l_List,k_Integer] := BinarySearch[l,k,1,Length[l],Identity] |
| 340 | +BinarySearch[l_List,k_Integer,f_] := BinarySearch[l,k,1,Length[l],f] |
| 341 | + |
| 342 | +BinarySearch[l_List,k_Integer,low_Integer,high_Integer,f_] := |
| 343 | + Block[{mid = Floor[ (low + high)/2 ]}, |
| 344 | + If [low > high, Return[low - 1/2]]; |
| 345 | + If [f[ l[[mid]] ] == k, Return[mid]]; |
| 346 | + If [f[ l[[mid]] ] > k, |
| 347 | + BinarySearch[l,k,1,mid-1,f], |
| 348 | + BinarySearch[l,k,mid+1,high,f] |
| 349 | + ] |
| 350 | + ] |
| 351 | + |
| 352 | +KSubsets::usage = "KSubsets[l, k] gives all subsets of set l containing exactly k elements, ordered lexicographically." |
| 353 | +KSubsets[l_List,0] := { {} } |
| 354 | +KSubsets[l_List,1] := Partition[l,1] |
| 355 | +KSubsets[l_List,k_Integer?Positive] := {l} /; (k == Length[l]) |
| 356 | +KSubsets[l_List,k_Integer?Positive] := {} /; (k > Length[l]) |
| 357 | + |
| 358 | +KSubsets[l_List,k_Integer?Positive] := |
| 359 | + Join[ |
| 360 | + Map[(Prepend[#,First[l]])&, KSubsets[Rest[l],k-1]], |
| 361 | + KSubsets[Rest[l],k] |
| 362 | + ] |
| 363 | + |
| 364 | + |
| 365 | +(* Not working: always returns the same sorted value. |
| 366 | +Probably Sort[] below is buggy. |
| 367 | + *) |
| 368 | +(* |
| 369 | +RandomPermutation::usage = "RandomPermutation[n] returns a random permutation of length n." |
| 370 | +RandomPermutation1[n_Integer?Positive] := |
| 371 | + Map[ Last, Sort[ Map[({Random[],#})&,Range[n]] ] ] |
| 372 | +
|
| 373 | +RandomPermutation2[n_Integer?Positive] := |
| 374 | + Block[{p = Range[n],i,x}, |
| 375 | + Do [ |
| 376 | + x = Random[Integer,{1,i}]; |
| 377 | + {p[[i]],p[[x]]} = {p[[x]],p[[i]]}, |
| 378 | + {i,n,2,-1} |
| 379 | + ]; |
| 380 | + p |
| 381 | + ] |
| 382 | +RandomPermutation[n_Integer?Positive] := RandomPermutation1[n] |
| 383 | + *) |
| 384 | + |
| 385 | +(* Tableaux stuff not working. Hitting recursion limit.... |
| 386 | +TransposeTableau::usage = "TransposeTableau[t] reflects a Young tableau t along the main diagonal, creating a different tableau." |
| 387 | +TransposeTableau[tb_List] := |
| 388 | + Block[{t=Select[tb,(Length[#]>=1)&],row}, |
| 389 | + Table[ |
| 390 | + row = Map[First,t]; |
| 391 | + t = Map[ Rest, Select[t,(Length[#]>1)&] ]; |
| 392 | + row, |
| 393 | + {Length[First[tb]]} |
| 394 | + ] |
| 395 | + ] |
| 396 | +
|
| 397 | +TableauQ::usage = "TableauQ[t] returns True if and only if t represents a Young tableau." |
| 398 | +TableauQ[{}] = True |
| 399 | +TableauQ[t_List] := |
| 400 | + And [ |
| 401 | + Apply[ And, Map[(Apply[LessEqual,#])&,t] ], |
| 402 | + Apply[ And, Map[(Apply[LessEqual,#])&,TransposeTableau[t]] ], |
| 403 | + Apply[ GreaterEqual, Map[Length,t] ], |
| 404 | + Apply[ GreaterEqual, Map[Length,TransposeTableau[t]] ] |
| 405 | + ] |
| 406 | +
|
| 407 | +
|
| 408 | +NextTableau::usage = "NextTableau[t] returns the tableau of shape t which follows t in lexicographic order." |
| 409 | +NextTableau[t_?TableauQ] := |
| 410 | + Block[{s,y,row,j,count=0,tj,i,n=Max[t]}, |
| 411 | + y = TableauToYVector[t]; |
| 412 | + For [j=2, (j<n) && (y[[j]]>=y[[j-1]]), j++]; |
| 413 | + If [y[[j]] >= y[[j-1]], |
| 414 | + Return[ FirstLexicographicTableau[ ShapeOfTableau[t] ] ] |
| 415 | + ]; |
| 416 | + s = ShapeOfTableau[ Table[Select[t[[i]],(#<=j)&], {i,Length[t]}] ]; |
| 417 | + {row} = Last[ Position[ s, s[[ Position[t,j] [[1,1]] + 1 ]] ] ]; |
| 418 | + s[[row]] --; |
| 419 | + tj = FirstLexicographicTableau[s]; |
| 420 | + If[ Length[tj] < row, |
| 421 | + tj = Append[tj,{j}], |
| 422 | + tj[[row]] = Append[tj[[row]],j] |
| 423 | + ]; |
| 424 | + Join[ |
| 425 | + Table[ |
| 426 | + Join[tj[[i]],Select[t[[i]],(#>j)&]], |
| 427 | + {i,Length[tj]} |
| 428 | + ], |
| 429 | + Table[t[[i]],{i,Length[tj]+1,Length[t]}] |
| 430 | + ] |
| 431 | + ] |
| 432 | +
|
| 433 | +
|
| 434 | +NumberOfTableaux::usage = "NumberOfTableaux[p] uses the hook length formula to count the number of Young tableaux with shape defined by partition p." |
| 435 | +NumberOfTableaux[{}] := 1 |
| 436 | +NumberOfTableaux[s_List] := |
| 437 | + Block[{row,col,transpose=TransposePartition[s]}, |
| 438 | + (Apply[Plus,s])! / |
| 439 | + Product [ |
| 440 | + (transpose[[col]]-row+s[[row]]-col+1), |
| 441 | + {row,Length[s]}, {col,s[[row]]} |
| 442 | + ] |
| 443 | + ] |
| 444 | +
|
| 445 | +NumberOfTableaux[n_Integer] := Apply[Plus, Map[NumberOfTableaux, Partitions[n]]] |
| 446 | +*) |
| 447 | + |
221 | 448 | EndPackage[] |
0 commit comments