This site is supported by donations to The OEIS Foundation.

User:R. J. Mathar/transforms3

From OeisWiki
Jump to: navigation, search
# 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:
# Seidel tranformation with parameters alpha, beta.
# @param L Input sequence
# @param alpha First multiplier
# @param beta Second multiplier
# @return The left column T(n,0) of the matrix T(0,i)=L(i), T(n,m) = alpha*T(n-1,m)+beta*T(n-1,m+1).
#   The case alpha=beta=1 is just the binomial transform.
# Richard J. Mathar, 2012-10-10 
SEIDEL := proc(L,f1,f2)
        local a,n ;
        a := [] ;
        n := nops(L) ;
        for n from 0 to nops(L)-1 do
                add(f1^(n-k)*f2^kbinomial(n,k)*op(k+1,L),k=0..n) ;
                a := [op(a),%]
        end do:
        a ;
end proc:


# Inverse Seidel tranformation with parameters alpha, beta.
# @param L Input sequence 
# @param alpha First multiplier
# @param beta Second multiplier
# @return The top row T(0,n) of the matrix T(i,0)=L(i), T(n,m) = alpha*T(n-1,m)+beta*T(n-1,m+1).
# Richard J. Mathar, 2012-10-13
SEIDELi := proc(L,f1,f2)
        SEIDEL(L,-f1/f2,1/f2) ;
end proc:

Digits := 500 ;

# Digits := 500 ;
# First Nmax terms of the signature sequence of x.
# @param x The floating point constant to be rendered.
# @param Nmax The number of terms of the signature sequence to be generated.
# @return A list of the first Nmax terms of the signature sequence.
# Richard J. Mathar, 2013-07-30
SignSeq := proc(x,Nmax)
        local Lij,i,j,k,ts,ins ;
        Lij := [] ;
        for i from 1 to Nmax do
        for j from 1 to Nmax do
                ts := i+j*x ;
                ins := 0 ;
                for k from 1 to nops(Lij) do
                        if ts > op(1,op(k,Lij))+op(2,op(k,Lij))*x then
                                ins := k ;
                        end if;
                end do:
                if ins > Nmax then
                        ;
                elif ins = 0 then
                        Lij := [[i,j],op(Lij)] ;
                elif ins = nops(Lij) then
                        Lij := [op(Lij),[i,j]] ;
                else
                        Lij := [op(1..ins,Lij),[i,j],op(ins+1..nops(Lij),Lij)] ;
                end if;
        end do:
        end do:
        [seq(op(1,op(k,Lij)),k=1..Nmax)] ;
end proc:


# Deleham's Delta function in A084938
Delta := proc(r::list,s::list,n,k)
        option remember;
        local P ,nloc,kloc,q,N,x,y;
        N := min(nops(r),nops(s)) ;
        P := Array(0..N,0..N) ;
        for kloc from 0 to N do
                P[0,kloc] := 1 ;
        end do:
        for nloc from 1 to min(N,n) do
                for kloc from 0 to N-nloc-1 do
                        q := x*op(1+kloc,r)+y*op(1+kloc,s) ;
                        if kloc > 0 then
                                P[nloc,kloc] := expand(P[nloc,kloc-1]+q*P[nloc-1,kloc+1]) ;
                        else
                                P[nloc,kloc] := expand(q*P[nloc-1,kloc+1]) ;
                        end if;
                end do:
        end do:
        coeff(coeff(P[n,0],x,n-k),y,k) ;
end proc:

DELTA := proc(r::list,s::list)
        local P ,nloc,kloc,q,N,x,y,k;
        N := min(nops(r),nops(s)) ;
        P := Array(0..N,0..N) ;
        for kloc from 0 to N do
                P[0,kloc] := 1 ;
        end do:
        printf("1,\n") ;
        for nloc from 1 to N do
                for kloc from 0 to N-nloc-1 do
                        q := x*op(1+kloc,r)+y*op(1+kloc,s) ;
                        if kloc > 0 then
                                P[nloc,kloc] := expand(P[nloc,kloc-1]+q*P[nloc-1,kloc+1]) ;
                        else
                                P[nloc,kloc] := expand(q*P[nloc-1,kloc+1]) ;
                        end if;
                        if kloc = 0 then
                                for k from 0 to nloc do
                                        printf("%d,",coeff(coeff(P[nloc,0],x,nloc-k),y,k) );
                                end do;
                        end if;
                end do:
                printf("\n") ;
        end do:
        return ;
end proc:
# @param r list of r
# @param s list of s
# @param delfcol If true delete first column of resulting array
# @param delfrow If true delete first row of resulting array
DELTAgf := proc(r::list,s::list,x,y,delfcol::boolean,delfrow::boolean)
        local N,n,g;
        N := min(nops(r),nops(s)) ;
        g := 0 ;
        for n from N to 1 by -1 do
                (op(n,r)*x+op(n,s)*x*y)/(1-g) ;
                g := factor(%) ;
        end do:
        g := 1/(1-g) ;
        if delfcol then
                g := (g-subs(y=0,g))/y;
        end if;
        if delfrow then
                g := (g-subs(x=0,g))/x;
        end if;
        g := factor(g) ;
        printf("\nG.f.: (%a)/(%a). - ~~~~\n",factor(numer(g)),factor(denom(g))) ;
        g ;
end proc:

# Count the frequency of n in the list L
# @param L The list of elements.
# @param n The needle to search for.
# @return The number of occurences of n in L.
# @since 2016-03-06
freq := proc(L::list,n::integer)
        local ct,l;
        ct := 0 ;
        for l in L do
                if l = n then
                        ct := ct+1 ;
                end if;
        end do:
        return ct;
end proc:

# The number of picking c parts of an existing set of C
# elements (optionally picking some elements more than once),
# without regard to the ordering of the elements of C.
pickP := proc(C::integer,c::integer)
        binomial(C+c-1,c) ;
end proc:
# A multiset decompositon of L.
# @param L L[1] corresponds to the n=0 elements in the first column
# @param n row index >=1 into L, to element n of the root sequence.
#   The elemen at index 0 of the root sequence is not in that list.
# @param f column index >=1 and <=n. If f=1, pick L[f] ;
# @example L=A000081 starting at n=1 gives A033185.
# @example L=A038055 starting at n=1 gives A271878.
# @example L=A000079 starting at n=1 gives A209406.
# @example L=A000055 starting at n=1 gives A095133.
# @example L=A001349 starting at n=1 gives A201922.
# @example L=A038059 starting at n=1 gives A271879.
# @example L=A000012 starting at n=1 gives A008284.
# @example L=A000027 starting at n=1 gives A089353.
# @see arxiv.org:1603.00077
MultiSet := proc(L::list,n::integer,f::integer)
        option remember ;
        local c,ct,i,cof,thisp,oldp,thisC,fr;
        if n < 0 then
                return 0;
        elif n = 0 then
                return 1;
        elif f = 1 then
                # refers to element n-1 (but maple index n)
                return op(n,L) ;
        else
                ct := 0 ;
                # cannot use combinat[partition](N,f) here because
                # f would not mean the number of parts...
                for c in combinat[partition](n) do
                        if nops(c) = f then
                                oldp := -1 ;
                                # print("N=",n,"f=",f,"c=",c) ;
                                cof := 1;
                                for i from 1 to nops(c) do
                                        thisp := op(i,c) ;
                                        thisC := procname(L,thisp,1) ;
                                        fr := freq(c,thisp) ;
                                        if thisp <> oldp then
                                                cof := cof*pickP(thisC,fr) ;
                                                # print("N=",n,"f=",f,"c=",c,"factor",pickP(thisC,fr),"from fr",fr) ;
                                                oldp := thisp ;
                                        end if;
                                end do:
                                ct := ct+cof ;
                        end if;
                end do:
                ct ;
        end if;
end proc:

MultiSetSum := proc(L::list,n::integer)
        add( MultiSet(L,n,f),f=1..n) ;
end proc:
# A labeled multiset decompositon of L.
# Luschny's Bell transform (apart from the offset)
# @param L L[1] corresponds to the n=0 elements in the first column
# @param n row index >=1 into L, to element n of the root sequence.
#   The elemen at index 0 of the root sequence is not in that list.
# @param f column index >=1 and <=n. If f=1, pick L[f] ;
# Examples: A143543 generated by A001187
# Examples: A307804 generated by A123543
# Examples: A307806 generated by A003515
# Examples: A228550 generated by A033678
# Examples: A105599 generated by A000272
# @since 2019-04-29
LblSet := proc(L::list,n::integer,f::integer)
        option remember ;
        local c,ct,i,cof ;
        if n < 0 then
                return 0;
        elif n = 0 then
                return 1;
        elif f = 1 then
                # refers to element n-1 (but maple index n)
                return op(n,L) ;
        elif f > n then
                return 0 ;
        else
                ct := 0 ;
                # i.e. partitions of n into f positive parts
                for c in combinat[composition](n,f) do
                        cof := combinat[multinomial](n,op(c)) ;
                        for i from 1 to nops(c) do
                                cof := cof*procname(L,op(i,c),1) ;
                        end do:
                        # print("n=",n,"f=",f,"parts=",c,"multi=",cof) ;
                        ct := ct+cof ;
                end do:
                ct/f! ;
        end if;
end proc:

# @param L The list a(i), i>=1, of the number of labelled structures with 1 part and i nodes
# @param n The total number of nodes
# @return the number of not necessarily connected labelled structures with n nodes
# Examples: A000012 creates A000110
# Examples: A004109 creates A002829.
# Examples: A001710 (with A001710(1)=0) generates A001205.
# Examples: A001710 starting 1,0,1,3,12... (offset 1 here) generates A108246
# Examples: A003515 generates A003514
# Examples: A059166 generates A059167
# Examples: A272905 generates A005815
# Examples: A092430 generates A007833
# Examples: A096332 generates A066537
# Examples: A079306 generates A006024
# Examples: A053941 generates A047656
# Examples: A000272 generates A001858
# @since 2019-04-29
LblSetSum := proc(L::list,n::integer)
        add( LblSet(L,n,f),f=1..n) ;
end proc:

# Inverse function of LblSetSum()
# @param L The number of lableled structures with n>=1 nodes
# @param n The index >=1 into the list of labeled structures with 1 component
# @param estim A pair of minimum andmaximum estimators for LblSetsumi()
# @return A list with a lower and upper estimate of LblSetSumi()
# @since 2019-05-05
LblSetSumiAux := proc(L::list,n::integer,estim::list)
        option remember;
        local a,Ltst ;
        if n = 0 then
                return 1 ;
        elif n = 1 then
                return op(n,L) ;
        else
                # trial and error check of the n'th component of the inverse
                a := floor((op(1,estim)+op(2,estim))/2) ;
                [seq(LblSetSumi(L,i),i=1..n-1),a] ;
                Ltst := LblSetSum(%,n) ;
                if op(1,estim) = op(2,estim) then
                        if Ltst = op(n,L) then
                                return a ;
                        else
                                error
                        end if;
                else
                        if Ltst = op(n,L) then
                                return a ;
                        elif Ltst > op(n,L) then
                                return procname(L,n,[op(1,estim),a]) ;
                        else
                                return procname(L,n,[a,op(2,estim)]) ;
                        end if;
                end if;
        end if;
end proc:

# Inverse function of LblSetSum()
# @param L The number of lableled structures with n>=1 nodes
# @param n The index >=1 into the list of labeled structures with 1 component
# @return The number of labeled structures with 1 component and n nodes.
# @since 2019-04-29
LblSetSumi := proc(L::list,n::integer)
        option remember;
        local a,Ltst ;
        if n = 0 then
                return 1 ;
        elif n = 1 then
                return op(n,L) ;
        else
                # trial and error check of the n'th component of the inverse
                # assuming that all values are non-negative in the original list
                return LblSetSumiAux(L,n,[0,op(n,L)]) ;
        end if;
end proc:

# Discriminator sequence derived from a strictly increasing sequence.
# @param L The input sequence
# @param checkSrtd If true, an additional check is run to ensure the input sequence
#    is strictly monotonic.
# @return The initial elements of the discriminator.
#   If the prameter L is not an increasing sequence, that output is the empty list.
# @since 2016-05-04
# @author R. J. Mathar
# @example with input of squares, generating A016726
# L := [seq(n^2,n=1..10)] ;
# DISCRTR(L,true) ;
#
# @example with input the cubes, generating A192429
# L := [seq(n^3,n=1..10)] ;
# DISCRTR(L,true) ;

DISCRTR := proc(L::list, checkSrtd::boolean)
        local Ldisc, i ,n ,m, el1, mworks, modset;
        # initial discriminator list

        Ldisc := [] ;
        # number of elements in input list
        n :=  nops(L) ;

        # Test that input is monotonic
        if checkSrtd then
                for i from 2 to n do
                        if op(i,L) <= op(i-1,L) then
                                return [] ;
                        end if;
                end do:
        end if:

        # compute the i'th element of the output list by considering
        # the first i elements of the input
        for i from 1 to n do
                # brute force examination of the moduli
                for m from 1 do
                        # examine all ordered pairs of input sequence
                        [seq(modp(op(el1,L),m) ,el1=1..i)] ;
                        modset := convert(%,set) ;
                        if nops(modset) = i then
                                # found an m that works: append to output
                                Ldisc := [op(Ldisc),m] ;
                                break ;
                        end if;
                end do:
        end do:

        return Ldisc ;
end proc:

# given a squence with g(x) find f(x) such that g(x)=( f(x^2)+f(x)^2)/2, according
# to the cycle index of the symmetric group with 2 elements .
# @since 2016-05-04
# @author R. J. Mathar
# @param L The input sequence with leading value 1,
#   representings g(x) = L[1] + x*L[2] + x^2*L[3]+..
# @return the truncated generating functin f
# @examples This relates A005995 with A000217 (without leading zero), or A005993 with A000027 (offset 0)
INVRTSYM2 := proc(L)
        local g,n, f,itr;
        n := nops(L) ;
        g := gfun[listtoseries](L,x) ;
        f := 1;
        for itr from 1 to n do
                f := sqrt(2*g-subs(x=x^2,f)) ;
                f := taylor(f,x=0,itr+2) ;
                f := convert(f,polynom) ;
        end do:
        f ;
end proc:

# Given sequences L1 and L2, compute the exponential convolution
# @param L1 First multiplicative squence, starting at a(1)
# @param L2 Second multiplicative sequence, starting at b(1)
# @return The multiplicative sequence defined by Lelechenko in arxiv:1405.7597
CONVE := proc(L1,L2)
        local L,n,a,pe,i,p,e,f,d ;
        L := [1] ;
        for n from 2 do
                a := 1 ;
                for pe in ifactors(n)[2] do
                        p := pe[1] ;
                        e := pe[2] ;
                        f := 0 ;
                        for d in numtheory[divisors](e) do
                                if p^d > nops(L1) or p^(e/d) > nops(L2) then
                                        return L ;
                                end if ;
                                f := f+L1[p^d]*L2[p^(e/d)] ;
                        end do:
                        a := a*f ;
                end do:
                L := [op(L),a] ;
        end do:
end proc:

# Given an ordered sequence L=[a1,a2,a3,..,ai] and g.f. (1+x^a1)*(1+x^a2)*(1+x^a3)..
# provide the sequence with that g.f.
# Which if a1, a2,a3 are parts in a partition, provide the number of
# ways n can be partitioned in distinct parts taken from the ai.
# @example: if L=[1,2,3,4,6..] = A029744, the result will be 1,1,1,2,2,2,... = A008620
# @example: if L=[1,2,3,4,5..] = A000027, the result will be 1,1,1,2,2,3,... = A000009
# @example: if L=[1,2,3,5,6] = A005117, the result will be 1,1,1,2,1,2,... = A087188
# @example: if L=[1,1,2,2,3,3,4,4..] = A008619, the result will be 1,2,3,6,9,.. = A022567
# @example: if L=[2,3,5,7,11,13] = A000040, the result will be 1,0,1,1,0 = A000586
# @example: if L=[2,3,5,7,11,13] = A109763, the result will be 1,0,2,2,.. = A280245
# @example: if L=[1,4,6,8,10,12] = A053012, the result will be 1,1,0,0.. = A226749
# @example: if L=[1,2,6,24,120] = A000142 without reps , the result will be 1,1,1,1,0,0 = A115944
# @example: if L=[4,6,9,10,14,..] = A001358 without reps , the result will be A112020
# @since 2023-03-01
# @author R. J. Mathar
DISPART := proc(L)
        local x ;
        mul( 1+x^p,p=L) ;
        taylor(%,x=0,max(op(L))) ;
        gfun[seriestolist](%) ;
