Counted and indexed, not built
12! permutations, and the hundred-millionth of them. Neither call builds a list.
There are 479 001 600 permutations of twelve things. You would not want the list. But "how many" and "which one is the hundred-millionth" are both perfectly reasonable questions, and neither needs the list to exist.
That is the whole idea here. A combinatorial family is not a sequence you generate and hold — it is a bijection with an interval of the integers. Fix an order, and the family becomes an indexed collection: rank takes an object to its position, unrank takes a position back to an object. Everything else follows.
@enumeratio/combinatorics/collections declares each family as a lazy indexed collection on compute-engine, so its own Count and At answer by arithmetic rather than by enumeration.
12! permutations, and the hundred-millionth of them. Neither call builds a list.
At is 1-based: At(F, 1) is the first object and At(F, Count(F)) the last, and a negative index counts from the end. Past the count At is Missing rather than an error, so a slider can run past the end of a family without breaking anything.
Ask a family how big it is and the classical numbers fall out — not as a lookup table, but because counting the family is what those numbers do.
Dyck paths are Catalan, set partitions are Bell, k-subsets are binomial. Each pair is the same number arrived at from two directions.
This is a good way to check an implementation, and a better way to remember what a counting sequence counts. If Count(Derangements(5)) did not come back 44, one of the two would be wrong.
An index is a dial. Sweep it and you see the family in its order, one object at a time — which is the fastest way to learn what the order is.
Press ▶ and watch the order: the last element climbs fastest. That is lexicographic order — subsets are compared by their smallest element first.
The slider's value fills the _r wildcard, the expression is evaluated, and the glyph draws whatever came back. Nothing about that is specific to subsets — point it at a different family and the same rig walks that one.
24 permutations of four things against 14 Dyck paths of semilength four. At does not wrap, so the paths take the index modulo their count themselves, Mod(_r - 1, 14) + 1, and start over while the permutations are still going.
Once an object is addressable, a statistic of it is an ordinary function call. The permutation statistics — inversions, descents, major index, cycles — compose with At directly, which makes "what does this statistic look like across the family" a question you can just ask.
The 7th permutation of four things is [2,1,3,4] — one inversion, one descent.
A family and an order are not separable: change the order and At answers differently, so the order has to be stated. KSubsets is lexicographic — the 4th 3-subset of {1..5} is {1,3,4}, not {1,2,5}, because lex compares the smallest element first.
First and last.
Unranking is the same operation as writing a number in a numeral system whose places are combinatorial rather than geometric — the factoradic digits of n are the Lehmer code of the n-th permutation, and the combinatorial number system's digits are the n-th k-subset. Numeral systems makes that identification properly.
Every family here is catalogued, with its order and its counting sequence, in the symbol reference. The pictures are Shows of their frame layers and the slider is <Manipulate>.