00001 __copyright__ = """
00002 Copyright 2008 Sean Ross-Ross
00003 """
00004 __license__ = """
00005 This file is part of SLIMpy .
00006
00007 SLIMpy is free software: you can redistribute it and/or modify
00008 it under the terms of the GNU Lesser General Public License as published by
00009 the Free Software Foundation, either version 3 of the License, or
00010 (at your option) any later version.
00011
00012 SLIMpy is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00015 GNU Lesser General Public License for more details.
00016
00017 You should have received a copy of the GNU Lesser General Public License
00018 along with SLIMpy . If not, see <http://www.gnu.org/licenses/>.
00019 """
00020
00021 def _permute_iter( nested_iter ):
00022
00023 nested_iter = list(nested_iter)
00024
00025 if len( nested_iter ) == 0:
00026 raise Exception("can not pass in empty list")
00027
00028 elif len( nested_iter ) == 1:
00029 for item in nested_iter[0]:
00030 yield [item]
00031
00032 else:
00033 head,tail = nested_iter[0], nested_iter[1:]
00034 for hitem in head:
00035 for titems in _permute_iter( tail ):
00036 yield [hitem] + titems
00037
00038
00039 def permute_range( shape ):
00040 return permute( map(xrange, shape))
00041
00042
00043 def permute( iter_lists , restrict=None, constructor=None ):
00044 """
00045 permute( nested_iterable ) -> permutation_genorator
00046
00047 Takes a nested iterator sequence and returns all of the
00048 permutaions
00049
00050 eg.
00051 >>> pgen = permute( [[1,2], [3,4] ] )
00052 >>> for permutaion in pgen:
00053 >>> print permutaion
00054 [1, 3]
00055 [1, 4]
00056 [2, 3]
00057 [2, 4]
00058
00059 >>> pgen = permute( dict( a=[1,2], b=[3] ) )
00060 >>> for permutaion in pgen:
00061 >>> print permutaion
00062 { 'a':1, 'b':3 }
00063 { 'a':2, 'b':3 }
00064
00065 if constructor is not None, the output of each genoration is
00066 replaced by permutaion = constructor( permutaion )
00067
00068 if restrict is passed in it may be a callable function
00069 that evaluates a permutaion and returns True if the
00070 permutation needs to be restricted.
00071 if the first egample passing lambda perm: perm[0] == 2
00072 will not generate permutations where permutaion[0] is 2
00073 i.e. only [1, 3] and [1, 4] are generated
00074
00075 """
00076
00077 if isinstance(iter_lists, dict):
00078
00079 keylist = iter_lists.keys( )
00080
00081 if constructor is None:
00082 constructor = lambda value_list: dict( zip(keylist,value_list) )
00083
00084 list_of_lists = [ ]
00085 for key in keylist:
00086 list_of_lists.append( iter_lists[key] )
00087 else:
00088
00089 list_of_lists = iter_lists
00090
00091 if constructor is None:
00092 constructor = lambda value_list: value_list
00093
00094 if not restrict:
00095 restrict = lambda permutation: False
00096
00097 for value_list in _permute_iter(list_of_lists):
00098 permutation = constructor(value_list)
00099 if restrict(permutation):
00100 continue
00101 else:
00102 yield permutation
00103
00104 return
00105
00106
00107