This site is supported by donations to The OEIS Foundation.
User:R. J. Mathar/transforms3
From OeisWiki
# This is a file with Maple programs. Usage from within another Maple program: # read("transforms3") ; # Read the b-file, named in the argument, and return the list of the # numbers of its 2nd column. The information on the offset of the sequence # is not transmitted: the first number in the list that is returned is just # the topmost value in the b-file, which may be a(0), a(1) or another # entry depending on the offset. # # Example to get a list of prime numbers after having downloaded b000040.txt # from the OEIS web page: # a := BFILETOLIST("b000040.txt") ; # # @param bfilename The string with the input file which is read/scanned. # @since 2010-09-06 Delete non-ASCII characters in the input # Richard J. Mathar, 2010-02-20 BFILETOLIST := proc(bfilename) local a,f,bline,b,nold,n ; # List intially empty nold := -999999 ; a := [] ; f := fopen(bfilename,READ) : bline := readline(f) : # Loop over the entire b-file while bline <> 0 do # There have been files with non-ASCII characters in the past # (BOM markers of UTF codes in particular) which are difficult to detect. # The following is an attempt to treat this error case gently, # deleting non-ASCII bytes completely. bline := StringTools[Select](StringTools[IsASCII],bline) ; bline := StringTools[TrimLeft](bline) ; # Skip lines with comments if StringTools[FirstFromLeft]("#",bline ) = 1 then ; else # interpret the line contents as two integers (index and value) b := sscanf( bline,"%d %d") ; # grab the second component of each line, the value; append if nops(b) >1 then a := [op(a),op(2,b)] ; n := op(1,b) ; if n <> nold+1 and nold <> -999999 then printf("# discontinuous first column %d %d\n",nold,n) ; end if; nold := n ; end if; end if ; bline := readline(f) ; end do: fclose(f) ; RETURN(a) ; end proc: # Write the list "L" to the file "bfilename" with the first number # given the offset "offs". # # Warning: existing files are overwritten. # # Example: # L := [seq(ithprime(i),i=1..20)] ; # LISTTOBFILE("B000040.txt",L,1) ; # note capital B in the example, not in real life. # # Richard J. Mathar, 2008-03-12 LISTTOBFILE := proc(bfilename,L,offs) local n,f ; f := fopen(bfilename,WRITE) : # Loop over the list members for n from 1 to nops(L) do fprintf(f,"%d %d\n",n+offs-1, op(n,L) ) ; end do: fclose(f) ; printf("%%I A%6s\n", substring(bfilename,2..7) ) ; printf("%%H A%6s F. Lastname, <a href=\"/A%6s/%s\">Table of n, a(n) for n=%d..%d</a>\n",substring(bfilename,2..7),substring(bfilename,2..7), bfilename,offs, nops(L)+offs-1) ; RETURN() ; end proc: # Read a b-file and replace tabs by spaces and <cr><lf> combinations # by <lf>. Remove empty lines. # The argument bfilename should be a readable b-file name b??????.txt # (no directory component). The result will be placed in a file named # B??????.txt (so that's just the first letter replaced by a capital-B), which is # overwritten if existing. # Richard J. Mathar, 2009-03-10 BFILE2BFILE := proc(bfilename) local f,fo,bline,b,n,boutname ; f := fopen(bfilename,READ) : boutname := sprintf("B%6s.txt", substring(bfilename,2..7) ) ; fo := fopen(boutname,WRITE) : bline := readline(f) : # Loop over the entire b-file; eliminate trailing blank lines while bline <> 0 do # copy lines with comments if StringTools[FirstFromLeft]("#",bline ) <> 0 then fprintf(fo,"%s\n",bline ) ; else # interpret the line contents as two integers (index and value) b := sscanf( bline,"%d %d") ; if nops(b) >=2 then # grab the second component of each line, the value; append fprintf(fo,"%d %d\n",op(1,b), op(2,b) ) ; fi; end if ; bline := readline(f) ; end do: fclose(f) ; fclose(fo) ; RETURN() ; end: # Convert a floating point constant to a sequence of decimal digits. # @param c the floating point constant # @return the list with zeros retained according to OEIS guidelines. # The length of the list depends on the value of Digits # at the time of the call. Two digits are chopped off as we assume # that the value of the constant would typically be rounded, not # truncated. # # Examples: # CONSTTOLIST(3.14159) ; # returns [3,1,4,1,5,9,0,0,...] # CONSTTOLIST(59) ; # returns [5,9,0,0,0,..] # # Richard J. Mathar, 2008-09-19 CONSTTOLIST := proc(c) local absc,a,dgs; # ensure it is the positive value, if negative absc := abs(c) ; a := [] ; # for numbers < 0.1, start with the zeros to maintain offset 0 while absc < 0.1 do a := [op(a),0] ; absc := 10*absc ; end do: # dgs is the number of digits of absc before the decimal point, the number that remains to be printed dgs := 1+ilog10(absc) ; # dgs is the number of places we want to shift absc to the right, truncating two more digits than DIGITS dgs := Digits-2-dgs ; absc := floor(absc*10^dgs) ; a := [op(a),op(ListTools[Reverse](convert(absc,base,10)))] ; RETURN(a) ; end proc: # Convert a floating point constant to a sequence of digits in base b. # @param c the floating point constant # @param b the base (2, 3,... ) # @return the list with zeros retained according to OEIS guidelines. # The length of the list depends on the value of Digits # at the time of the call. Two digits are chopped off as we assume # that the value of the constant would typically be rounded, not # truncated. # # Examples: # CONSTTOLIST(evalf(Pi/3),2) ; # returns 1,0,0,0,0,1,... (See A019670) # CONSTTOLIST(59,2) ; # # Richard J. Mathar, 2009-02-06 CONSTTOLISTB := proc(c,b) local absc,a,dgs; # ensure it is the positive value, if negative absc := abs(c) ; a := [] ; # for numbers < 0.1, start with the zeros to maintain offset 0 while absc < 1/b do a := [op(a),0] ; absc := b*absc ; end do: # dgs is the number of digits of absc before the decimal point, the number that remains to be printed dgs := 1+floor(log(absc)/log(b)) ; # dgs is the number of places we want to shift absc to the right, truncating two more digits than DIGITS dgs := Digits-2-dgs ; absc := floor(absc*b^dgs) ; a := [op(a),op(ListTools[Reverse](convert(absc,base,b)))] ; RETURN(a) ; end proc: # Convert a sequence to a floating point constant. # The arguments are the list and the (correct) offset. # Richard J. Mathar, 2009-02-02 LISTTOCONST := proc(L,offs) local c,n,dgs,realdigs ; c := 0 ; dgs := 0 ; for n from 1 to nops(L) do if dgs = 0 then if op(n,L) <> 0 then dgs := 1 ; end if; else dgs := dgs+1 ; end if; c := 10*c+op(n,L) ; end do: # Set effective precision for the floating point conversion to # what the list's length (after removing leading zeros) offers. realdigs := Digits ; Digits := dgs ; c := evalf( c*10^(offs-nops(L)) ) ; Digits := realdigs ; RETURN(c) ; end proc: # Motzkin transform of the sequence provided by the list L. # This is equivalent to replacing the independent variable x in the # generating function for L by x*M(x), where M(x) is the generating # function for the Motzkin numbers. # # Examples: # L := [0,1,0,0,0,0,0,0,0] ; Motzkin(L) ; # returns [0,1,1,2,4,9,21,51,27] # L := [0,1,0,1,0,1,0,1,0,1] ; Motzkin(L) ; # returns [0,1,1,3,7,19,51,141,393,1107,...] # L := [1,0,1,0,1,0,1,0,1] ; Motzkin(L) ; # returns [1,0,1,2,6,16,45,126,357,1016,2907,...] # # Richard J. Mathar, 2008-11-07 MOTZKIN := proc(L) local d, bgf, mL, maxd; # output list intially empty # maximum degree of output is limited by initial length of L maxd := nops(L)-1 ; # generate an auxiliary list of Motzkin numbers mL := taylor( (1-x-sqrt(1-2*x-3*x^2))/2/x, x=0,maxd+2) ; bgf := op(1,L) ; for d from 1 to maxd do bgf := bgf+taylor(op(d+1,L)*mL^d,x=0,maxd+1) ; end do: [seq(coeftayl(bgf,x=0,d),d=0..maxd)] ; end proc: # Inverse Motzkin transform of the sequence provided by the list L. # The inverse of the operation given by MOTZKIN above. # # Richard J. Mathar, 2008-11-08 MOTZKINi := proc(L) local d, bgf, mL, maxd; # output list intially empty # maximum degree of output is limited by initial length of L maxd := nops(L)-1 ; # generate an auxiliary list of Motzkin numbers mL := taylor( x/(1+x+x^2), x=0,maxd+2) ; bgf := op(1,L) ; for d from 1 to maxd do bgf := bgf+taylor(op(d+1,L)*mL^d,x=0,maxd+1) ; end do: [seq(coeftayl(bgf,x=0,d),d=0..maxd)] ; end proc: # Catalan transform of the sequence provided by the list L. # This is equivalent to replacing the independent variable x in the # generating function for L by x*C(x), where C(x) is the generating # function for the Catalan numbers. # # Richard J. Mathar, 2008-12-17 CATALAN := proc(L) local d, bgf, cL, maxd; # output list intially empty # maximum degree of output is limited by initial length of L maxd := nops(L)-1 ; # generate an auxiliary list of Catalan numbers cL := taylor( (1-sqrt(1-4*x))/2, x=0,maxd+2) ; bgf := op(1,L) ; for d from 1 to maxd do bgf := bgf+taylor(op(d+1,L)*cL^d,x=0,maxd+1) ; end do: [seq(coeftayl(bgf,x=0,d),d=0..maxd)] ; end proc: # Inverse Catalan transform of the sequence provided by the list L. # The inverse of the operation given by CATALAN above. # Richard J. Mathar, 2008-12-11 CATALANi := proc(L) local d, bgf, cL, maxd; # output list intially empty # maximum degree of output is limited by initial length of L maxd := nops(L)-1 ; cL := taylor( x*(1-x), x=0,maxd+2) ; bgf := op(1,L) ; for d from 1 to maxd do bgf := bgf+taylor(op(d+1,L)*cL^d,x=0,maxd+1) ; end do: # bug in Maple 9: the following line is necessary to get correct results bgf := taylor(bgf,x=0,maxd+1) ; [seq(coeftayl(bgf,x=0,d),d=0..maxd)] ; end proc: # Pierce sequence generated from a constant. # The input is a number between 0 and 1, the output the list of Pierce # expansion coefficients. # Richard J. Mathar, 2009-01-21 PIERCE := proc(c) local resid,L,i,an ; resid := c ; L := [] ; if whattype(c) = `float` then if c >0 and c <= 1 then for i from 1 do an := floor(1./resid) ; L := [op(L),an] ; resid := evalf(1.-an*resid) ; if ilog10( mul(i,i=L)) > 0.7*Digits then break ; end if ; end do: end if; end if; L ; end proc: # Engel sequence generated from a constant. # The input is a number between 0 and 1, the output the list of Engel # expansion coefficients. # Richard J. Mathar, 2009-07-30 ENGEL := proc(c) local resid,L,i,an ; resid := c ; L := [] ; if whattype(c) = `float` then if c > 1 then RETURN( [1,op(procname(c-1.))] ) ; elif c >0 and c <= 1 then for i from 1 do an := ceil(1./resid) ; L := [op(L),an] ; resid := evalf(an*resid-1.) ; if ilog10( mul(i,i=L)) > 0.7*Digits then break ; end if ; end do: end if; end if; L ; end proc: # Beatty sequence generated from a constant. # Richard J. Mathar, 2009-05-20 BEATTY := proc(c) local L,n,x ; L := [] ; x := evalf(c) ; for n from 1 to 0.8*Digits do L := [op(L),floor(n*x)] ; end do: L ; end proc: # L-Schroeder transform of the sequence provided by the list L. # This is equivalent to replacing the independent variable x in the # generating function for L by x*S(x), where S(x) is the generating # function for the large Schroeder numbers. # # Richard J. Mathar, 2008-11-13 SCHROEDER := proc(L) local d, bgf, mL, maxd; # output list intially empty # maximum degree of output is limited by initial length of L maxd := nops(L)-1 ; # generate an auxiliary list of Schroeder numbers mL := taylor( (1-x-sqrt(1-6*x+x^2))/2, x=0,maxd+2) ; bgf := op(1,L) ; for d from 1 to maxd do bgf := bgf+taylor(op(d+1,L)*mL^d,x=0,maxd+1) ; end do: [seq(coeftayl(bgf,x=0,d),d=0..maxd)] ; end proc: # Inverse L-Schroeder transform of the sequence provided by the list L. # This is equivalent to replacing the independent variable x in the # generating function for L by x*(1-x)/(1+x). # # Example: if L is A001850, the funtion returns a list of 1 followed # by A001333. # Richard J. Mathar, 2008-11-13 SCHROEDERi := proc(L) local d, bgf, mL, maxd; # output list intially empty # maximum degree of output is limited by initial length of L maxd := nops(L)-1 ; # generate an auxiliary list of Schroeder numbers mL := taylor( (1-x)*x/(1+x), x=0,maxd+2) ; bgf := op(1,L) ; for d from 1 to maxd do bgf := bgf+taylor(op(d+1,L)*mL^d,x=0,maxd+1) ; end do: [seq(coeftayl(bgf,x=0,d),d=0..maxd)] ; end proc: # Reduce the list given by the argument L to a list in which immediately repeated # numbers (ie, clusters of the same numbers) are reduced to a single occurrence. # # Example: if L contains [3,5,6,7,7,8,3,3,3,10], # then the list returned is [3,5,6,7,8,3,10], where "7,7" has shrunk to "7" # and "3,3,3" has shrunk to "3". # # Richard J. Mathar, 2008-05-03 LISTNODUPL := proc(L) local b, a, aprev; # output list intially empty b := [] ; # Note that aprev is not initialized to avoid a coincidental equality with L[1]. for a in L do if a <> aprev then b := [op(b),a] ; end if ; aprev := a ; end do: RETURN(b) ; end proc: # Reduce the list given by the argument "L" to a list which only contains clusters # of 2 or more repeated numbers. The argument "multpl" is either a number # larger than 0 which specifies the multiplicity (cluster length) which the # repetitions need to have (exactly) to enter the new list, or is 0 (zero) # to indicate that any cluster length of 2 or more will have one representative # be put on the list returned. # # Example: If L contains [3,5,7,7,8,3,3,3,10,7,7,7,11] # then the list returned by LISTDUPL(L,2) is [7], which represents the # first of the two clusters with 7's. # Example: If L contains [3,5,7,7,8,3,3,3,10,7,7,7,11] # then the list returned by LISTDUPL(L,3) is [3,7], which represents the # cluster with the 3's and the 2nd cluster with the 7's, each showing # numbers repeated 3 times. # Example: If L contains [3,5,7,7,8,3,3,3,10,7,7,7,11,11] # then the list returned by LISTDUPL(L,0) is [7,3,7,11], which represents the # cluster with the two 7's, the 2nd cluster with the 3's, the 2nd cluster # with 7's, and the final cluster with 11's. # Example: If L contains [3,5,7,7,8,3,3,3,10,7,7,7,11,11] # then the list returned by LISTDUPL(L,1) is [3,5,8,10], which represents the # isolated numbers (numbers in clusters of length 1). # # To obtain results which register repeated numbers without regard to # their placement in the original list, these may be sorted before calling # the routine: LISTDUPL(sort(L),multpl) ; # # Richard J. Mathar, 2008-05-03 LISTDUPL := proc(L,multpl) local b, a, aprev, cnt; if multpl < 0 then ERROR("negative multiplicity ",args[2]) ; end if ; # output list intially empty b := [] ; cnt :=0 ; aprev := op(1,L) ; for a in L do if a <> aprev then if ( cnt = multpl and multpl >0 ) or (cnt > 1 and multpl = 0 ) then b := [op(b),aprev] ; end if ; cnt := 1 ; else cnt := cnt+1 ; end if ; aprev := a ; end do: # At that time, aprev represents a number in the last cluster. Since # the lists in the OEIS are generally incomplete at the end, the following # check on the length of this last cluster is not executed, because # the length of this cluster might actually be larger than the list # representatives tell; this may lead to misinterpretations if the lists # are "full"! # if ( cnt = multpl and multpl >0 ) or (cnt > 1 and multpl = 0 ) then # b := [op(b),aprev] ; # end if ; if cnt > 1 and multpl = 0 then b := [op(b),aprev] ; end if ; RETURN(b) ; end proc: # Lehmer's cotangent representation of an irrational number. # Example # CONSTTOCOT(evalf(Pi)); # see A002667 # CONSTTOCOT(evalf(log(2))); # see A081785 # Fritz Schweiger, Metrische Ergebnisse ueber den Kotangensalgorithmus, Acta Arith. 26 (1975) 217 CONSTTOCOT := proc(x) local L,xcut ; xcut := x ; L := [floor(xcut)] ; while type(L[-1],'infinity') = false do arccot(L[-1])-arccot(xcut) ; xcut := cot(evalf(%) ) ; L := [op(L),floor(xcut)] ; end do; return subsop(-1=NULL,L) ; end proc: # LOG transformation operation on o.g.f. # The input list L represents [a0=1,a1,a2,a3,a4....] of an ordinary # generating function, g=1+a1*x+a2*x^2+.... This is to say that the first # element of L is tacitly assumed to be equal to 1. # # The output contains the coefficients of log(g) = sum_{i=1..inf} b(i)*x^i/i . # Richard J. Mathar, 2009-03-13 OLOG := proc(L) local x,gf,gfl,i,a; gf := add( op(i,L)*x^(i-1),i=2..nops(L)) ; gfl := 0 ; for i from 1 to nops(L) do gfl := taylor(gfl+gf^i/i,x=0,nops(L)) ; end do: a := [] ; for i from 1 to nops(L)-1 do a := [op(a), i*coeftayl(gfl,x=0,i)] ; end do: a; end proc: # Akiyama-Tanigawa algorithm, one step # The input list L with L[0], L[1] is transformed to the output list # A[0], A[1] as described in # D. Merlini, R. Sprugnoli, M. C. Verri, The Akiyama-Tanigawa Transformation, Integers, 5 (1) (2005) #A05 # Richard J. Mathar 2010-12-02 AKIYATANI := proc(L) local a,k ; a := [] ; for k from 1 to nops(L)-1 do a := [op(a),k*(op(k,L)-op(k+1,L))] ; end do; a ; end proc: # Akiyama-Tanigawa algorithm, generate first column. # The input list L is iteratively transformed to construct the first columnof the table. # D. Merlini, R. Sprugnoli, M. C. Verri, The Akiyama-Tanigawa Transformation, Integers, 5 (1) (2005) #A05 # Richard J. Mathar 2010-12-02 AKIYAMATANIGAWA := proc(L) local a,r,img ; a := [op(1,L)] ; img := L ; for r from 1 to nops(L)-1 do img := AKIYATANI(img) ; a := [op(a),op(1,img)] ; end do; a ; end proc: # Inverse Akiyama-Tanigawa tabulation: generate top row given the column k=0. # Richard J. Mathar 2010-12-02 AKIYAMATANIGAWAi := proc(L) local a,r,img,k,row ; img := [op(-1,L)] ; for r from nops(L)-1 to 1 by -1 do row := [op(r,L)] ; for k from 2 to 1+nops(L)-r do op(k-1,row)-op(k-1,img)/(k-1) ; row := [op(row),%] ; end do; img := row ; end do; img ; end proc: # Given the left entry d(x) and the right entry h(x) of the Riordan array, # compute the (n,k) element of the array. # @param d a function of x # @param h a function of x # @param n the row index >=0 # @param k the column index >=0 # Richard J. Mathar 2011-01-09 RIORDAN := proc(d,h,n,k) d*h^k ; expand(%) ; coeftayl(%,x=0,n) ; end proc: RIORDANEXP := proc(d,h,n,k) RIORDAN(d,h,n,k)*n!/k! ; end proc: # Generate a list of multinomial partitions. # @param n The sum of the first moment of the parts, sum_j j*p_j = n # @param k The sum of the parts, sum_j p_j = k # @param nparts The number of parts, sum_j 1 = nparts # @param zIsPart If true, the constrained is 0<=p_j, other wise 1<=p_j. # @return A list of the form [[p_1,p_2,p_3,...],[p_1,p_2,p_3,...]] # where each of the sublists is a partition in nparts obeying the two constraints. # There no other restrictions but p_j<=k. Some of the p_j may be equal. # Richard J. Mathar, 2011-04-06 multinomial2q := proc(n::integer,k::integer,nparts::integer,zIsPart::boolean) local lpar ,res, constrp; res := [] ; if n< 0 or nparts <= 0 then ; elif nparts = 1 then if n = k then if n > 0 or zIsPart then return [[n]] ; end if; end if; else for lpar from `if`(zIsPart,0,1) do if lpar*nparts > n or lpar > k then break; end if; # recursive call, assuming that lpar is the last part for constrp in procname(n-nparts*lpar,k-lpar,nparts-1,zIsPart) do if nops(constrp) > 0 then res := [op(res),[op(constrp),lpar]] ; end if; end do: end do: end if ; return res ; end proc: # Generate a list of multinomial partitions. # @param n The sum of the first moment of the parts, sum_j j*p_j = n # @param k The sum of the parts, sum_j p_j = k # @param zIsPart If true, the constrained is 0<=p_j, other wise 1<=p_j. # @return A list of the form [[p_1,p_2,p_3,...],[p_1,p_2,p_3,...]] # where each of the sublists is a partition obeying the two constraints. # There are no other restrictions but 1<=p_j<=k. Some of the p_j may be equal. # The Bell polynomials of the second kind are an application of this. # Note that ordering in the sublists matters. # Empty partitions (in case n=k=0) are not returned as empty sublists but not returned at all. # Example: # multinomial2(10,5,false) returns [[1,3,1],[2,1,2]] where 1+3+1=5, 1+2*3+3*1= 10 # for the first sublist and 2+1+2=5, 2+2*1+3*2=10 for the second sublist. # Richard J. Mathar, 2011-04-06 multinomial2 := proc(n::integer,k::integer,zIsPart::boolean) local npart,res,constrp ; res := [] ; for npart from 1 do # The smallest part is 1. So sum_j j*p_j >= npart*(npart+1)/2 =n means # that the number of parts is restricted by n, only to a lesser degree # by k. if npart*(npart+1)/2 > n or npart > k then return res; end if; # loop over the partitions with fixed number of parts and # attach those solultions to the result vector for constrp in multinomial2q(n,k,npart,zIsPart) do if nops(constrp) > 0 then res := [op(res),constrp] ; end if ; end do: end do: end proc: # Bell polynomial of the second kind. # @param n # @param k # @param x The vector of x1,x2,x3... # @return sum_{j1+j2+..=k, j1+2*j2+.. =n} n!/(j1!j2!..) (x1/1!)^j1 (x2/2!)^j2 ... # Richard J. Mathar, 2011-04-06 bell2 := proc(n::integer,k::integer,x::list) local p,npart,b,m,j; npart := nops(x) ; b := 0 ; for p in multinomial2q(n,k,npart,true) do m := 1 ; for j from 1 to nops(p) do m := m*(op(j,x)/j!)^op(j,p)/op(j,p)! ; end do: b := b+ n!*m ; end do: return b; end proc: