#!/usr/bin/perl =head1 Name panGenomeAnalysis.pl =head1 Description run pan- and core-genome analysis from ortholog groups output file. =head1 Version Author: Lifu Song (lifu.song@tuhh.de) Version: 1.1 =head1 Usage perl panGenomeAnalysis.pl [options] input_file -run run core/pan (runcp) or run new genes (default) -gnumer Specific the total genome number of input file -clunum Specific the total cluster number of the input file -samples How many random samples will be outputed. =head1 Exmple 1. Run core and pan analysis: perl panGenomeAnalysis.pl -run runcp -gnumber 67 -clunum 3000 -samples 1000 input > output 2. Run new genes analysis: perl panGenomeAnalysis.pl -run newgene -gnumber 67 -clunum 3000 -samples 1000 input > output =cut use strict; use Getopt::Long; use Data::Dumper; use Math::Combinatorics; use List::Util qw/sum/; my $run; my $g_number; my $clu_num; my $total_genes_file; my $samples; my $help; GetOptions( "run:s"=>\$run, "gnumber:i"=>\$g_number, "clunum:i"=>\$clu_num, "totalgenes:s"=>\$total_genes_file, "samples:i"=>\$samples, "help"=>\$help ); die `pod2text $0` if (@ARGV==0 || $help); my $in=shift; my @data; open(IN,$in)||die("can not open the input file!\n"); while(){ chomp; s/\a//; my @a; my $i; @a=split(/\t/,$_); for($i=1;$i<$g_number+1; $i++){ if(!$a[$i]){$a[$i]=0;} push(@{$data[$i-1]},$a[$i]); } } my @arr_spec_genes_num; open(TO,"$total_genes_file")||die("cannot open total genes number file\n!"); my $ss=0; while(){ chomp; if($_){ my @arr=split(/\t/); push(@arr_spec_genes_num, $arr[1] - sum(@{$data[$ss]}) ); $ss++; } } warn "Data loaded!\n"; if($run eq "runcp"){&runCP;} else{&runNewGene;} sub runCP(){ warn "Starting to run the core & pan analysis......\n"; my $i; for($i=1;$i<=$g_number; $i++){ if(&combCount($i,$g_number) <= $samples*2){ my $combinat=Math::Combinatorics->new(count => $i, data => [@data]); my @combo=(); my %spec; my $sx; my $ii; for($ii=0;$ii<@data;$ii++){ $spec{$data[$ii]}= $arr_spec_genes_num[$ii]; } while(@combo=$combinat->next_combination){ print "$i\t"; print coreFix(\@combo); print "\t"; print core(\@combo); print "\t"; my $ttt=(int(pan(\@combo))+ int(&allSpec(\@combo,\%spec))); print "$ttt"; print "\n"; } }else{ my @arr_samples=randConm($samples,$i,$g_number); my $sX; foreach $sX (@arr_samples){ my $sY; my $spec_genes=0; my @combo=(); foreach $sY (@{$sX}){ push(@combo,$data[$sY]); $spec_genes+=$arr_spec_genes_num[$sY]; } print "$i\t"; print coreFix(\@combo); print "\t"; print core(\@combo); print "\t"; print pan(\@combo)+$spec_genes; print "\n"; } } } } sub runNewGene(){ warn "Starting to run the new genes analysis......\n"; my $i; for($i=2;$i<=$g_number; $i++){ if(&newCount($i) <= $samples ){ my $combinat=Math::Combinatorics->new(count => $i-1, data => [@data]); my @combo=(); while(@combo=$combinat->next_combination){ my $j=0; for($j=0;$j<$g_number;$j++){ if(!isInArr(\@combo,$data[$j])){ print "$i\t"; print newgenes(\@combo,$data[$j]) +$arr_spec_genes_num[$j]; print "\n";}else{} } } }else{ my @arr_samples=randConmN($samples,$i,$g_number); my $sX; foreach $sX (@arr_samples){ my $sY; my @combo=(); my $newGn=shift(@{$sX}); my $newGenome=$data[$newGn]; foreach $sY (@{$sX}){ push(@combo,$data[$sY]); } print "$i\t"; print newgenes(\@combo,$newGenome)+$arr_spec_genes_num[$newGn]; print "\t"; print "\n"; } } } } sub isInArr(){ my $arr=shift; my $ele=shift; my $sItem; foreach $sItem (@{$arr}){ if($sItem eq $ele){ return 1; } } return 0; } sub combCount(){ my $a=shift; my $b=shift; return nn($b)/(nn($a)*nn($b-$a)); } sub newCount(){ my $a=shift; my $b=shift; return nn($b)/(nn($a)*nn($b-$a-1)); } sub nn(){ my $n=int(shift); if($n>1){ return $n* &nn($n-1); }else{return 1} } sub allSpec(){ my $combo=shift; my $spec=shift; my $sx; my $total=0; foreach $sx(@{$combo}){ $total += $spec->{$sx}; } return $total; } sub newgenes(){ my $data=shift; my $newgenome=shift; my $i; my $newGnum=0; for($i=0;$i<$clu_num;$i++){ my $tmp=0; my $j; for($j=0;$j<= $#{$data};$j++){ $tmp+=$data->[$j]->[$i]; } if($newgenome->[$i] > 0 and $tmp <=0){ $newGnum+=$newgenome->[$i]; } } return $newGnum; } sub core(){ my $d=shift; my $c_size=0; my $i; for($i=0;$i<$clu_num;$i++){ my @tmp=(); my $j; for($j=0;$j<=$#{$d};$j++){ push(@tmp,$d->[$j]->[$i]); } $c_size+=c(@tmp); } return $c_size; } sub coreFix(){ my $d=shift; my $c_size=0; my $i; for($i=0;$i<$clu_num;$i++){ my @tmp=(); my $j=0; for($j=0;$j<= $#{$d};$j++){ push(@tmp,$d->[$j]->[$i]); } my @tmp2=(); for($j=0;$j<$g_number;$j++){ push(@tmp2,$data[$j]->[$i]); } $c_size+=cFix(\@tmp,\@tmp2); } return $c_size; } sub pan(){ my $d=shift; my $p_size=0; my $i; for($i=0;$i<$clu_num;$i++){ my @tmp=(); my $j; for($j=0;$j<@{$d};$j++){ push(@tmp,$d->[$j]->[$i]); } $p_size+=p(@tmp); } return $p_size; } sub cFix(){ my $a=shift; my $b=shift; my $c=$a->[0]; my $sx; foreach $sx (@{$a}){ if($sx<$c){$c=$sx;} } if($c > 0){return $c;}else{ if(&zeroNum($b) > 1){return 0;}else{ if($b->[0]*$b->[1]*$b->[2]*$b->[3] >0){ return 1; #For Complete genomes. }else{return 0;} } } } sub zeroNum(){ my $arr=shift; my $a; my $n; foreach $a (@{$arr}){ if($a <= 0){ $n++; } } return $n; } sub c(){ my $a=shift; my $b=$a; while($b ne ""){ if($b<$a){ $a=$b; } $b=shift; } if(defined($a)){ return $a;}else{ return 0; } } sub p(){ my $a=shift; my $b=shift; while($b ne ""){ if($b>$a){$a=$b} $b=shift; } return $a; } sub randCnm(){ my $n=shift; my $m=shift; my @arr1=(0..($m-1)); my $i; my $rn; my %hs=(); my @arr2=(); for($i=0;$i<$n;$i++){ $rn=int(rand($m-$i)); @arr1=(sort{$a<=>$b}(@arr1)); $hs{$arr1[$rn]}=1; push(@arr2,($arr1[$rn])); $arr1[$rn]=$m+1; } return @arr2; } sub randConm(){ my $o=shift; my $n=shift; my $m=shift; my @data; my %hs; my $i; for($i=0;$i<$o;$i++){ my @arr = &randCnm($n,$m); while(defined($hs{join(" ", sort {$a<=>$b} @arr)})){ @arr = &randCnm($n,$m); } $hs{join(" ",sort {$a<=>$b} @arr)}=1; push(@{$data[$i]},@arr); } return @data; } sub randConmN(){ my $o=shift; my $n=shift; my $m=shift; my @data; my %hs; my $i; for($i=0;$i<$o;$i++){ my @arr = &randCnm($n,$m); while(defined($hs{join(" ", ($arr[0],sort {$a<=>$b} @arr))})){ @arr = &randCnm($n,$m); } $hs{join(" ",($arr[0],sort {$a<=>$b} @arr))}=1; push(@{$data[$i]},@arr); } return @data; }