#!/usr/bin/perl -w use strict; main( @ARGV ); exit( 0 ); # Return the possible starting points for a new open paren: sub Starts { my( $str )= @_; my @start; my $start= 1 + rindex( $str, "(" ); pos($str)= $start; while( $str =~ /[^()]/g ) { push @start, pos($str)-1; } return @start; } # Return the possible ending points: sub Ends { my( $str, $start )= @_; pos($str)= $start; $str =~ /[^()]+/g; return $start+1 .. pos($str); } # Iterator that adds one new pair of parens: sub AddParenIter { my( $str )= @_; my @start= Starts( $str ); my @end= Ends( $str, $start[0] ); return sub { if( ! @end ) { shift @start; return if ! @start; @end= Ends( $str, $start[0] ); } my $new= $str; substr( $new, shift(@end), 0 )= ")"; substr( $new, $start[0], 0 )= "("; return $new; }; } # Iterator that adds N new pairs of parens: sub AddParensIter { my( $count, $str )= @_; my @iter= AddParenIter( $str ); return sub { my $next; while( not $next= $iter[-1]->() ) { pop @iter; return if ! @iter; } while( @iter < $count ) { push @iter, AddParenIter( $next ); $next= $iter[-1]->(); } return $next; } } sub main { die "Usage: $0 count string\n", " or: $0 M..N J..K\n" unless 2 == @_; my( $count, $str )= @_; if( $count !~ /\.\./ ) { my $iter= AddParensIter( $count, $str ); $count= 0; while( $str= $iter->() ) { print ++$count, ": $str\n"; } return; } my( $m, $n )= split /\.\./, $count; my( $j, $k )= split /\.\./, $str; print "parens\tlengths\n"; for my $len ( $j .. $k ) { printf "\t%7d", $len; } for my $parens ( $m .. $n ) { printf "\n%5d:", $parens; for my $len ( $j .. $k ) { my $iter= AddParensIter( $parens, "x"x$len ); my $count= 0; ++$count while $iter->(); printf "\t%7d", $count; } } print "\n"; } #### > parenperms 3 12 1: (((1)))2 2: ((1))(2) 3: (1)((2)) 4: (((1))2) 5: ((1)(2)) 6: (((1)2)) 7: (((12))) 8: ((1(2))) 9: (1((2))) 10: 1(((2))) #### > parenperms 1..7 1..7 parens lengths 1 2 3 4 5 6 7 1: 1 3 6 10 15 21 28 2: 1 6 20 50 105 196 336 3: 1 10 50 175 490 1176 2520 4: 1 15 105 490 1764 5292 13860 5: 1 21 196 1176 5292 19404 60984 6: 1 28 336 2520 13860 60984 226512 7: 1 36 540 4950 32670 169884 736164