Discussion:
[Pdl-porters] Rotate a Matrix: rot2d and zeroes from outer space
Diab Jerius
2014-02-03 19:42:39 UTC
Permalink
[Please pardon the possible duplicate message]


Over at stackoverflow there's a question on rotating a 2D matrix:

https://stackoverflow.com/questions/21433364/use-perl-pdl-to-rotate-a-matrix

(Please add your own favorite solution.)

One solution that's custom built would seem to be rot2d. a 90 degree
rotation (with anti-aliasing turned off for good measure) should
provide an exact result.

In any case, here's what I got:

pdl> p $m = pdl( [ 1..3],[4..6],[7..9])

[
[1 2 3]
[4 5 6]
[7 8 9]
]

pdl> p $m->rot2d( 90, 0, 1 )

[
[0 0 0]
[3 6 9]
[2 5 8]
]

Looks good. Except for those pesky 0's. Where'd they come from? It
looks like it's rotating about the "6", not the "5", and filling in
the off-matrix values with my specified value of 0.

I'm tempted to call this an off-by-one error in the x direction, but
then I gave rot2d a nice even-sized matrix:

pdl> p $m = pdl( [ 1..4],[5..8],[9..12],[13..16])

[
[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]
[13 14 15 16]
]

pdl> p $m->rot2d( 90, 0, 1 )

[
[ 0 0 0 0]
[ 4 8 12 16]
[ 3 7 11 15]
[ 2 6 10 14]
]

with the same results. The x coord of the rotation center is
off-by-one from what I would consider the rotation center. Typically
such errors resolve themselves when switching from even to odd sizes,
so now I wonder if this is a feature rather than a bug.

There's a hard-coded 0.999999 in the code which gives me the willies,
but I haven't dissected it to figure out why it has the above
properties.

Any thoughts? Bug? Feature?
Craig DeForest
2014-02-03 20:49:45 UTC
Permalink
Hmmm. I haven't used rot2d, I use PDL::Transform instead.

pdl> use PDL::Transform;
pdl> $m = sequence(3,3)+1;
pdl> print $m->map(t_rot(90));
[
[3 6 9]
[2 5 8]
[1 4 7]
]
pdl>


PDL::Transform is a *lot* more general than rot2d.
Post by Diab Jerius
[Please pardon the possible duplicate message]
https://stackoverflow.com/questions/21433364/use-perl-pdl-to-rotate-a-matrix
(Please add your own favorite solution.)
One solution that's custom built would seem to be rot2d. a 90 degree
rotation (with anti-aliasing turned off for good measure) should
provide an exact result.
pdl> p $m = pdl( [ 1..3],[4..6],[7..9])
[
[1 2 3]
[4 5 6]
[7 8 9]
]
pdl> p $m->rot2d( 90, 0, 1 )
[
[0 0 0]
[3 6 9]
[2 5 8]
]
Looks good. Except for those pesky 0's. Where'd they come from? It
looks like it's rotating about the "6", not the "5", and filling in
the off-matrix values with my specified value of 0.
I'm tempted to call this an off-by-one error in the x direction, but
pdl> p $m = pdl( [ 1..4],[5..8],[9..12],[13..16])
[
[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]
[13 14 15 16]
]
pdl> p $m->rot2d( 90, 0, 1 )
[
[ 0 0 0 0]
[ 4 8 12 16]
[ 3 7 11 15]
[ 2 6 10 14]
]
with the same results. The x coord of the rotation center is
off-by-one from what I would consider the rotation center. Typically
such errors resolve themselves when switching from even to odd sizes,
so now I wonder if this is a feature rather than a bug.
There's a hard-coded 0.999999 in the code which gives me the willies,
but I haven't dissected it to figure out why it has the above
properties.
Any thoughts? Bug? Feature?
_______________________________________________
PDL-porters mailing list
http://mailman.jach.hawaii.edu/mailman/listinfo/pdl-porters
Diab Jerius
2014-02-03 21:12:24 UTC
Permalink
On Mon, Feb 3, 2014 at 3:49 PM, Craig DeForest
Post by Craig DeForest
Hmmm. I haven't used rot2d, I use PDL::Transform instead.
pdl> use PDL::Transform;
pdl> $m = sequence(3,3)+1;
pdl> print $m->map(t_rot(90));
[
[3 6 9]
[2 5 8]
[1 4 7]
]
pdl>
PDL::Transform is a *lot* more general than rot2d.
Agreed. However, there's this line in rot2d's documentation:

PDL::Transform offers a more general interface to distortions, including
rotation, with various types of sampling; but rot2d is faster.


Which requires some evidence, which I'm thinking of providing, should
I ever figure out rot2d's mysteries.

Diab
Craig DeForest
2014-02-03 21:23:34 UTC
Permalink
Hmmm. If you do compare directly, try "$m->map(t_rot(90),{method=>'sample'})" for the best speed...
Post by Diab Jerius
On Mon, Feb 3, 2014 at 3:49 PM, Craig DeForest
Post by Craig DeForest
Hmmm. I haven't used rot2d, I use PDL::Transform instead.
pdl> use PDL::Transform;
pdl> $m = sequence(3,3)+1;
pdl> print $m->map(t_rot(90));
[
[3 6 9]
[2 5 8]
[1 4 7]
]
pdl>
PDL::Transform is a *lot* more general than rot2d.
PDL::Transform offers a more general interface to distortions, including
rotation, with various types of sampling; but rot2d is faster.
Which requires some evidence, which I'm thinking of providing, should
I ever figure out rot2d's mysteries.
Diab
_______________________________________________
PDL-porters mailing list
http://mailman.jach.hawaii.edu/mailman/listinfo/pdl-porters
Diab Jerius
2014-02-03 22:07:17 UTC
Permalink
For grins I tested it against my simple solution:

use PDL;
use PDL::Transform;
use Benchmark ':all';

$m = sequence(3,3)+1;

timethese(10000,
{ transrev => '$m->transpose->slice(":","-1:0")',
xfrm => '$m->map(t_rot(90),{method=>"sample"})'
} );



Benchmark: timing 10000 iterations of transrev, xfrm...
transrev: 0 wallclock secs ( 0.11 usr + 0.00 sys = 0.11 CPU) @
90909.09/s (n=10000)
(warning: too few iterations for a reliable count)
xfrm: 42 wallclock secs (41.49 usr + 0.11 sys = 41.60 CPU) @
240.38/s (n=10000)


Ouch...

On Mon, Feb 3, 2014 at 4:23 PM, Craig DeForest
Post by Craig DeForest
Hmmm. If you do compare directly, try "$m->map(t_rot(90),{method=>'sample'})" for the best speed...
Post by Diab Jerius
On Mon, Feb 3, 2014 at 3:49 PM, Craig DeForest
Post by Craig DeForest
Hmmm. I haven't used rot2d, I use PDL::Transform instead.
pdl> use PDL::Transform;
pdl> $m = sequence(3,3)+1;
pdl> print $m->map(t_rot(90));
[
[3 6 9]
[2 5 8]
[1 4 7]
]
pdl>
PDL::Transform is a *lot* more general than rot2d.
PDL::Transform offers a more general interface to distortions, including
rotation, with various types of sampling; but rot2d is faster.
Which requires some evidence, which I'm thinking of providing, should
I ever figure out rot2d's mysteries.
Diab
_______________________________________________
PDL-porters mailing list
http://mailman.jach.hawaii.edu/mailman/listinfo/pdl-porters
Craig DeForest
2014-02-03 22:24:50 UTC
Permalink
Ouch indeed!

The slicing will of course be insanely fast since it only deals with metadata. I knew map was more optimized for large datasets, but that is ridiculous! :-)