end proc:

# Input represents list L=[1,a1,a2,a4,..] which means leading coefficient must be 1.
# Output contains a list of (possibly repeated) exponents b1, b2, b3 such
# that 1+a1*x+a2*x^2+a3*x^3+... = (1_x^b1)*(1+x^b2)*(1+x^3b)*..
# example: L= [seq(i,i=1..20)] = A000027 produces  [1,1,2,2,4,4,8,8,16,16,...]
#  which represents (1+x)^2*(1+x^2)^2*(1+x^4)^2*(1+x^8)^2*... =((1+x)*(1+x^2)*(1+x^3)*..)^2 and
# expresses the fact A000027 is the autoconvolution of A000012.
# @since 2023-03-01
# @author R. J. Mathar
DISPARTi := proc(L)
        local Lout,g,x,hd,ld ;
        Lout := [] ;
        g := add(op(i,L)*x^(i-1),i=1..nops(L)) ;
        while g<> 1 do
                hd := degree(g) ;
                ld := ldegree(g-1) ;
                g := g/(1+x^ld) ;
                Lout := [op(Lout),ld] ;
                if ld = 0 or nops(Lout) > 200 then
                        break ;
                end if;
                g := taylor(g,x=0,hd+1) ;
                g := convert(g,polynom) ;
        end do:
        Lout ;
end proc:

# Support function that sorts 2 lists with sort() and
# considers a list "prior" to another list if its first
# entry is numerically smaller. This is the kind of sorting values
# and i-indices in the signature sequences.
# @param l1 a list of the form [val,...] where the dots mean
#     the actual number of elements is unimportant and only the first
#     item is used.
# @param l2 a list of the form [val,...] where the dots mean
#     the actual number of elements is unimportant and only the first
#     item is used.
# @return true if the val of l1 is smaller than the val of l2.
# @since 2024-05-28
# @author R. J. Mathar
SIGSEQsort := proc(l1::list,l2::list)
        if op(1,l1) < op(1,l2) then
                return true ;
        else
                return false ;
        end if
end proc:

# Construct the signature sequnce of the constant x.
# @param x The constant defining a list of i+j*x values.
# @param vmax The maximum value of i+j*x considered for
#  evaluation. The length of the
#  signature list that will be returned grows with vmax.
# @return the list of i-values after the values of i+j*x, i,j>=1
#  i+j*,x < vmax, are sorted by the standard increasing arithmetic value.
# @example
#   For the sign. seq. of log(2), A373212 run
#   Digits := 100 ; SIGSEQ(log(2),50) ;
#   For the sign. seq. of Pi^2, A373211, run
#   Digits := 100 ; SIGSEQ(Pi^2,50) ;
# @since 2024-05-28
# @author R. J. Mathar
SIGSEQ := proc(x,vmax)
        local TBsrtd,i,j ;
        # TBsrtd contains a list of [[i1+j1*x,i1],[i2+j2*x,i2],...]
        # i.e., pairs of i+j*x and their i-indices.
        TBsrtd := [] ;
        # double loop over i and j to gather the i+j*x
        for i from 1 do
                if i > vmax then
                        break ;
                end if;
                for j from 1 do
                        if evalf(i+j*x) > vmax then
                                break ;
                        end if;
                        TBsrtd := [op(TBsrtd),[evalf(i+j*x),i]] ;
                end do:
        end do:
        # sort the values of i+j*x in natural increasing order
        sort(TBsrtd,SIGSEQsort) ;
        # extract the i-values of the sorted list
        [seq(op(2,v),v=%)] ;
end proc:

digcatL2 := proc(L1,L2)
        digcatL([op(L1),op(L2)]) ;
end proc: