#!/usr/bin/perl #jda@math.umd.edu use strict; use Data::Dumper; use Getopt::Long; use vars qw($help $quiet $outputFile $split $fundamental $parameter $cayleyString $crossString); my %options=('h' => \$help, 'o' => \$outputFile, 's' => \$split, 'f' => \$fundamental, 'p' => \$parameter, 'cayley' => \$cayleyString, 'cross' => \$crossString, 'q' => \$quiet); GetOptions(\%options,qw(h! o=s q! i=s s! f! p=s cayley=s cross=s)); my $inputFile=$ARGV[0]; &help if ($help or !$inputFile); if ($outputFile){ $quiet or print "Sending output to file $outputFile\n"; open(OUT,">$outputFile")||die("Can't open $outputFile for output"); select(OUT); } $crossString='x' unless (defined($crossString)); $cayleyString ='^' unless (defined($cayleyString)); my $rank; if ($split and $fundamental){ die("Can't use both -s (split) and -f (fundamental). Use -h for help\n"); } my $start=$split?'split':'fundamental'; my ($size,$rank,$minLength,$maxLength,$maxLengthTau,$baseParameterLength)=&getBasicData; if (length($baseParameterLength)){ if ($baseParameterLength == $minLength){ $start='fundamental'; }elsif ($baseParameterLength == $maxLength){ $start='split'; }else{ print "\nIgnoring -p: parameter length is $baseParameterLength, but maximum length=$maxLength and minimum length=$minLength"; $parameter=''; } } $start = ($start =~ /s/)?'split':'fundamental'; unless ($quiet){ if ($parameter){ print "\nStarting on parameter $parameter of $start Cartan\n"; }else{ print "\nStarting on $start Cartan\n"; } print "Data from file $inputFile\n\n"; } my $action=&action($parameter) if (length($parameter)); my ($realCayley,$imaginaryCayley)=&getCayley; my $sequence=&process; &output($realCayley,$imaginaryCayley,$sequence,$maxLengthTau,$action); sub process{ open(IN,"<$inputFile")||die("Can't open $inputFile for input"); my %step; my $C; my $cayleyTypes; my $cayleys; my $startLength; if ($start eq 'fundamental'){ $C='C-'; $cayleyTypes="r1|r2"; $startLength=$minLength; $cayleys=$realCayley; }else{ $C='C+'; $cayleyTypes="i1|i2"; $startLength=$maxLength; $cayleys=$imaginaryCayley; } my @lines; foreach my $line (){ chomp($line); # my ($space,$number,$xy,$cross,$imaginaryCayley,$types,$length,$tau)= # ($line =~ /^(\s*)([0-9\s]*)(\([0-9,\s]*\)).*:\s*([^\(]*)\((.*)\)\s*\[([^\]]*)\]\s*([0-9]*)(\s*[0-9]*)/g); # 0( 0,6): 0 0 [i1,i1] 1 2 ( 4, *) ( 5, *) e my ($space,$number,$xy,$length,$cartan,$types,$cross,$imaginaryCayley,$tau)= ($line =~ /^(\s*)([0-9\s]*)(\([0-9,\s]*\)).*:\s*([0-9]*)\s*([0-9]*)\s*\[([^\]]*)\]\s*([^\(]*)\((.*)\)\s*(.*)/g); next unless $line; push @lines,[$space,$number,$xy,$cross,$imaginaryCayley,$types,$length,$tau]; if ($start eq 'fundamental'){ @lines=sort {$a->[6] <=> $b->[6]} @lines; }else{ @lines=sort {$b->[6] <=> $a->[6]} @lines; } } close(IN); foreach my $line (@lines){ my ($space,$number,$xy,$cross,$imaginaryCayley,$types,$length,$tau)=@$line; if ($length == $startLength){ $step{$number}="[$number]"; next; } my @types=split ',', $types; my @cross = split /\s+/, $cross; foreach my $i (0..$rank-1){ if ($types[$i] eq $C){ $step{$number}=[$i,$types[$i],$cross[$i]]; last; } if ($types[$i] =~ /$cayleyTypes/){ my $cayley=$cayleys->{$number}->{$i}->[0]; $step{$number}=[$i,$types[$i],$cayley]; last; } } } my %sequence; foreach my $line (@lines){ my $i=$line->[1]; my $step=$step{$i}; unless (ref($step)){ $sequence{$i}=$step; }else{ my ($root,$type,$image)=@$step; if ($type =~ /C/){ $sequence{$i}=$root.$crossString.$sequence{$image}; }elsif ($type =~ /$cayleyTypes/){ $sequence{$i}=$root.$cayleyString.$sequence{$image}; } } } # print "\nSEQUENCE:", Dumper(\%sequence); return \%sequence; } sub getBasicData{ open(IN,"<$inputFile")||die("Can't open $inputFile for input"); my $size=0; my $minLength=1000; my $maxLength=0; my $maxLengthTau=0; my $baseParameterLength; #one run to get size, rank, max/min lengths foreach my $line (){ $line =~ s/\#.*//; next unless $line; my ($space,$number,$xy,$length,$cartan,$types,$cross,$cayley,$tau)= ($line =~ /^(\s*)([0-9\s]*)(\([0-9,\s]*\)).*:\s*([0-9]*)\s*([0-9]*)\s*\[([^\]]*)\]\s*([^\(]*)\((.*)\)\s*(.*)/g); # my ($number,$cross,$cayley,$types,$length,$tau)= # ($line =~ /^([0-9\s]*).*:\s*([^\(]*)\(\s*(.*)\)\s*\[([^\]]*)\]\s*([0-9]*)\s*([0-9]*)/g); $number =~ s/\s//g; $size=$number if ($number >$size); $minLength=$length if ($length < $minLength); $maxLength=$length if ($length > $maxLength); $maxLengthTau=length($tau) if (length($tau)>$maxLengthTau); unless ($rank){ my @cayley=split(/\)\s*\(/, $cayley); $rank=scalar(@cayley); } $baseParameterLength=$length if ($parameter eq $number); } close(IN); # $quiet or print "size: $size\nrank: $rank\nminLength: $minLength\nmaxLength: $maxLength\nmaxLengthTau: $maxLengthTau\n"; return ($size,$rank,$minLength,$maxLength,$maxLengthTau,$baseParameterLength); } sub getCayley{ my %realCayley; my %imaginaryCayley; open(IN,"<$inputFile")||die("Can't open $inputFile for input"); foreach my $line (){ my ($number,$cross,$imaginaryCayley,$types,$length,$tau)= ($line =~ /^([0-9\s]*).*:\s*([^\(]*)\(\s*(.*)\)\s*\[([^\]]*)\]\s*([0-9]*)\s*([0-9]*)/g); $line =~ s/\#.*//; next unless $line; $number =~ s/\s//g; $imaginaryCayley =~ s/\s//g; my @cross = split /\s+/, $cross; my @imaginaryCayley=split /\)\(/, $imaginaryCayley; my @types=split ',', $types; foreach my $i (0..$#imaginaryCayley){ my $cayleyPair=$imaginaryCayley[$i]; foreach my $c (split ',', $cayleyPair){ next if ($c eq '*'); push @{$realCayley{$c}->{$i}}, $number; push @{$imaginaryCayley{$number}->{$i}}, $c; } } } close(IN); unless ($quiet){ # print "REAL CAYLEY:", Dumper(\%realCayley); # print "IM CAYLEY:", Dumper(\%imaginaryCayley); } return (\%realCayley,\%imaginaryCayley); } sub output{ my ($realCayley,$imaginaryCayley,$sequence,$maxLengthTau,$action)=@_; my %realCayley=%$realCayley; my %imaginaryCayley=%$imaginaryCayley; open(IN,"<$inputFile")||die("Can't open $inputFile for input"); foreach my $line (){ chomp($line); # my ($space,$number,$xy,$cross,$imaginaryCayley,$types,$length,$tau)= # ($line =~ /^(\s*)([0-9\s]*)(\([0-9,\s]*\))(.*:\s*[^\(]*)\((.*)\)(\s*\[[^\]]*\]\s*)([0-9]*\s*)([0-9]*)/g); my ($space,$number,$xy,$length,$cartan,$types,$cross,$imaginaryCayley,$tau)= ($line =~ /^(\s*)([0-9\s]*)(\([0-9,\s]*\)).*:\s*([0-9]*)\s*([0-9]*)\s*\[([^\]]*)\]\s*([^\(]*)\((.*)\)\s*(.*)/g); $line =~ s/\#.*//; next unless $line; #put in real cayleys my @imaginaryCayley=split /\) \(/, $imaginaryCayley; foreach my $i (0..$#imaginaryCayley){ next unless ($realCayley{$number}); next unless ($realCayley{$number}->{$i}); my @realCayleyPair=@{$realCayley{$number}->{$i}}; my $c1=$realCayleyPair[0]; my $c2=$realCayleyPair[1]||"*"; my $ic=$imaginaryCayley[$i]; my @ic=split ',', $ic; my $star=$ic[0]; $c1=" "x(length($star)-length($c1)).$c1; $c2=" "x(length($star)-length($c2)).$c2; $imaginaryCayley[$i]="$c1,$c2"; } $imaginaryCayley=join ') (', @imaginaryCayley; my $tauSpace=" "x($maxLengthTau-length($tau)); $tau = $tau.$tauSpace; # $line = "$space$number$xy$cross($imaginaryCayley)$types$length$tau"; # $line = "$space$number$xy$length$cartan$types$cross$imaginaryCayley$tau"; print $line; my $seq=$sequence->{$number}; if (length($parameter)){ (my $base = $seq) =~ s/.*\[([0-9]*)\]/\1/g; # print "base:$base\n"; # print "test:$number:$action->{$number}\n"; $seq =~ s/\[$base\]/$action->{$base}/; } print "$tauSpace $seq"; print "\n"; } } sub action{ my $parameter=shift; open(IN,"<$inputFile")||die("Can't open $inputFile for input"); my $C; my $crossTypes; my $startLength; if ($start eq 'fundamental'){ $startLength=$minLength; $crossTypes='i1|i2'; }else{ $C='C+'; $startLength=$maxLength; $crossTypes='r1|r2'; } my %lines; foreach my $line (){ chomp($line); my ($space,$number,$xy,$cross,$imaginaryCayley,$types,$length,$tau)= ($line =~ /^(\s*)([0-9\s]*)(\([0-9,\s]*\)).*:\s*([^\(]*)\((.*)\)\s*\[([^\]]*)\]\s*([0-9]*)(\s*[0-9]*)/g); next unless $line; next unless ($length == $startLength); $lines{$number}=[$space,$number,$xy,$cross,$imaginaryCayley,$types,$length,$tau]; } close(IN); my %action; $action{$parameter}="[$parameter]"; my %done; my %actionTemp; while (scalar(keys %action) < scalar(keys %lines)){ foreach my $i (keys %action){ next if ($done{$i}); my $line=$lines{$i}; my $types=$line->[5]; my @types=split ',', $types; my $crosses=$line->[3]; my @crosses = split /\s+/, $crosses; foreach my $j (0..$#types){ my $type=$types[$j]; next unless ($type =~ /$crossTypes/); my $image=$crosses[$j]; next if ($action{$image}); $actionTemp{$image}=$j.$crossString.$action{$i}; } } foreach my $i (keys %actionTemp){ $action{$i}=$actionTemp{$i}; } } return \%action; } sub help{ print "This script reads a file, containing block information, and gives some additional information about sequences of Cayley transforms and cross actions. The file should be the output of the block command of atlas. Usage: blockj [-o output] [-s|-f] [--cayley ...] [--cross ...] [-p parameter] [-q] inputFile The output is the same as the output of the block command of atlas with the following changes: 1) Real Cayley transforms are listed 2) An additional column gives every parameter as a sequence of Cayley transforms and complex cross actions applied to a parameter coming from the fundamental Cartan (the default) or the split Cartan 3) If a parameter is chosen with -p, the final column instead gives every parameter as a sequence of Cayley transforms, complex cross actions, and imaginary (the default, or real) cross actions, applied to this parameter. Options: -f start on fundamental Cartan (the default) -s start on split Cartan -p parameter reduce every parameter to this one --cross X denote cross action with X (default: x) --cayley _ denote Cayley transforms with _ (default: ^) -o outputFile send output to outputFile -q quiet The parameter -p is ignored if it isn't on the fundamental or split Cartan, and overrides -s or -f if it is. Examples: blockj blockC2 Take blockC2 (output of block command of atlas),insert real Cayley transforms, and write every parameter as a series of Cayley transform/cross actions applied to a discrete series blockj blockC2 -s Same as above but start with the principal series blockj blockC2 -p 1 Same as above, but related every parameter back to the large discrete series with parameter 1 blockj blockC2 --cross X Write cross actions with X instead of x blockj blockC2 --cross '' Write cross actions with no extra character. Sample output: blockj blockC2 Starting at fundamental Cartan Data from file blockC2 0( 0,6): 1 2 ( 6, *) ( 4, *) [i1,i1] 0 [0] 1( 1,6): 0 3 ( 6, *) ( 5, *) [i1,i1] 0 [1] 2( 2,6): 2 0 ( *, *) ( 4, *) [ic,i1] 0 [2] 3( 3,6): 3 1 ( *, *) ( 5, *) [ic,i1] 0 [3] 4( 4,4): 8 4 ( *, *) ( 0, 2) [C+,r1] 1 2 1^[0] 5( 5,4): 9 5 ( *, *) ( 1, 3) [C+,r1] 1 2 1^[1] 6( 6,5): 6 7 ( 0, 1) ( *, *) [r1,C+] 1 1 0^[0] 7( 7,2): 7 6 (10,11) ( *, *) [i2,C-] 2 212 1x0^[0] 8( 8,3): 4 9 ( *, *) (10, *) [C-,i1] 2 121 0x1^[0] 9( 9,3): 5 8 ( *, *) (10, *) [C-,i1] 2 121 0x1^[1] 10(10,0): 11 10 ( 7, *) ( 8, 9) [r2,r1] 3 1212 0^1x0^[0] 11(10,1): 10 11 ( 7, *) ( *, *) [r2,rn] 3 1212 0^1x0^[0] blockj blockC2 -p 1 Starting at fundamental Cartan Data from file blockC2 0( 0,6): 1 2 ( 6, *) ( 4, *) [i1,i1] 0 0x[1] 1( 1,6): 0 3 ( 6, *) ( 5, *) [i1,i1] 0 [1] 2( 2,6): 2 0 ( *, *) ( 4, *) [ic,i1] 0 1x0x[1] 3( 3,6): 3 1 ( *, *) ( 5, *) [ic,i1] 0 1x[1] 4( 4,4): 8 4 ( *, *) ( 0, 2) [C+,r1] 1 2 1^0x[1] 5( 5,4): 9 5 ( *, *) ( 1, 3) [C+,r1] 1 2 1^[1] 6( 6,5): 6 7 ( 0, 1) ( *, *) [r1,C+] 1 1 0^0x[1] 7( 7,2): 7 6 (10,11) ( *, *) [i2,C-] 2 212 1x0^0x[1] 8( 8,3): 4 9 ( *, *) (10, *) [C-,i1] 2 121 0x1^0x[1] 9( 9,3): 5 8 ( *, *) (10, *) [C-,i1] 2 121 0x1^[1] 10(10,0): 11 10 ( 7, *) ( 8, 9) [r2,r1] 3 1212 0^1x0^0x[1] 11(10,1): 10 11 ( 7, *) ( *, *) [r2,rn] 3 1212 0^1x0^0x[1] Note: the name of this command is a pun on the atlas command blockd, which stands for \"block-David\". "; exit; }