Copyright copyright 2006 Gene Michael Stover. All rights reserved. Permission to copy, store, & view this document unmodified & in its entirety is granted.
Sometimes, you have a bunch of variables, each of which has a defined set of values it can take, & you want to generate all the permutations of the variables. Here are some utility functions in Lisp that do this task.
For example, maybe you have three variables, like this:
You want a function to generate (color, size, temperature) for each combination of color, size, & temperature. Some of the values it might produce are:
The need for these functions shows up all the time in programming contests & sometimes at work.
Here is a copy of the license agreement that is on the source code. The same agreement appears in each source code file.
Copyright (c) 2006 Gene Michael Stover. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
In particular, take note that:
I implemented two functions, maperm & make-permutator.
maperm stands for “map permutator”. It s analogous to mapcar.
To use maperm, you give it a function to call for each permutation & then lists of the values for each variable. It will call your function for each combination of values.
For example, the color, size, temperature example from Section 1 “What is this” works with maperm like this:
Tfunction I gave to maperm prints each tuple. When it’s done, maperm returns the number of tuples.
Here is the source code for maperm:
make-permutator returns a function which you can call repeatedly. Each time you call it, the function returns the next combination of values. When there are no more combinations, it returns nil.
For example, the color, size, temperature example from Section 1 “What is this” works with make-permutator like this:
This example with make-permutator prints the same lines that the maperm example does. Notice that with make-permutator, you do not get the combination count unless you keep it or figure it out yourself.
Here is the source code for make-permutator:
I suspect the deciding factor when it comes to choosing maperm or make-permutator is how you want to use it, not performance. Nevertheless, I was curious about their relative performances.
I wrote three functions to help use the two generator functions on the same inputs. Here are those three functions:
Now let’s use those helper functions & time to compare maperm & make-permutator:
I am surprised that the make-permutator technique is noticeably faster than maperm. I guessed that using make-permutator would be slightly slower because it has to do the same work and has one extra level of function calls because each combination takes a function-call trip all the way back out to the client.
Since that’s not the case, I’m guessing that the performance difference is due to the extra consing that maperm does implicitly, via the &rest arguments. In fact, the ratio between the amounts consed is just about equal to the ratio between the run times. Table 1 shows those ratios.
| consed | seconds | |
| maperm | 517234960 | 9.272 |
| make-permutator | 283421816 | 5.214 |
| relative | 1.825 | 1.778 |
Another Lisp implementation could use a bignum integer counter. To get the next combination, it would increment the integer, then extract the position in each list of attributes with mod & ash.
I sometimes think of making a permutation generator in C, but don’t need it very often. I’ll probably make one the next time I need one. (Or, more likely, the next time I need one, I’ll wish I had made one now.)