use strict; use warnings; use feature 'say'; use Time::HiRes 'time'; use PDL; use PDL::NiceSlice; use Test::PDL 'eq_pdl'; use constant { WIDTH => 20, HEIGHT => 20, STEPS => 1000, }; my \$x = zeroes long, WIDTH, HEIGHT; # Put in a simple glider. \$x(1:3,1:3) .= pdl ( [1,1,1], [0,0,1], [0,1,0] ); my \$backup = \$x-> copy; printf "Game of Life!\nMatrix: %s, %d generations\n", \$x-> info, STEPS; # Tutorial my \$t = time; for ( 1 .. STEPS ) { my \$t_ = time; # Calculate the number of neighbours per cell. my \$n = \$x->range(ndcoords(\$x)-1,3,"periodic")->reorder(2,3,0,1); \$n = \$n->sumover->sumover - \$x; # Calculate the next generation. \$x = (((\$n == 2) + (\$n == 3))* \$x) + ((\$n == 3) * !\$x); } printf "Tutorial: %0.3f s\n", time - \$t; # Faster my \$m = \$backup-> copy; \$t = time; my \$wrap_w = pdl [ reverse WIDTH - 1, ( 0 .. WIDTH - 1 ), 0 ]; my \$wrap_h = pdl [ reverse HEIGHT - 1, ( 0 .. HEIGHT - 1 ), 0 ]; for ( 1 .. STEPS ) { my \$n = \$m -> dice_axis( 0, \$wrap_w ) -> lags( 0, 1, WIDTH ) -> sumover -> dice_axis( 1, \$wrap_h ) -> lags( 1, 1, HEIGHT ) -> xchg( 0, 1 ) -> sumover; \$n -= \$m; \$m = ( \$n == 3 ) | \$m & ( \$n == 2 ) } printf "Faster: %0.3f s\n", time - \$t; die unless eq_pdl( \$x, \$m ); __END__ Game of Life! Matrix: PDL: Long D [20,20], 1000 generations Tutorial: 0.341 s Faster: 0.111 s Matrix: PDL: Long D [200,200], 100 generations Tutorial: 0.845 s Faster: 0.086 s Matrix: PDL: Long D [1000,1000], 20 generations Tutorial: 4.422 s Faster: 0.443 s Matrix: PDL: Long D [2000,2000], 10 generations Tutorial: 8.878 s Faster: 0.872 s