I get similar results -- 35 wallclock seconds for 10,000 iterations of the map() call. But to be fair, over 20 seconds of that is spent autoscaling the result (transforming 9 points forward to see where they lie on the output plane, then generating transform objects that make them fit the output plane). This:

timethese(10000,{xfrm2=>'$m->map(t_linear(pre=>[-1,-1],rot=>90,post=>[1,1]),{method=>"sample",pix=>1})'});

takes 15 seconds on my machine.

Still, that's a lot of overhead for a small answer.

Going to a larger scale: setting $m=sequence(1000,1000) and using 1000 iterations gives a map runtime (with autoscaling) of 258 seconds and a rot2($m,90,0,0) runtime of 17 seconds -- so, er, rot2 is clearly worth using if it can be fixed up!
Post by Diab Jerius
use PDL;
use PDL::Transform;
use Benchmark ':all';
$m = sequence(3,3)+1;
timethese(10000,
{ transrev => '$m->transpose->slice(":","-1:0")',
xfrm => '$m->map(t_rot(90),{method=>"sample"})'
} );
Benchmark: timing 10000 iterations of transrev, xfrm...
90909.09/s (n=10000)
(warning: too few iterations for a reliable count)
240.38/s (n=10000)
Ouch...
On Mon, Feb 3, 2014 at 4:23 PM, Craig DeForest
Post by Craig DeForest
Hmmm. If you do compare directly, try "$m->map(t_rot(90),{method=>'sample'})" for the best speed...
Post by Diab Jerius
On Mon, Feb 3, 2014 at 3:49 PM, Craig DeForest
Post by Craig DeForest
Hmmm. I haven't used rot2d, I use PDL::Transform instead.
pdl> use PDL::Transform;
pdl> $m = sequence(3,3)+1;
pdl> print $m->map(t_rot(90));
[
[3 6 9]
[2 5 8]
[1 4 7]
]
pdl>
PDL::Transform is a *lot* more general than rot2d.
PDL::Transform offers a more general interface to distortions, including
rotation, with various types of sampling; but rot2d is faster.
Which requires some evidence, which I'm thinking of providing, should
I ever figure out rot2d's mysteries.
Diab
_______________________________________________
PDL-porters mailing list
http://mailman.jach.hawaii.edu/mailman/listinfo/pdl-porters
_______________________________________________
PDL-porters mailing list
http://mailman.jach.hawaii.edu/mailman/listinfo/pdl-porters
Diab Jerius
2014-02-03 22:52:32 UTC
Permalink
Your point about slice is well taken. If I apply a sever operation to
the results of all of the algorithms to ensure that each is delivering
a similarly constructed piddle, I get the following for a matrix of
(1000,1000):

timethese(
100,
{
transrev => '$m->transpose->slice(":","-1:0")->sever;',
rot2d => '$m->rot2d(90,0,0)->sever',
xfrm => '$m->map(t_rot(90),{method=>"sample"})->sever;',
xfrm2 =>
'$m->map(t_linear(pre=>[-1,-1],rot=>90,post=>[1,1]),{method=>"sample",pix=>1})->sever;'
} );

Benchmark: timing 100 iterations of rot2d, transrev, xfrm, xfrm2...
rot2d: 3 wallclock secs ( 2.28 usr + 0.24 sys = 2.52 CPU) @
39.68/s (n=100)
transrev: 3 wallclock secs ( 2.76 usr + 0.00 sys = 2.76 CPU) @
36.23/s (n=100)
xfrm: 70 wallclock secs (62.08 usr + 8.75 sys = 70.83 CPU) @
1.41/s (n=100)
xfrm2: 49 wallclock secs (41.09 usr + 7.19 sys = 48.28 CPU) @
2.07/s (n=100)




On Mon, Feb 3, 2014 at 5:24 PM, Craig DeForest
Post by Craig DeForest
Ouch indeed!
The slicing will of course be insanely fast since it only deals with metadata. I knew map was more optimized for large datasets, but that is ridiculous! :-)
timethese(10000,{xfrm2=>'$m->map(t_linear(pre=>[-1,-1],rot=>90,post=>[1,1]),{method=>"sample",pix=>1})'});
takes 15 seconds on my machine.
Still, that's a lot of overhead for a small answer.
Going to a larger scale: setting $m=sequence(1000,1000) and using 1000 iterations gives a map runtime (with autoscaling) of 258 seconds and a rot2($m,90,0,0) runtime of 17 seconds -- so, er, rot2 is clearly worth using if it can be fixed up!
Post by Diab Jerius
use PDL;
use PDL::Transform;
use Benchmark ':all';
$m = sequence(3,3)+1;
timethese(10000,
{ transrev => '$m->transpose->slice(":","-1:0")',
xfrm => '$m->map(t_rot(90),{method=>"sample"})'
} );
Benchmark: timing 10000 iterations of transrev, xfrm...
90909.09/s (n=10000)
(warning: too few iterations for a reliable count)
240.38/s (n=10000)
Ouch...
On Mon, Feb 3, 2014 at 4:23 PM, Craig DeForest
Post by Craig DeForest
Hmmm. If you do compare directly, try "$m->map(t_rot(90),{method=>'sample'})" for the best speed...
Post by Diab Jerius
On Mon, Feb 3, 2014 at 3:49 PM, Craig DeForest
Post by Craig DeForest
Hmmm. I haven't used rot2d, I use PDL::Transform instead.
pdl> use PDL::Transform;
pdl> $m = sequence(3,3)+1;
pdl> print $m->map(t_rot(90));
[
[3 6 9]
[2 5 8]
[1 4 7]
]
pdl>
PDL::Transform is a *lot* more general than rot2d.
PDL::Transform offers a more general interface to distortions, including
rotation, with various types of sampling; but rot2d is faster.
Which requires some evidence, which I'm thinking of providing, should
I ever figure out rot2d's mysteries.
Diab
_______________________________________________
PDL-porters mailing list
http://mailman.jach.hawaii.edu/mailman/listinfo/pdl-porters
_______________________________________________
PDL-porters mailing list
http://mailman.jach.hawaii.edu/mailman/listinfo/pdl-porters
Diab Jerius
2014-02-03 18:39:39 UTC
Permalink
Over at stackoverflow there's a question on rotating a 2D matrix:

https://stackoverflow.com/questions/21433364/use-perl-pdl-to-rotate-a-matrix

(Please add your own favorite solution.)

One solution that's custom built would seem to be rot2d. a 90 degree
rotation (with anti-aliasing turned off for good measure) should
provide an exact result.

In any case, here's what I got:

pdl> p $m = pdl( [ 1..3],[4..6],[7..9])

[
[1 2 3]
[4 5 6]
[7 8 9]
]

pdl> p $m->rot2d( 90, 0, 1 )

[
[0 0 0]
[3 6 9]
[2 5 8]
]

Looks good. Except for those pesky 0's. Where'd they come from? It
looks like it's rotating about the "6", not the "5", and filling in
the off-matrix values with my specified value of 0.

I'm tempted to call this an off-by-one error in the x direction, but
then I gave rot2d a nice even-sized matrix:

pdl> p $m = pdl( [ 1..4],[5..8],[9..12],[13..16])

[
[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]
[13 14 15 16]
]

pdl> p $m->rot2d( 90, 0, 1 )

[
[ 0 0 0 0]
[ 4 8 12 16]
[ 3 7 11 15]
[ 2 6 10 14]
]

with the same results. The x coord of the rotation center is
off-by-one from what I would consider the rotation center. Typically
such errors resolve themselves when switching from even to odd sizes,
so now I wonder if this is a feature rather than a bug.

There's a hard-coded 0.999999 in the code which gives me the willies,
but I haven't dissected it to figure out why it has the above
properties.

Any thoughts? Bug? Feature?

Loading...