def mono_between_enum ( m, n1, n2 ): #*****************************************************************************80 # ## MONO_BETWEEN_ENUM enumerates monomials in M dimensions of degrees in a range. # # Discussion: # # For M = 3, we have the following table: # # N2 0 1 2 3 4 5 6 7 8 # N1 +---------------------------- # 0 | 1 4 10 20 35 56 84 120 165 # 1 | 0 3 9 19 34 55 83 119 164 # 2 | 0 0 6 16 31 52 80 116 161 # 3 | 0 0 0 10 25 46 74 110 155 # 4 | 0 0 0 0 15 36 64 100 145 # 5 | 0 0 0 0 0 21 49 85 130 # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 23 October 2014 # # Author: # # John Burkardt # # Parameters: # # Input, integer M, the spatial dimension. # # Input, integer N1, N2, the minimum and maximum degrees. # 0 <= N1 <= N2. # # Output, integer VALUE, the number of monomials in M variables, # of total degree between N1 and N2 inclusive. # from i4_choose import i4_choose n1 = max ( n1, 0 ) if ( n2 < n1 ): value = 0 return value if ( n1 == 0 ): value = i4_choose ( n2 + m, n2 ) elif ( n1 == n2 ): value = i4_choose ( n2 + m - 1, n2 ) else: n0 = n1 - 1 value = i4_choose ( n2 + m, n2 ) - i4_choose ( n0 + m, n0 ) return value
def mono_between_enum(m, n1, n2): #*****************************************************************************80 # ## MONO_BETWEEN_ENUM enumerates monomials in M dimensions of degrees in a range. # # Discussion: # # For M = 3, we have the following table: # # N2 0 1 2 3 4 5 6 7 8 # N1 +---------------------------- # 0 | 1 4 10 20 35 56 84 120 165 # 1 | 0 3 9 19 34 55 83 119 164 # 2 | 0 0 6 16 31 52 80 116 161 # 3 | 0 0 0 10 25 46 74 110 155 # 4 | 0 0 0 0 15 36 64 100 145 # 5 | 0 0 0 0 0 21 49 85 130 # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 23 October 2014 # # Author: # # John Burkardt # # Parameters: # # Input, integer M, the spatial dimension. # # Input, integer N1, N2, the minimum and maximum degrees. # 0 <= N1 <= N2. # # Output, integer VALUE, the number of monomials in M variables, # of total degree between N1 and N2 inclusive. # from i4_choose import i4_choose n1 = max(n1, 0) if (n2 < n1): value = 0 return value if (n1 == 0): value = i4_choose(n2 + m, n2) elif (n1 == n2): value = i4_choose(n2 + m - 1, n2) else: n0 = n1 - 1 value = i4_choose(n2 + m, n2) - i4_choose(n0 + m, n0) return value
def slice(dim_num, slice_num): #*****************************************************************************80 # ## SLICE: maximum number of pieces created by a given number of slices. # # Discussion: # # If we imagine slicing a pizza, each slice produce more pieces. # The position of the slice affects the number of pieces created, but there # is a maximum. # # This function determines the maximum number of pieces created by a given # number of slices, applied to a space of a given dimension. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 26 February 2015 # # Author: # # John Burkardt # # Reference: # # Robert Banks, # Slicing Pizzas, Racing Turtles, and Further Adventures in # Applied Mathematics, # Princeton, 1999, # ISBN13: 9780691059471, # LC: QA93.B358. # # Parameters: # # Input, integer DIM_NUM, the spatial dimension. # # Input, integer SLICE_NUM, the number of slices. # # Input, integer VALUE, the maximum number of pieces that can # be created by the given number of slices applied in the given dimension. # from i4_choose import i4_choose value = 0 j_hi = min(dim_num, slice_num) + 1 for j in range(0, j_hi): value = value + i4_choose(slice_num, j) return value
def slice ( dim_num, slice_num ): #*****************************************************************************80 # ## SLICE: maximum number of pieces created by a given number of slices. # # Discussion: # # If we imagine slicing a pizza, each slice produce more pieces. # The position of the slice affects the number of pieces created, but there # is a maximum. # # This function determines the maximum number of pieces created by a given # number of slices, applied to a space of a given dimension. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 26 February 2015 # # Author: # # John Burkardt # # Reference: # # Robert Banks, # Slicing Pizzas, Racing Turtles, and Further Adventures in # Applied Mathematics, # Princeton, 1999, # ISBN13: 9780691059471, # LC: QA93.B358. # # Parameters: # # Input, integer DIM_NUM, the spatial dimension. # # Input, integer SLICE_NUM, the number of slices. # # Input, integer VALUE, the maximum number of pieces that can # be created by the given number of slices applied in the given dimension. # from i4_choose import i4_choose value = 0 j_hi = min ( dim_num, slice_num ) + 1 for j in range ( 0, j_hi ): value = value + i4_choose ( slice_num, j ) return value
def mono_total_enum(m, n): #*****************************************************************************80 # ## MONO_TOTAL_ENUM enumerates monomials in M dimensions of degree equal to N. # # Discussion: # # For M = 3, we have the following values: # # N VALUE # # 0 1 # 1 3 # 2 6 # 3 10 # 4 15 # 5 21 # # In particular, VALUE(3,3) = 10 because we have the 10 monomials: # # x^3, x^2y, x^2z, xy^2, xyz, xz^3, y^3, y^2z, yz^2, z^3. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 23 October 2014 # # Author: # # John Burkardt # # Parameters: # # Input, integer M, the spatial dimension. # # Input, integer N, the maximum degree. # # Output, integer VALUE, the number of monomials in M variables, # of total degree N. # from i4_choose import i4_choose value = i4_choose(n + m - 1, n) return value
def mono_upto_enum ( m, n ): #*****************************************************************************80 # ## MONO_UPTO_ENUM enumerates monomials in M dimensions of degree up to N. # # Discussion: # # For M = 2, we have the following values: # # N VALUE # # 0 1 # 1 3 # 2 6 # 3 10 # 4 15 # 5 21 # # In particular, VALUE(2,3) = 10 because we have the 10 monomials: # # 1, x, y, x^2, xy, y^2, x^3, x^2y, xy^2, y^3. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 23 October 2014 # # Author: # # John Burkardt # # Parameters: # # Input, integer M, the spatial dimension. # # Input, integer N, the maximum degree. # # Output, integer VALUE, the number of monomials in # M variables, of total degree N or less. # from i4_choose import i4_choose value = i4_choose ( n + m, n ) return value
def mono_upto_enum ( m, n ): #*****************************************************************************80 # ## MONO_UPTO_ENUM enumerates monomials in M dimensions of degree up to N. # # Discussion: # # For M = 2, we have the following values: # # N VALUE # # 0 1 # 1 3 # 2 6 # 3 10 # 4 15 # 5 21 # # In particular, VALUE(2,3) = 10 because we have the 10 monomials: # # 1, x, y, x^2, xy, y^2, x^3, x^2y, xy^2, y^3. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 23 October 2014 # # Author: # # John Burkardt # # Parameters: # # Input, int M, the spatial dimension. # # Input, int N, the maximum degree. # # Output, int VALUE, the number of monomials in # M variables, of total degree N or less. # from i4_choose import i4_choose value = i4_choose ( n + m, n ) return value
def comp_enum ( n, k ): #******************************************************************************/ # ## COMP_ENUM returns the number of compositions of the integer N into K parts. # # Discussion: # # A composition of the integer N into K parts is an ordered sequence # of K nonnegative integers which sum to N. The compositions (1,2,1) # and (1,1,2) are considered to be distinct. # # The 28 compositions of 6 into three parts are: # # 6 0 0, 5 1 0, 5 0 1, 4 2 0, 4 1 1, 4 0 2, # 3 3 0, 3 2 1, 3 1 2, 3 0 3, 2 4 0, 2 3 1, # 2 2 2, 2 1 3, 2 0 4, 1 5 0, 1 4 1, 1 3 2, # 1 2 3, 1 1 4, 1 0 5, 0 6 0, 0 5 1, 0 4 2, # 0 3 3, 0 2 4, 0 1 5, 0 0 6. # # The formula for the number of compositions of N into K parts is # # Number = ( N + K - 1 )! / ( N! * ( K - 1 )! ) # # Describe the composition using N '1's and K-1 dividing lines '|'. # The number of distinct permutations of these symbols is the number # of compositions. This is equal to the number of permutations of # N+K-1 things, with N identical of one kind and K-1 identical of another. # # Thus, for the above example, we have: # # Number = ( 6 + 3 - 1 )! / ( 6! * (3-1)! ) = 28 # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 30 October 2014 # # Author: # # John Burkardt # # Reference: # # Albert Nijenhuis, Herbert Wilf, # Combinatorial Algorithms for Computers and Calculators, # Second Edition, # Academic Press, 1978, # ISBN: 0-12-519260-6, # LC: QA164.N54. # # Parameters: # # Input, integer N, the integer whose compositions are desired. # # Input, integer K, the number of parts in the composition. # # Output, integer VALUE, the number of compositions of N # into K parts. # from i4_choose import i4_choose value = i4_choose ( n + k - 1, n ) return value
def comb_unrank_test(): #*****************************************************************************80 # ## COMB_UNRANK_TEST tests COMB_UNRANK. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 22 May 2015 # # Author: # # John Burkardt # from i4_choose import i4_choose n = 5 m = 10 cnk = i4_choose(m, n) print '' print 'COMB_UNRANK_TEST' print ' COMB_UNRANK returns a combination of N things' print ' out of M, given the lexicographic rank.' print '' print ' The total set size is M = %d' % (m) print ' The subset size is N = %d' % (n) print ' The number of combinations of N out of M is %d' % (cnk) print '' print ' Rank Combination' print '' for rank in range(1, 4): a = comb_unrank(m, n, rank) print ' %3d' % (rank), for i in range(0, n): print ' %5d' % (a[i]), print '' for rank in range(6, 9): a = comb_unrank(m, n, rank) print ' %3d' % (rank), for i in range(0, n): print ' %5d' % (a[i]), print '' for rank in range(250, 253): a = comb_unrank(m, n, rank) print ' %3d' % (rank), for i in range(0, n): print ' %5d' % (a[i]), print '' # # Terminate. # print '' print 'COMB_UNRANK_TEST:' print ' Normal end of execution.' return
def mono_unrank_grlex ( m, rank ): #*****************************************************************************80 # ## MONO_UNRANK_GRLEX computes the monomial of given grlex rank. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 25 October 2015 # # Author: # # John Burkardt # # Parameters: # # Input, integer M, the spatial dimension. # 1 <= M. # # Input, integer RANK, the rank of the monomial. # # Output, integer X[M], the monomial. # import numpy as np from i4_choose import i4_choose from sys import exit # # Ensure that 1 <= M. # if ( m < 1 ): print '' print 'MONO_UNRANK_GRLEX - Fatal error!' print ' M < 1' exit ( 'MONO_UNRANK_GRLEX - Fatal error!' ) # # Ensure that 1 <= RANK. # if ( rank < 1 ): print '' print 'MONO_UNRANK_GRLEX - Fatal error!' print ' RANK < 1' exit ( 'MONO_UNRANK_GRLEX - Fatal error!' ) x = np.zeros ( m, dtype = np.int32 ) # # Special case M = 1. # if ( m == 1 ): x[0] = rank - 1 return x # # Determine the appropriate value of NM. # Do this by adding up the number of compositions of sum 0, 1, 2, # ..., without exceeding RANK. Moreover, RANK - this sum essentially # gives you the rank of the composition within the set of compositions # of sum NM. And that's the number you need in order to do the # unranking. # rank1 = 1 nm = -1 while ( True ): nm = nm + 1 r = i4_choose ( nm + m - 1, nm ) if ( rank < rank1 + r ): break rank1 = rank1 + r rank2 = rank - rank1 # # Convert to KSUBSET format. # Apology: an unranking algorithm was available for KSUBSETS, # but not immediately for compositions. One day we will come back # and simplify all this. # ks = m - 1 ns = nm + m - 1 xs = np.zeros ( ks, dtype = np.int32 ) nksub = i4_choose ( ns, ks ) j = 1 for i in range ( 1, ks + 1 ): r = i4_choose ( ns - j, ks - i ) while ( r <= rank2 and 0 < r ): rank2 = rank2 - r j = j + 1 r = i4_choose ( ns - j, ks - i ) xs[i-1] = j j = j + 1 # # Convert from KSUBSET format to COMP format. # x[0] = xs[0] - 1 for i in range ( 2, m ): x[i-1] = xs[i-1] - xs[i-2] - 1 x[m-1] = ns - xs[ks-1] return x
def comb_unrank ( m, n, rank ): #*****************************************************************************80 # ## COMB_UNRANK returns the RANK-th combination of N things out of M. # # Discussion: # # Going from a rank to a thing is called "unranking". # # The combinations are ordered lexically. # # Lexical order can be illustrated for the general case of N and M as # follows: # # 1: 1, 2, 3, ..., N-2, N-1, N # 2: 1, 2, 3, ..., N-2, N-1, N+1 # 3: 1, 2, 3, ..., N-2, N-1, N+2 # ... # M-N+1: 1, 2, 3, ..., N-2, N-1, M # M-N+2: 1, 2, 3, ..., N-2, N, N+1 # M-N+3: 1, 2, 3, ..., N-2, N, N+2 # ... # LAST-2: M-N, M-N+1, M-N+3, ..., M-2, M-1, M # LAST-1: M-N, M-N+2, M-N+3, ..., M-2, M-1, M # LAST: M-N+1, M-N+2, M-N+3, ..., M-2, M-1, M # # There are a total of M!/(N!*(M-N)!) combinations of M # things taken N at a time. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 22 May 2015 # # Author: # # John Burkardt # # Reference: # # B P Buckles, M Lybanon, # Algorithm 515, # Generation of a Vector from the Lexicographical Index, # ACM Transactions on Mathematical Software, # Volume 3, Number 2, pages 180-182, June 1977. # # Parameters: # # Input, integer M, the size of the set. # # Input, integer N, the number of things in the combination. # N must be greater than 0, and no greater than M. # # Input, integer RANK, the lexicographical rank of the combination # sought. RANK must be at least 1, and no greater than M!/(N!*(M-N)!). # # Output, integer A(N), the combination. # import numpy as np from i4_choose import i4_choose a = np.zeros ( n, dtype = np.int32 ) # # Initialize the lower bound index. # k = 0 # # Select elements in ascending order. # for i in range ( 0, n - 1 ): # # Set the lower bound element number for next element value. # a[i] = 0 if ( 0 < i ): a[i] = a[i-1] # # Check each element value. # while ( True ): a[i] = a[i] + 1 j = i4_choose ( m - a[i], n - i - 1 ) k = k + j if ( rank <= k ): break k = k - j; a[n-1] = a[n-2] + rank - k return a
def comp_rank_grlex ( kc, xc ): #*****************************************************************************80 # ## COMP_RANK_GRLEX computes the graded lexicographic rank of a composition. # # Discussion: # # The graded lexicographic ordering is used, over all KC-compositions # for NC = 0, 1, 2, ... # # For example, if KC = 3, the ranking begins: # # Rank Sum 1 2 3 # ---- --- -- -- -- # 1 0 0 0 0 # # 2 1 0 0 1 # 3 1 0 1 0 # 4 1 1 0 1 # # 5 2 0 0 2 # 6 2 0 1 1 # 7 2 0 2 0 # 8 2 1 0 1 # 9 2 1 1 0 # 10 2 2 0 0 # # 11 3 0 0 3 # 12 3 0 1 2 # 13 3 0 2 1 # 14 3 0 3 0 # 15 3 1 0 2 # 16 3 1 1 1 # 17 3 1 2 0 # 18 3 2 0 1 # 19 3 2 1 0 # 20 3 3 0 0 # # 21 4 0 0 4 # .. .. .. .. .. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 30 October 2014 # # Author: # # John Burkardt # # Parameters: # # Input, int KC, the number of parts in the composition. # 1 <= KC. # # Input, int XC[KC], the composition. # For each 1 <= I <= KC, we have 0 <= XC(I). # # Output, int RANK, the rank of the composition. # import numpy as np from i4_choose import i4_choose from i4vec_sum import i4vec_sum from sys import exit # # Ensure that 1 <= KC. # if ( kc < 1 ): print ''; print 'COMP_RANK_GRLEX - Fatal error!' print ' KC < 1' exit ( 'COMP_RANK_GRLEX - Fatal error!' ); # # Ensure that 0 <= XC(I). # for i in range ( 0, kc ): if ( xc[i] < 0 ): print '' print 'COMP_RANK_GRLEX - Fatal error!' print ' XC[I] < 0' exit ( 'COMP_RANK_GRLEX - Fatal error!' ); # # NC = sum ( XC ) # nc = i4vec_sum ( kc, xc ) # # Convert to KSUBSET format. # ns = nc + kc - 1 ks = kc - 1 xs = np.zeros ( ks, dtype = np.int32 ) xs[0] = xc[0] + 1 for i in range ( 2, kc ): xs[i-1] = xs[i-2] + xc[i-1] + 1 # # Compute the rank. # rank = 1; for i in range ( 1, ks + 1 ): if ( i == 1 ): tim1 = 0 else: tim1 = xs[i-2]; if ( tim1 + 1 <= xs[i-1] - 1 ): for j in range ( tim1 + 1, xs[i-1] ): rank = rank + i4_choose ( ns - j, ks - i ) for n in range ( 0, nc ): rank = rank + i4_choose ( n + kc - 1, n ) return rank
def comp_unrank_grlex(kc, rank): #*****************************************************************************80 # ## COMP_UNRANK_GRLEX computes the composition of given grlex rank. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 30 October 2014 # # Author: # # John Burkardt # # Parameters: # # Input, int KC, the number of parts of the composition. # 1 <= KC. # # Input, int RANK, the rank of the composition. # 1 <= RANK. # # Output, int XC[KC], the composition XC of the given rank. # For each I, 0 <= XC[I] <= NC, and # sum ( 1 <= I <= KC ) XC[I] = NC. # from i4_choose import i4_choose from sys import exit import numpy as np # # Ensure that 1 <= KC. # if (kc < 1): print '' print 'COMP_UNRANK_GRLEX - Fatal error!' print ' KC < 1' exit('COMP_UNRANK_GRLEX - Fatal error!') # # Ensure that 1 <= RANK. # if (rank < 1): print '' print 'COMP_UNRANK_GRLEX - Fatal error!' print ' RANK < 1' exit('COMP_UNRANK_GRLEX - Fatal error!') # # Determine the appropriate value of NC. # Do this by adding up the number of compositions of sum 0, 1, 2, # ..., without exceeding RANK. Moreover, RANK - this sum essentially # gives you the rank of the composition within the set of compositions # of sum NC. And that's the number you need in order to do the # unranking. # rank1 = 1 nc = -1 while (True): nc = nc + 1 r = i4_choose(nc + kc - 1, nc) if (rank < rank1 + r): break rank1 = rank1 + r rank2 = rank - rank1 # # Convert to KSUBSET format. # Apology: an unranking algorithm was available for KSUBSETS, # but not immediately for compositions. One day we will come back # and simplify all this. # ks = kc - 1 ns = nc + kc - 1 xs = np.zeros(ks, dtype=np.int32) nksub = i4_choose(ns, ks) j = 1 for i in range(1, ks + 1): r = i4_choose(ns - j, ks - i) while (r <= rank2 and 0 < r): rank2 = rank2 - r j = j + 1 r = i4_choose(ns - j, ks - i) xs[i - 1] = j j = j + 1 # # Convert from KSUBSET format to COMP format. # xc = np.zeros(kc, dtype=np.int32) xc[0] = xs[0] - 1 for i in range(2, kc): xc[i - 1] = xs[i - 1] - xs[i - 2] - 1 xc[kc - 1] = ns - xs[ks - 1] return xc
def lock(n): #*****************************************************************************80 # ## LOCK returns the number of codes for a lock with N buttons. # # Discussion: # # A button lock has N numbered buttons. To open the lock, groups # of buttons must be pressed in the correct order. Each button # may be pushed no more than once. Thus, a code for the lock is # an ordered list of the groups of buttons to be pushed. # # For this discussion, we will assume that EVERY button is pushed # at some time, as part of the code. To count the total number # of codes, including those which don't use all the buttons, then # the number is 2 * A(N), or 2 * A(N) - 1 if we don't consider the # empty code to be valid. # # Examples: # # If there are 3 buttons, then there are 13 possible "full button" codes: # # (123) # (12) (3) # (13) (2) # (23) (1) # (1) (23) # (2) (13) # (3) (12) # (1) (2) (3) # (1) (3) (2) # (2) (1) (3) # (2) (3) (1) # (3) (1) (2) # (3) (2) (1) # # and, if we don't need to push all the buttons, every "full button" code above # yields a distinct "partial button" code by dropping the last set of buttons: # # () # (12) # (13) # (23) # (1) # (2) # (3) # (1) (2) # (1) (3) # (2) (1) # (2) (3) # (3) (1) # (3) (2) # # First values: # # N A(N) # 0 1 # 1 1 # 2 3 # 3 13 # 4 75 # 5 541 # 6 4683 # 7 47293 # 8 545835 # 9 7087261 # 10 102247563 # # Recursion: # # A(I) = sum ( 0 <= J < I ) Binomial ( I, N-J ) * A(J) # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 23 February 2015 # # Author: # # John Burkardt # # Reference: # # Daniel Velleman, Gregory Call, # Permutations and Combination Locks, # Mathematics Magazine, # Volume 68, Number 4, October 1995, pages 243-253. # # Parameters: # # Input, integer N, the maximum number of lock buttons. # # Output, integer A(1:N+1), the number of lock codes. # import numpy as np from i4_choose import i4_choose a = np.zeros(n + 1) a[0] = 1 for i in range(1, n + 1): a[i] = 0 for j in range(0, i): a[i] = a[i] + i4_choose(i, i - j) * a[j] return a
def euler_number ( n ): #*****************************************************************************80 # ## EULER_NUMBER computes the Euler numbers. # # Discussion: # # The Euler numbers can be evaluated in Mathematica by the call # # EulerE[n] # # These numbers rapidly get too big to store in an ordinary integer! # # The terms of odd index are 0. # # E(N) = -C(N,N-2) * E(N-2) - C(N,N-4) * E(N-4) - ... - C(N,0) * E(0). # # First terms: # # E0 = 1 # E1 = 0 # E2 = -1 # E3 = 0 # E4 = 5 # E5 = 0 # E6 = -61 # E7 = 0 # E8 = 1385 # E9 = 0 # E10 = -50521 # E11 = 0 # E12 = 2702765 # E13 = 0 # E14 = -199360981 # E15 = 0 # E16 = 19391512145 # E17 = 0 # E18 = -2404879675441 # E19 = 0 # E20 = 370371188237525 # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 04 February 2015 # # Author: # # John Burkardt # # Reference: # # Stephen Wolfram, # The Mathematica Book, # Fourth Edition, # Wolfram Media / Cambridge University Press, 1999. # # Parameters: # # Input, integer N, the index of the last Euler number to compute. # # Output, integer E[0:N], the Euler numbers. # import numpy as np from i4_choose import i4_choose e = np.zeros ( n + 1 ) e[0] = 1 if ( 0 < n ): e[1] = 0 if ( 1 < n ): e[2] = -1 for i in range ( 3, n + 1 ): e[i] = 0 if ( ( i % 2 ) == 0 ): for j in range ( 2, i + 1, 2 ): e[i] = e[i] - i4_choose ( i, j ) * e[i-j] return e
def comb_unrank(m, n, rank): #*****************************************************************************80 # ## COMB_UNRANK returns the RANK-th combination of N things out of M. # # Discussion: # # Going from a rank to a thing is called "unranking". # # The combinations are ordered lexically. # # Lexical order can be illustrated for the general case of N and M as # follows: # # 1: 1, 2, 3, ..., N-2, N-1, N # 2: 1, 2, 3, ..., N-2, N-1, N+1 # 3: 1, 2, 3, ..., N-2, N-1, N+2 # ... # M-N+1: 1, 2, 3, ..., N-2, N-1, M # M-N+2: 1, 2, 3, ..., N-2, N, N+1 # M-N+3: 1, 2, 3, ..., N-2, N, N+2 # ... # LAST-2: M-N, M-N+1, M-N+3, ..., M-2, M-1, M # LAST-1: M-N, M-N+2, M-N+3, ..., M-2, M-1, M # LAST: M-N+1, M-N+2, M-N+3, ..., M-2, M-1, M # # There are a total of M!/(N!*(M-N)!) combinations of M # things taken N at a time. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 22 May 2015 # # Author: # # John Burkardt # # Reference: # # B P Buckles, M Lybanon, # Algorithm 515, # Generation of a Vector from the Lexicographical Index, # ACM Transactions on Mathematical Software, # Volume 3, Number 2, pages 180-182, June 1977. # # Parameters: # # Input, integer M, the size of the set. # # Input, integer N, the number of things in the combination. # N must be greater than 0, and no greater than M. # # Input, integer RANK, the lexicographical rank of the combination # sought. RANK must be at least 1, and no greater than M!/(N!*(M-N)!). # # Output, integer A(N), the combination. # import numpy as np from i4_choose import i4_choose a = np.zeros(n, dtype=np.int32) # # Initialize the lower bound index. # k = 0 # # Select elements in ascending order. # for i in range(0, n - 1): # # Set the lower bound element number for next element value. # a[i] = 0 if (0 < i): a[i] = a[i - 1] # # Check each element value. # while (True): a[i] = a[i] + 1 j = i4_choose(m - a[i], n - i - 1) k = k + j if (rank <= k): break k = k - j a[n - 1] = a[n - 2] + rank - k return a
def mono_unrank_grlex(m, rank): #*****************************************************************************80 # ## MONO_UNRANK_GRLEX computes the monomial of given grlex rank. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 25 October 2015 # # Author: # # John Burkardt # # Parameters: # # Input, integer M, the spatial dimension. # 1 <= M. # # Input, integer RANK, the rank of the monomial. # # Output, integer X[M], the monomial. # import numpy as np from i4_choose import i4_choose from sys import exit # # Ensure that 1 <= M. # if (m < 1): print '' print 'MONO_UNRANK_GRLEX - Fatal error!' print ' M < 1' exit('MONO_UNRANK_GRLEX - Fatal error!') # # Ensure that 1 <= RANK. # if (rank < 1): print '' print 'MONO_UNRANK_GRLEX - Fatal error!' print ' RANK < 1' exit('MONO_UNRANK_GRLEX - Fatal error!') x = np.zeros(m, dtype=np.int32) # # Special case M = 1. # if (m == 1): x[0] = rank - 1 return x # # Determine the appropriate value of NM. # Do this by adding up the number of compositions of sum 0, 1, 2, # ..., without exceeding RANK. Moreover, RANK - this sum essentially # gives you the rank of the composition within the set of compositions # of sum NM. And that's the number you need in order to do the # unranking. # rank1 = 1 nm = -1 while (True): nm = nm + 1 r = i4_choose(nm + m - 1, nm) if (rank < rank1 + r): break rank1 = rank1 + r rank2 = rank - rank1 # # Convert to KSUBSET format. # Apology: an unranking algorithm was available for KSUBSETS, # but not immediately for compositions. One day we will come back # and simplify all this. # ks = m - 1 ns = nm + m - 1 xs = np.zeros(ks, dtype=np.int32) nksub = i4_choose(ns, ks) j = 1 for i in range(1, ks + 1): r = i4_choose(ns - j, ks - i) while (r <= rank2 and 0 < r): rank2 = rank2 - r j = j + 1 r = i4_choose(ns - j, ks - i) xs[i - 1] = j j = j + 1 # # Convert from KSUBSET format to COMP format. # x[0] = xs[0] - 1 for i in range(2, m): x[i - 1] = xs[i - 1] - xs[i - 2] - 1 x[m - 1] = ns - xs[ks - 1] return x
def comp_unrank_grlex ( kc, rank ): #*****************************************************************************80 # ## COMP_UNRANK_GRLEX computes the composition of given grlex rank. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 30 October 2014 # # Author: # # John Burkardt # # Parameters: # # Input, int KC, the number of parts of the composition. # 1 <= KC. # # Input, int RANK, the rank of the composition. # 1 <= RANK. # # Output, int XC[KC], the composition XC of the given rank. # For each I, 0 <= XC[I] <= NC, and # sum ( 1 <= I <= KC ) XC[I] = NC. # from i4_choose import i4_choose from sys import exit import numpy as np # # Ensure that 1 <= KC. # if ( kc < 1 ): print '' print 'COMP_UNRANK_GRLEX - Fatal error!' print ' KC < 1' exit ( 'COMP_UNRANK_GRLEX - Fatal error!' ) # # Ensure that 1 <= RANK. # if ( rank < 1 ): print '' print 'COMP_UNRANK_GRLEX - Fatal error!' print ' RANK < 1' exit ( 'COMP_UNRANK_GRLEX - Fatal error!' ) # # Determine the appropriate value of NC. # Do this by adding up the number of compositions of sum 0, 1, 2, # ..., without exceeding RANK. Moreover, RANK - this sum essentially # gives you the rank of the composition within the set of compositions # of sum NC. And that's the number you need in order to do the # unranking. # rank1 = 1 nc = -1 while ( True ): nc = nc + 1 r = i4_choose ( nc + kc - 1, nc ) if ( rank < rank1 + r ): break rank1 = rank1 + r rank2 = rank - rank1 # # Convert to KSUBSET format. # Apology: an unranking algorithm was available for KSUBSETS, # but not immediately for compositions. One day we will come back # and simplify all this. # ks = kc - 1 ns = nc + kc - 1 xs = np.zeros ( ks, dtype = np.int32 ) nksub = i4_choose ( ns, ks ) j = 1 for i in range ( 1, ks + 1 ): r = i4_choose ( ns - j, ks - i ) while ( r <= rank2 and 0 < r ): rank2 = rank2 - r j = j + 1 r = i4_choose ( ns - j, ks - i ) xs[i-1] = j j = j + 1 # # Convert from KSUBSET format to COMP format. # xc = np.zeros ( kc, dtype = np.int32 ) xc[0] = xs[0] - 1 for i in range ( 2, kc ): xc[i-1] = xs[i-1] - xs[i-2] - 1 xc[kc-1] = ns - xs[ks-1] return xc
def mono_rank_grlex ( m, x ): #*****************************************************************************80 # ## MONO_RANK_GRLEX computes the graded lexicographic rank of a monomial. # # Discussion: # # The graded lexicographic ordering is used, over all monomials in # M dimensions, for total degree = 0, 1, 2, ... # # For example, if M = 3, the ranking begins: # # Rank Sum 1 2 3 # ---- --- -- -- -- # 1 0 0 0 0 # # 2 1 0 0 1 # 3 1 0 1 0 # 4 1 1 0 1 # # 5 2 0 0 2 # 6 2 0 1 1 # 7 2 0 2 0 # 8 2 1 0 1 # 9 2 1 1 0 # 10 2 2 0 0 # # 11 3 0 0 3 # 12 3 0 1 2 # 13 3 0 2 1 # 14 3 0 3 0 # 15 3 1 0 2 # 16 3 1 1 1 # 17 3 1 2 0 # 18 3 2 0 1 # 19 3 2 1 0 # 20 3 3 0 0 # # 21 4 0 0 4 # .. .. .. .. .. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 31 October 2015 # # Author: # # John Burkardt # # Parameters: # # Input, integer M, the spatial dimension. # 1 <= M. # # Input, integer X[M], the composition. # For each 1 <= I <= M, we have 0 <= X(I). # # Output, integer RANK, the rank. # from i4_choose import i4_choose from i4vec_sum import i4vec_sum import numpy as np # # Ensure that 1 <= M. # if ( m < 1 ): print '' print 'MONO_RANK_GRLEX - Fatal error!' print ' M < 1' sys.exit ( 'MONO_RANK_GRLEX - Fatal error!' ) # # Ensure that 0 <= X(I). # for i in range ( 0, m ): if ( x[i] < 0 ): print '' print 'MONO_RANK_GRLEX - Fatal error!' print ' X[I] < 0' sys.exit ( 'MONO_RANK_GRLEX - Fatal error!' ) # # NM = sum ( X ) # nm = i4vec_sum ( m, x ) # # Convert to KSUBSET format. # ns = nm + m - 1 ks = m - 1 if ( 0 < ks ): xs = np.zeros ( ks, dtype = np.int32 ) xs[0] = x[0] + 1 for i in range ( 2, m ): xs[i-1] = xs[i-2] + x[i-1] + 1 # # Compute the rank. # rank = 1 for i in range ( 1, ks + 1 ): if ( i == 1 ): tim1 = 0 else: tim1 = xs[i-2] if ( tim1 + 1 <= xs[i-1] - 1 ): for j in range ( tim1 + 1, xs[i-1] ): rank = rank + i4_choose ( ns - j, ks - i ) for n in range ( 0, nm ): rank = rank + i4_choose ( n + m - 1, n ) return rank
def poly_coef_count ( dim, degree ): #*****************************************************************************80 # ## POLY_COEF_COUNT: polynomial coefficient count given dimension and degree. # # Discussion: # # To count all monomials of degree 5 or less in dimension 3, # we can count all monomials of degree 5 in dimension 4. # # To count all monomials of degree 5 in dimension 4, we imagine # that each of the variables X, Y, Z and W is a "box" and that # we need to drop 5 pebbles into these boxes. Every distinct # way of doing this represents a degree 5 monomial in dimension 4. # Ignoring W gives us monomials up to degree five in dimension 3. # # To count them, we draw 3 lines as separators to indicate the # 4 boxes, and then imagine all disctinct sequences involving # the three lines and the 5 pebbles. Indicate the lines by 1's # and the pebbles by 0's and we're asking for the number of # permutations of 3 1's and 5 0's, which is 8! / (3! 5!) # # In other words, 56 = 8! / (3! 5!) is: # * the number of monomials of degree exactly 5 in dimension 4, # * the number of monomials of degree 5 or less in dimension 3, # * the number of polynomial coefficients of a polynomial of # degree 5 in (X,Y,Z). # # In general, the formula for the number of monomials of degree DEG # or less in dimension DIM is # # (DEG+DIM)! / (DEG! * DIM!) # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 25 February 2015 # # Author: # # John Burkardt # # Parameters: # # Input, integer DIM, the dimension of the polynomial. # 0 <= DIM. # # Input, integer DEGREE, the degree of the polynomnial # 0 <= DEGREE # # Output, integer VALUE, the number of coefficients # in the general polynomial of dimension DIM and degree DEGREE. # from i4_choose import i4_choose if ( dim < 0 ): value = -1 elif ( degree < 0 ): count = -1 else: value = i4_choose ( degree + dim, degree ) return value
def comb_unrank_test ( ): #*****************************************************************************80 # ## COMB_UNRANK_TEST tests COMB_UNRANK. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 22 May 2015 # # Author: # # John Burkardt # from i4_choose import i4_choose n = 5 m = 10 cnk = i4_choose ( m, n ) print '' print 'COMB_UNRANK_TEST' print ' COMB_UNRANK returns a combination of N things' print ' out of M, given the lexicographic rank.' print '' print ' The total set size is M = %d' % ( m ) print ' The subset size is N = %d' % ( n ) print ' The number of combinations of N out of M is %d' % ( cnk ) print '' print ' Rank Combination' print '' for rank in range ( 1, 4 ): a = comb_unrank ( m, n, rank ) print ' %3d' % ( rank ), for i in range ( 0, n ): print ' %5d' % ( a[i] ), print '' for rank in range ( 6, 9 ): a = comb_unrank ( m, n, rank ) print ' %3d' % ( rank ), for i in range ( 0, n ): print ' %5d' % ( a[i] ), print '' for rank in range ( 250, 253 ): a = comb_unrank ( m, n, rank ) print ' %3d' % ( rank ), for i in range ( 0, n ): print ' %5d' % ( a[i] ), print '' # # Terminate. # print '' print 'COMB_UNRANK_TEST:' print ' Normal end of execution.' return
def comp_rank_grlex(kc, xc): #*****************************************************************************80 # ## COMP_RANK_GRLEX computes the graded lexicographic rank of a composition. # # Discussion: # # The graded lexicographic ordering is used, over all KC-compositions # for NC = 0, 1, 2, ... # # For example, if KC = 3, the ranking begins: # # Rank Sum 1 2 3 # ---- --- -- -- -- # 1 0 0 0 0 # # 2 1 0 0 1 # 3 1 0 1 0 # 4 1 1 0 1 # # 5 2 0 0 2 # 6 2 0 1 1 # 7 2 0 2 0 # 8 2 1 0 1 # 9 2 1 1 0 # 10 2 2 0 0 # # 11 3 0 0 3 # 12 3 0 1 2 # 13 3 0 2 1 # 14 3 0 3 0 # 15 3 1 0 2 # 16 3 1 1 1 # 17 3 1 2 0 # 18 3 2 0 1 # 19 3 2 1 0 # 20 3 3 0 0 # # 21 4 0 0 4 # .. .. .. .. .. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 30 October 2014 # # Author: # # John Burkardt # # Parameters: # # Input, int KC, the number of parts in the composition. # 1 <= KC. # # Input, int XC[KC], the composition. # For each 1 <= I <= KC, we have 0 <= XC(I). # # Output, int RANK, the rank of the composition. # import numpy as np from i4_choose import i4_choose from i4vec_sum import i4vec_sum from sys import exit # # Ensure that 1 <= KC. # if (kc < 1): print '' print 'COMP_RANK_GRLEX - Fatal error!' print ' KC < 1' exit('COMP_RANK_GRLEX - Fatal error!') # # Ensure that 0 <= XC(I). # for i in range(0, kc): if (xc[i] < 0): print '' print 'COMP_RANK_GRLEX - Fatal error!' print ' XC[I] < 0' exit('COMP_RANK_GRLEX - Fatal error!') # # NC = sum ( XC ) # nc = i4vec_sum(kc, xc) # # Convert to KSUBSET format. # ns = nc + kc - 1 ks = kc - 1 xs = np.zeros(ks, dtype=np.int32) xs[0] = xc[0] + 1 for i in range(2, kc): xs[i - 1] = xs[i - 2] + xc[i - 1] + 1 # # Compute the rank. # rank = 1 for i in range(1, ks + 1): if (i == 1): tim1 = 0 else: tim1 = xs[i - 2] if (tim1 + 1 <= xs[i - 1] - 1): for j in range(tim1 + 1, xs[i - 1]): rank = rank + i4_choose(ns - j, ks - i) for n in range(0, nc): rank = rank + i4_choose(n + kc - 1, n) return rank
def compnz_enum(n, k): #*****************************************************************************80 # ## COMPNZ_ENUM returns the number of nonzero compositions of the N into K parts. # # Discussion: # # A composition of the integer N into K nonzero parts is an ordered sequence # of K positive integers which sum to N. The compositions (1,2,1) # and (1,1,2) are considered to be distinct. # # The 10 compositions of 6 into three nonzero parts are: # # 4 1 1, 3 2 1, 3 1 2, 2 3 1, 2 2 2, 2 1 3, # 1 4 1, 1 3 2, 1 2 3, 1 1 4. # # The formula for the number of compositions of N into K nonzero # parts is # # Number = ( N - 1 )! / ( ( N - K )! * ( K - 1 )! ) # # (Describe the composition using N-K '1's and K-1 dividing lines '|'. # The number of distinct permutations of these symbols is the number # of compositions into nonzero parts. This is equal to the number of # permutations of N-1 things, with N-K identical of one kind # and K-1 identical of another.) # # Thus, for the above example, we have: # # Number = ( 6 - 1 )! / ( ( 6 - 3 )! * ( 3 - 1 )! ) = 10 # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 14 December 2014 # # Author: # # John Burkardt # # Reference: # # Albert Nijenhuis, Herbert Wilf, # Combinatorial Algorithms for Computers and Calculators, # Second Edition, # Academic Press, 1978, # ISBN: 0-12-519260-6, # LC: QA164.N54. # # Parameters: # # Input, integer N, the integer whose compositions are desired. # # Input, integer K, the number of parts in the composition. # # Output, integer VALUE, the number of compositions of N into # K nonzero parts. # from i4_choose import i4_choose value = i4_choose(n - 1, n - k) return value
def bell(n): #*****************************************************************************80 # ## BELL returns the Bell numbers from 0 to N. # # Discussion: # # The Bell number B(N) is the number of restricted growth functions # on N. # # Note that the Stirling numbers of the second kind, S^m_n, count the # number of partitions of N objects into M classes, and so it is # true that # # B(N) = S^1_N + S^2_N + ... + S^N_N. # # Definition: # # The Bell number B(N) is defined as the number of partitions (of # any size) of a set of N distinguishable objects. # # A partition of a set is a division of the objects of the set into # subsets. # # Examples: # # There are 15 partitions of a set of 4 objects: # # (1234), (123)(4), (124)(3), (12)(34), (12)(3)(4), # (134)(2), (13)(24), (13)(2)(4), (14)(23), (1)(234), # (1)(23)(4), (14)(2)(3), (1)(24)(3), (1)(2)(34), (1)(2)(3)(4) # # and so B(4) = 15. # # First values: # # N B(N) # 0 1 # 1 1 # 2 2 # 3 5 # 4 15 # 5 52 # 6 203 # 7 877 # 8 4140 # 9 21147 # 10 115975 # # Recursion: # # B(I) = sum ( 1 <= J <= I ) Binomial ( I-1, J-1 ) * B(I-J) # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 21 December 2014 # # Author: # # John Burkardt # # Parameters: # # Input, integer N, the number of Bell numbers desired. # # Output, integer B(1:N+1), the Bell numbers from 0 to N. # import numpy as np from i4_choose import i4_choose b = np.zeros(n + 1) b[0] = 1 for i in range(1, n + 1): b[i] = 0 for j in range(1, i + 1): b[i] = b[i] + i4_choose(i - 1, j - 1) * b[i - j] return b
def perm_fixed_enum(n, m): #******************************************************************************/ # ## PERM_FIXED_ENUM enumerates the permutations of N objects with M fixed. # # Discussion: # # A permutation of N objects with M fixed is a permutation in which # exactly M of the objects retain their original positions. If # M = 0, the permutation is a "derangement". If M = N, the # permutation is the identity. # # Formula: # # F(N,M) = ( N! / M! ) * ( 1 - 1/1! + 1/2! - 1/3! ... 1/(N-M)! ) # = COMB(N,M) * D(N-M) # # where D(N-M) is the number of derangements of N-M objects. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 02 June 2007 # # Author: # # John Burkardt # # Parameters: # # Input, integer N, the number of objects to be permuted. # N should be at least 1. # # Input, integer M, the number of objects that retain their # position. M should be between 0 and N. # # Output, integer VALUE, the number of derangements of N objects # in which M objects retain their positions. # from derange_enum import derange_enum from i4_choose import i4_choose if (n <= 0): value = 1 elif (m < 0): value = 0 elif (n < m): value = 0 elif (m == n): value = 1 elif (n == 1): if (m == 1): value = 1 else: value = 0 else: value = i4_choose(n, m) * derange_enum(n - m) return value
def euler_number(n): #*****************************************************************************80 # ## EULER_NUMBER computes the Euler numbers. # # Discussion: # # The Euler numbers can be evaluated in Mathematica by the call # # EulerE[n] # # These numbers rapidly get too big to store in an ordinary integer! # # The terms of odd index are 0. # # E(N) = -C(N,N-2) * E(N-2) - C(N,N-4) * E(N-4) - ... - C(N,0) * E(0). # # First terms: # # E0 = 1 # E1 = 0 # E2 = -1 # E3 = 0 # E4 = 5 # E5 = 0 # E6 = -61 # E7 = 0 # E8 = 1385 # E9 = 0 # E10 = -50521 # E11 = 0 # E12 = 2702765 # E13 = 0 # E14 = -199360981 # E15 = 0 # E16 = 19391512145 # E17 = 0 # E18 = -2404879675441 # E19 = 0 # E20 = 370371188237525 # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 04 February 2015 # # Author: # # John Burkardt # # Reference: # # Stephen Wolfram, # The Mathematica Book, # Fourth Edition, # Wolfram Media / Cambridge University Press, 1999. # # Parameters: # # Input, integer N, the index of the last Euler number to compute. # # Output, integer E[0:N], the Euler numbers. # import numpy as np from i4_choose import i4_choose e = np.zeros(n + 1) e[0] = 1 if (0 < n): e[1] = 0 if (1 < n): e[2] = -1 for i in range(3, n + 1): e[i] = 0 if ((i % 2) == 0): for j in range(2, i + 1, 2): e[i] = e[i] - i4_choose(i, j) * e[i - j] return e
def perm_fixed_enum(n, m): # ******************************************************************************/ # ## PERM_FIXED_ENUM enumerates the permutations of N objects with M fixed. # # Discussion: # # A permutation of N objects with M fixed is a permutation in which # exactly M of the objects retain their original positions. If # M = 0, the permutation is a "derangement". If M = N, the # permutation is the identity. # # Formula: # # F(N,M) = ( N! / M! ) * ( 1 - 1/1! + 1/2! - 1/3! ... 1/(N-M)! ) # = COMB(N,M) * D(N-M) # # where D(N-M) is the number of derangements of N-M objects. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 02 June 2007 # # Author: # # John Burkardt # # Parameters: # # Input, integer N, the number of objects to be permuted. # N should be at least 1. # # Input, integer M, the number of objects that retain their # position. M should be between 0 and N. # # Output, integer VALUE, the number of derangements of N objects # in which M objects retain their positions. # from derange_enum import derange_enum from i4_choose import i4_choose if n <= 0: value = 1 elif m < 0: value = 0 elif n < m: value = 0 elif m == n: value = 1 elif n == 1: if m == 1: value = 1 else: value = 0 else: value = i4_choose(n, m) * derange_enum(n - m) return value
def mono_rank_grlex(m, x): #*****************************************************************************80 # ## MONO_RANK_GRLEX computes the graded lexicographic rank of a monomial. # # Discussion: # # The graded lexicographic ordering is used, over all monomials in # M dimensions, for total degree = 0, 1, 2, ... # # For example, if M = 3, the ranking begins: # # Rank Sum 1 2 3 # ---- --- -- -- -- # 1 0 0 0 0 # # 2 1 0 0 1 # 3 1 0 1 0 # 4 1 1 0 1 # # 5 2 0 0 2 # 6 2 0 1 1 # 7 2 0 2 0 # 8 2 1 0 1 # 9 2 1 1 0 # 10 2 2 0 0 # # 11 3 0 0 3 # 12 3 0 1 2 # 13 3 0 2 1 # 14 3 0 3 0 # 15 3 1 0 2 # 16 3 1 1 1 # 17 3 1 2 0 # 18 3 2 0 1 # 19 3 2 1 0 # 20 3 3 0 0 # # 21 4 0 0 4 # .. .. .. .. .. # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 31 October 2015 # # Author: # # John Burkardt # # Parameters: # # Input, integer M, the spatial dimension. # 1 <= M. # # Input, integer X[M], the composition. # For each 1 <= I <= M, we have 0 <= X(I). # # Output, integer RANK, the rank. # from i4_choose import i4_choose from i4vec_sum import i4vec_sum import numpy as np # # Ensure that 1 <= M. # if (m < 1): print '' print 'MONO_RANK_GRLEX - Fatal error!' print ' M < 1' sys.exit('MONO_RANK_GRLEX - Fatal error!') # # Ensure that 0 <= X(I). # for i in range(0, m): if (x[i] < 0): print '' print 'MONO_RANK_GRLEX - Fatal error!' print ' X[I] < 0' sys.exit('MONO_RANK_GRLEX - Fatal error!') # # NM = sum ( X ) # nm = i4vec_sum(m, x) # # Convert to KSUBSET format. # ns = nm + m - 1 ks = m - 1 if (0 < ks): xs = np.zeros(ks, dtype=np.int32) xs[0] = x[0] + 1 for i in range(2, m): xs[i - 1] = xs[i - 2] + x[i - 1] + 1 # # Compute the rank. # rank = 1 for i in range(1, ks + 1): if (i == 1): tim1 = 0 else: tim1 = xs[i - 2] if (tim1 + 1 <= xs[i - 1] - 1): for j in range(tim1 + 1, xs[i - 1]): rank = rank + i4_choose(ns - j, ks - i) for n in range(0, nm): rank = rank + i4_choose(n + m - 1, n) return rank
def lock ( n ): #*****************************************************************************80 # ## LOCK returns the number of codes for a lock with N buttons. # # Discussion: # # A button lock has N numbered buttons. To open the lock, groups # of buttons must be pressed in the correct order. Each button # may be pushed no more than once. Thus, a code for the lock is # an ordered list of the groups of buttons to be pushed. # # For this discussion, we will assume that EVERY button is pushed # at some time, as part of the code. To count the total number # of codes, including those which don't use all the buttons, then # the number is 2 * A(N), or 2 * A(N) - 1 if we don't consider the # empty code to be valid. # # Examples: # # If there are 3 buttons, then there are 13 possible "full button" codes: # # (123) # (12) (3) # (13) (2) # (23) (1) # (1) (23) # (2) (13) # (3) (12) # (1) (2) (3) # (1) (3) (2) # (2) (1) (3) # (2) (3) (1) # (3) (1) (2) # (3) (2) (1) # # and, if we don't need to push all the buttons, every "full button" code above # yields a distinct "partial button" code by dropping the last set of buttons: # # () # (12) # (13) # (23) # (1) # (2) # (3) # (1) (2) # (1) (3) # (2) (1) # (2) (3) # (3) (1) # (3) (2) # # First values: # # N A(N) # 0 1 # 1 1 # 2 3 # 3 13 # 4 75 # 5 541 # 6 4683 # 7 47293 # 8 545835 # 9 7087261 # 10 102247563 # # Recursion: # # A(I) = sum ( 0 <= J < I ) Binomial ( I, N-J ) * A(J) # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 23 February 2015 # # Author: # # John Burkardt # # Reference: # # Daniel Velleman, Gregory Call, # Permutations and Combination Locks, # Mathematics Magazine, # Volume 68, Number 4, October 1995, pages 243-253. # # Parameters: # # Input, integer N, the maximum number of lock buttons. # # Output, integer A(1:N+1), the number of lock codes. # import numpy as np from i4_choose import i4_choose a = np.zeros ( n + 1 ) a[0] = 1 for i in range ( 1, n + 1 ): a[i] = 0 for j in range ( 0, i ): a[i] = a[i] + i4_choose ( i, i - j ) * a[j] return a
def bell ( n ): #*****************************************************************************80 # ## BELL returns the Bell numbers from 0 to N. # # Discussion: # # The Bell number B(N) is the number of restricted growth functions # on N. # # Note that the Stirling numbers of the second kind, S^m_n, count the # number of partitions of N objects into M classes, and so it is # true that # # B(N) = S^1_N + S^2_N + ... + S^N_N. # # Definition: # # The Bell number B(N) is defined as the number of partitions (of # any size) of a set of N distinguishable objects. # # A partition of a set is a division of the objects of the set into # subsets. # # Example: # # There are 15 partitions of a set of 4 objects: # # (1234), (123)(4), (124)(3), (12)(34), (12)(3)(4), # (134)(2), (13)(24), (13)(2)(4), (14)(23), (1)(234), # (1)(23)(4), (14)(2)(3), (1)(24)(3), (1)(2)(34), (1)(2)(3)(4) # # and so B(4) = 15. # # First values: # # N B(N) # 0 1 # 1 1 # 2 2 # 3 5 # 4 15 # 5 52 # 6 203 # 7 877 # 8 4140 # 9 21147 # 10 115975 # # Recursion: # # B(I) = sum ( 1 <= J <= I ) Binomial ( I-1, J-1 ) * B(I-J) # # Licensing: # # This code is distributed under the GNU LGPL license. # # Modified: # # 06 December 2014 # # Author: # # John Burkardt # # Parameters: # # Input, integer N, the number of Bell numbers desired. # # Output, integer B(1:N+1), the Bell numbers from 0 to N. # from i4_choose import i4_choose import numpy as np b = np.zeros ( n + 1 ) b[0] = 1 for i in range ( 1, n + 1 ): b[i] = 0 for j in range ( 1, i + 1 ): b[i] = b[i] + i4_choose ( i - 1, j - 1 ) * b[i-j] return b