Return to Snippet

Revision: 36415
at November 22, 2010 01:05 by StanislavZza


Initial Code
local $| = 1; #forces stdout to flush so the dots show up.

#set up parameters..................................
$first = 3;
$end = 100; # upper bound on the N to use
$max_gen = 1000; # how many generations to run for each
$max_pop = 100; # carrying capacity C

open(OUT,'>output.txt') or die 'hard'; # this is where the summary output goes
open(MISS,'>missing.txt'); # this creates a list of all the 'missing' values for N

# first add some column headings
print OUT "Start,Generation,PopSize,Last,Demand,Kids,Died,Total\n";

# main loop to generate summary stats and individual report files for each N
for ($start = $first ;$start < $end; $start+=2) { #just do the odd numbers
	sim($start);
	print ".";
}
print "\n";

# run the simulation for the given N
sub sim {
	undef %n;  #keeps track of what numbers are still in the ecology. Zero out before each run
	undef %all; #keeps track of any number ever hit
	$id = $_[0]; # the starting number N is the argument
	
	# you need to have a folder called 'sim' to dump the details in
	open(START,">sim//$id.txt") or die;  #set up for windows. If you run Linux change the slashes
	
	$generation = 0; #initialize for this run
	
	$all{$id} = $n{$id} = 1; # associative arrays will keep track of who was and is alive
			
	$last = $start; #keeps track of the biggest number reached for the summary report
	
	while($generation < $max_gen) {
		
		$generation++;
		$pop = scalar(keys(%n)); # get the size
		
		print OUT "$start,$generation,$pop,$last,";
		$kids = $died = 0; #keeps track of reproduction and extinction for this generation
		
		foreach $v (keys(%n)) { #go through the population and iterate
						
			if ($v % 2 == 0) { # if even divide by two
				$v /=2;
				if ($v == 1) { # kill it if it reaches 1
					# it will vanish because it doesn't get copied to %n1
					$died++; # keep track of how many we lost
				} else {
					$all{$v} = $n1{$v} = 1; # %n1 is the temp array for this work
				}
			} else { # it's odd, so do (3n+1)/2. Unless we're about to blow up our precision.
				# have to have a rule about overflow. I'll chose to kill it off as being a hog.
				if ($v > 1000000000) { # overflow problem
					$died++;
				} else {
					$v = (3*$v + 1)/2; 
					$all{$v} = $n1{$v} = 1;
					copy($v); # make the mutant--see function below
				}
			}
		}
		
		$demand = scalar(keys(%n2)); #save this for reporting
		%n = %n1; # reset for the next trial. Yes, I should use pointers instead. I know.
		$npop = scalar(keys(%n));
		
		#now add in the new generation
		foreach $num (sort(keys(%n2))) { # sorted so that we give the smaller ones priority
			last if $npop >= $max_pop; # stop when we get to the capacity
			next if $n{$num}; # already have this one in the population
			$n{$num} = 1; # add it in
			$npop++; # increment the total current population
			$kids++;
		}
				
		$total = scalar(keys(%all)); # count the types who ever lived
		
		print OUT "$demand,$kids,$died,$total\n";
		
		# this prints out the whole population for this generation and N into N.txt in the sim folder
		foreach $key (sort {$a <=> $b} (keys(%n))) {
			print START "$key,"; 
		}
		print START "\n"; # all done with that row
		
		undef %n1; # wipe our workspace clean
		undef %n2; 
	}
	close START;
	
	# the sim is done. Print out what integers were missed between 2 and 1000
	for($i =2;$i<1000;$i++) {
		print MISS "$start,$i\n" unless $all{$i} > 0; 
	}
}
	
sub copy { #reproduce a number with mutation
	 $t = $_[0] - 2;
	 $all{$t} = $n2{$t}=1; #keep the kids separate, so we can apply the carrying capacity
	 $last = $t if $t > $last; #find the biggest one reproduced
}

Initial URL
http://highered.blogspot.com/2010/11/collatz-ecologies.html

Initial Description
See [blog post](http://highered.blogspot.com/2010/11/collatz-ecologies.html)

Initial Title
Collatz Ecology Generator

Initial Tags


Initial Language
Perl