#!/usr/bin/perl ## Copyright 2003 Hal Canary ## ## I PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, ## EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ## THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ## PARTICULAR PURPOSE. In particular, this program might not ## do what it purports to do. The algorithm upon which it is ## based may not be mathematically sound. Or I could have ## made a mistake converting mathematical formulas into code. ## ## This is free software, and you are welcome to redistribute ## it _ONLY_ under the terms of the GPL. See ## http://www.gnu.org/copyleft/gpl.txt ## for more information. # Revision history: # *hwc 2003-09-13 - created. # *hwc 2003-09-14 - Add better comments. # *hwc 2003-09-15 - Multiple arguments. ## # This is a recursivly defined function that returns the number # of perfect matchings on a snake graph. # Argument: a string describing the snake, such as 'e' or 'erur' # In general, it is a string beginning with 'e' followed by # any number of 'u's or 'r's. ## sub countsnake { my $snake = shift; # N(e) = 2 if ($snake eq 'e') { return 2; } # N(er) = N(eu) = 3 elsif (($snake eq 'er') or ($snake eq 'eu')) { return 3; } $len = length($snake); if ($len%2 == 1) { # k = (length - 1)/2 # N(e(ru)^k) = 2k + 2 if ($snake eq 'e'.'ru'x(($len-1)/2)) { return $len+1; } # N(e(ur)^k) = 2k + 2 elsif ($snake eq 'e'.'ur'x(($len-1)/2)) { return $len+1; } } else { # N(eu(ru)^k) = 2k + 3 if ($snake eq 'eu'.'ru'x(($len/2)-1) ) { return $len+1; } # N(er(ur)^k) = 2k + 3 elsif ($snake eq 'er'.'ur'x(($len/2)-1) ) { return $len+1; } } if ($snake =~ m/rr\z/ ) { ## N(xrr) = N(xr) + N(x) [11] my $xr = $snake; $xr =~ s/rr\z/r/; my $x = $snake; $x =~ s/rr\z//; return &countsnake($xr) + &countsnake($x); } elsif ($snake =~ m/uu\z/ ) { ## N(xuu) = N(xu) + N(x) [11] my $xu = $snake; $xu =~ s/uu\z/u/; my $x = $snake; $x =~ s/uu\z//; return &countsnake($xu) + &countsnake($x); } ## N(xr(ru)^k) = (2 * k * N(x)) + N(xr) [15] my $counter = 0; while($counter < $len/2) { $counter++; $pattern = 'r'.('ru'x$counter); if (substr($snake, -length($pattern)) eq $pattern) { my $x = substr($snake,0,-length($pattern)); return 2*$counter*&countsnake($x) + &countsnake($x.'r'); } $pattern = 'u'.('ur'x$counter); if (substr($snake, -length($pattern)) eq $pattern) { my $x = substr($snake,0,-length($pattern)); return 2*$counter*&countsnake($x) + &countsnake($x.'u'); } ## N(xr(ru)^{k}r) = ((2k+1) * N(x)) + N(xr) [17] $pattern = 'rr'.('ur'x$counter) ; if (substr($snake, -length($pattern)) eq $pattern) { my $x = substr($snake,0,-length($pattern)); return (2 * $counter + 1) * &countsnake($x) + &countsnake($x.'r'); } $pattern = 'uu'.('ru'x$counter) ; if (substr($snake, -length($pattern)) eq $pattern) { my $x = substr($snake,0,-length($pattern)); return (2 * $counter + 1) * &countsnake($x) + &countsnake($x.'u'); } } ## Should never get here unless code buggy or there ## is a case I missed. Or if there is bad input. return '9999999'; } ## # This function is a frontend to the &countsnake function. # It prints the output nicely. ## sub printsnake { my $snake = shift; print 'N('.$snake.") = ".&countsnake($snake) ." \n"; } ## # main part of program starts here. ## if ($ARGV[0]) { if ($ARGV[0] eq 'all') { $low = $ARGV[1]; $high = $ARGV[2]; if ($high eq '') { print "useage: $0 all [number] [number]\n\n"; exit 1; } foreach my $length ($low..$high) { my $part = 'u'x$length; my $i=0; &printsnake("e$part"); while ($part ne 'r'x$length){ #print "\t * ".substr($part,$i,1)."\n"; if (substr($part,$i,1) eq 'u'){ substr($part,$i,1) = 'r'; while ($i > 0) { $i--; substr($part,$i,1) = 'u'; } &printsnake("e$part"); } else { $i++; } } } } else { # Undocumented easter egg. You can pass in many # arguments at once. foreach $x (@ARGV) { &printsnake($x); } } } else { print "\n Usage: \n perl snake-counting [snake]\n\n"; print " where [snake] is a string beginning with 'e'\n"; print " followed by any number of 'u's or 'r's.\n"; print "\n Example: \n perl snake-counting eruurr\n\n"; } # Examples of useage. # perl snake-counting 'e' # perl snake-counting 'er' # perl snake-counting 'eu' # perl snake-counting 'eru' # perl snake-counting 'errr' # perl snake-counting 'erururr' # perl snake-counting 'erurururrurur' # perl snake-counting 'er' # perl snake-counting 'err' # perl snake-counting 'errr' # perl snake-counting 'errrr' # perl snake-counting 'errrrr' # perl snake-counting 'errrrrr' # perl snake-counting 'errrrrrr' # perl snake-counting 'errrrrrrr' # perl snake-counting 'errrrrrrrr' # perl snake-counting 'errrrrrrrrr' # perl snake-counting 'errrrrrrrrrr' # perl snake-counting 'errrrrrrrrrrr'