This repository contains the course materials from Math 157: Intro to Mathematical Software.
Creative Commons BY-SA 4.0 license.
License: OTHER
Math 157: Intro to Mathematical Software
UC San Diego, winter 2018
February 5, 2018: Combinatorics (part 1 of 3)
Administrivia:
We are continuing to monitor the course waitlist. If you are on it and still want to join the course, please continue to keep up with lectures and homework, and watch your email for further instructions.
Here (again) is the precise link for the documentary screening later today.
There was an error in the HW 2 solution set (now fixed) which may have affected the grading of problem 3a. If you believe you were affected, contact course staff.
Added in class:
HW 4 is now posted.
Postscript: algorithms for determinants
How does a computer algebra system compute the determinant of an matrix ? Let's consider some options.
Recall that there is an explicit formula where runs over all permutations of and is the sign of (if you factor as a sequence of transpositions, the sign is +1 or -1 depending on whether this sequence has even or odd length). The sum involves terms, which means that already for this is unusable.
There is a recursive algorithm given by expansion in minors. For example, if I expand in minors along the first row, I get where is the submatrix obtained by removing row 1 and column . However, once you unwind the recursion, this also involves computations.
The most reasonable generic method is Gaussian elimination, which requires arithmetic operations.
For very large matrices (say n > 50000), there are some more advanced methods that do a bit better, e.g., ones which incorporate Strassen's algorithm for matrix multiplication.
However, as you learned on the last problem set, Sage does not use Gaussian elimination by itself to do this kind of computation.
The reason is that the use of Gaussian elimination creates some numbers in the middle of the computation which are about twice as long as this. To avoid this, Sage uses a bit of elementary number theory, in the form of the Chinese remainder theorem. (I'll demonstrate this for determinants, but similar considerations apply to other complex operations in linear algebra: reduced row echelon forms, matrix inverses, etc.)
Let's step through Gaussian elimination in this example.
Skipping ahead...
One way to get around this would be to be more careful about division, to get rid of the denominators. However, this requires some care and is not quite the best approach.
Alternate strategy:
Choose some random prime .
Reduce our matrix modulo a prime number to get .
Perform row reduction to compute .
(*) Lift the result back to the rational numbers to get the right answer.
This is potentially better, since until the last step we only deal with integers from 0 to .
Notice that the numbers are not exploding in size. Imagine doing all this with a 200x200 matrix (or worse)!
Unfortunately, the prime was not big enough: this computation tells me that but this is not enough to deduce that . To fix this, I need to compute a bound on (e.g., using the explicit formula in terms of permutations) and then take . (Why does this suffice?)
This creates its own difficulties, because if is really large, then we again end up working with large integers and this creates computational overhead. (CPUs can typically only handle 64 bits at a time, so large integers have to be broken into smaller chunks in order to deal with them. Think about the effect on multiplication, for example.)
Enter the Chinese remainder theorem. Let's instead choose primes such that ; we can then compute for each and use this knowledge to reconstruct .
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-59-8883128bdf31> in <module>()
----> 1 crt(m, l) ## This won't work
/ext/sage/sage-8.1/local/lib/python2.7/site-packages/sage/arith/misc.pyc in crt(a, b, m, n)
2756 """
2757 if isinstance(a, list):
-> 2758 return CRT_list(a, b)
2759 if isinstance(a, integer_types):
2760 a = Integer(a) # otherwise we get an error at (b-a).quo_rem(g)
/ext/sage/sage-8.1/local/lib/python2.7/site-packages/sage/arith/misc.pyc in CRT_list(v, moduli)
2841 from sage.arith.functions import lcm
2842 for i in range(1, len(v)):
-> 2843 x = CRT(x,v[i],m,moduli[i])
2844 m = lcm(m,moduli[i])
2845 return x%m
/ext/sage/sage-8.1/local/lib/python2.7/site-packages/sage/arith/misc.pyc in crt(a, b, m, n)
2760 a = Integer(a) # otherwise we get an error at (b-a).quo_rem(g)
2761 g, alpha, beta = XGCD(m, n)
-> 2762 q, r = (b - a).quo_rem(g)
2763 if r != 0:
2764 raise ValueError("No solution to crt problem since gcd(%s,%s) does not divide %s-%s" % (m, n, a, b))
/ext/sage/sage-8.1/src/sage/structure/element.pyx in sage.structure.element.Element.__sub__ (build/cythonized/sage/structure/element.c:11444)()
1361 return (<Element>left)._sub_(right)
1362 if BOTH_ARE_ELEMENT(cl):
-> 1363 return coercion_model.bin_op(left, right, sub)
1364
1365 try:
/ext/sage/sage-8.1/src/sage/structure/coerce.pyx in sage.structure.coerce.CoercionModel_cache_maps.bin_op (build/cythonized/sage/structure/coerce.c:10736)()
1137 # We should really include the underlying error.
1138 # This causes so much headache.
-> 1139 raise bin_op_exception(op, x, y)
1140
1141 cpdef canonical_coercion(self, x, y):
TypeError: unsupported operand parent(s) for -: 'Ring of integers modulo 3' and 'Ring of integers modulo 2'
P.S. If for some reason you really wanted to work modulo some very large prime , you would be better off lifting to integers, then doing this CRT approach. Sage doesn't yet do this, but maybe someday...
Combinatorics
Sage has very well-developed infrastructure for combinatorics, of which we will only scratch the surface here. For PhD-level research in the subject, it is probably the best software available, open-source or otherwise. (And remember that some basic functionality is available in Python via the itertools
module, as described last time.)
Reference: the Sage combinatorics tutorial http://doc.sagemath.org/html/en/reference/combinat/sage/combinat/tutorial.html
To begin with, recall that the number of ways to make an unordered choice of distinguishable objects from among given objects is the binomial coefficient where as usual denotes the factorial function.
You can use the binomial coefficients to count subsets without generating them. However, if you do actually want to generate the list of -element subsets of a given set, you can do that easily!
The Subsets function is an example of a structured set construction. Another important example is the Cartesian product; let's see an example based on playing cards.
Another example is the set of permutations of a list.
Exercise for right now: "Deal" a random hand of 13 cards from the deck. You can do this either by "shuffling" the whole deck, or by directly selecting a suitable subset.
Another example is the set of partitions of a given nonnegative integer. Let's illustrate with an example:
There is a method for counting partitions without enumerating them. This is due to Rademacher, and builds on the phenomenal work of Hardy and Ramanujan where they found an asymptotic series.
At a somewhat smaller scale, we can sample random partitions:
One can also enumerate partitions where the parts have fixed size, as in my examples of last time, making change:
... or solving the (original) Chicken McNuggets problem: https://en.wikipedia.org/wiki/Coin_problem. (I'm punting on my American football example because both Super Bowl teams have proved that failing to convert the point-after-touchdown is not such a rare occurrence!)
Many combinatorics problems lead naturally to integer sequences. These can be looked up in the On-line Encyclopedia of Integer Sequences (OEIS); but better yet, this database is integrated into Sage! (Whenever you encounter an unknown integer sequence, always consult OEIS. If it's not there yet, maybe it should be added.)
Maybe a less familiar example: let's count set partitions of {1, ..., n}.
Aha, let's read about that first one some more.