Saturday, October 26, 2013

Perl5i Presentation to Toronto Perl Mongers

I presented a workshop based on the blog articles I wrote in March & April about perl5i.

It went out on the Google Hangout, and the recording is available on YouTube, though unfortunately it stops short of the end. There may be a way that can be fixed, though i doubt it.

Slides are available at Scribd, as are the speaker notes.

Thanks to Michael for the module, Ingy dot Net for his YAPC mention of my Rosetta Code efforts, and Stephan Little for p5mop, his attempts to bring OO into core Perl5.

Thursday, August 8, 2013

Dear John Nack #2

I suppose I should name this Dear Adobe, since John isn't actually involved with Lightroom or Photoshop. And I will, next time.

I LOVE the Adaptive Wide Angle filter in Photoshop CC .... except when I don't.

AWA is a filter like Lens Corrections, that places a preview of your image in  window of its own, where you modify various controls and view the effects in more-or-less real time. When you click OK, the modifications are applied to the entire image. While there are a number of options, which vary the amount and type of controls available, I use it on panoramas. You draw a line on the image, by clicking the endpoints, and a guide line is presented, bisecting a circle. By clicking where the line and circle intersect, you can cause the line to rotate to a different angle. But unlike a simple image rotation, you can have many lines, rotated to various angles, manipulating a mesh superimposed on the image.

I use it to straighten out panoramas, so my horizontals are horizontal and my verticals are all vertical. But you could be more creative with your selections, and generate something more cubist.

I forgot to mention, since AWA is presumably intended for application to wide-angle images, the two points you select are connected by an arc, not a line, and the intensity of the arc depends on where you are in the image. That is, near the top the arc is a rainbow, near the bottom it is a cup, and in the middle it is a straight line.

Pre- & Post Arc Complexity

Sometimes the degree of curvature is an excellent match to the portion of the image I want to adjust, but sometimes the system wants to draw an arc, when I want a straight line, or at least a drastically different radius of curvature. I wish there were a way to control the curvature, maybe an adjustment in the sidebar. Actually, it's something you need to adjust in the middle of setting the end-points for a line. Perhaps a control-click could specify one or more intermediate points, similar to the way you draw bezier. In fact, why not allow bezier curves, not just arcs? Most people wouldn't use the fancier features, but a few perverts creative types would.

As well, You don't always want a curve  totally flattened out. Since wide-angle distortion has become a part of our visual vocabulary, there are times when you want to leave some distortion, or even to create some where there wasn't any! Wouldn't it be cool if you could adjust the post-flattening characteristics of the line, as well as the pre-flattening ones? Of course, you COULD achieve the same effect by using a "wrong" curve for the original line, then, when it was flattened, you would wind up with some curvature. In fact, all that's needed is to be able to re-adjust the points that define the curve, including the one or more intermediate points. Click the two endpoints of some feature to define a line, then drag the automatically provided mid-point away from the line, to introduce curvature where there was none.

Moving Reference Points away from Line Endpoints

A totally different problem I have is that sometimes the features I want to snap to, don't extend all the way across the region that should be modified. For example, if there's a wall with a couple of windows in it, the bottoms of the windows define a horizontal line ( usually ). But the line should extend right across the wall. AWA provides a zoom-in view of the endpoint, allowing you to precisely place the point where it belongs. But if you click on the windows, you aren't affecting the whole wall. If you go to the edge of the wall, there are no reference points to work by.

My solution is to set an endpoint on one window, then drag across to the other end of the wall, setting the endpoint by guessing where the reference point is on the second window. Then I move the first endpoint to its end of the wall, again guessing where the reference point is.

One simple solution would be to define the curve using the endpoints and intermediate point, and then extend the resulting line to the edges of the region. In effect, the end points are turned into intermediate points. I'm not sure how that would work with beziers.

Another solution is to lock the preview window in one place (the window in the wall) while setting the endpoint at the end of the wall. The up-down location of the endpoint is critical, since it is defining a horizontal; the left-right position is less critical---it doesn't matter if it extends past the edge of the wall, or stops a fraction short. Perhaps you could have multiple preview windows, the way you have multiple reference points in the Sharpen->Shake Reduction filter.

Automating Line Angles

As I mentioned, the result of clicking twice on the image is a straight line which can be rotated to any angle you like. But it's irritating to rotate it some tiny amount. Long lines get better precision, while shorter lines are difficult to adjust accurately. Why can't you just specify that some line should become horizontal, or should become vertical, thought I? After imaging some overly-complicated ways that could be done, I thought the best solution would be to hold down the shift key, just like you do when drawing lines to restrict them to horizontal, vertical or diagonal. Well, that's a silly idea, but I gave it a try, anyway. What do you know, those Adobe engineers are almost as smart as I am! :-)

Endpoint Fine Adjustment

The preview gives you the ability to see close-in around the endpoint, but there is no fine-movement control, or, at least, I haven't found it. Once the proximity of the end-point is established, it would be good to set the exact location in a more precise manner, even pixel-by-pixel. I've tried chording the shift, control, option and command keys, but they don't seem to affect the behaviour.

Autoscale

When you go into AWA, the image occupies most of the frame. However, since it may not be rectangular, as a result of merging multiple images into a panorama, it may not fill it entirely, in both horizontal and vertical. On the contrary, while one dimension may not fill the frame, the other dimension frequently overflows it, like a camera viewfinder that shows you only 90% of the image.

I prefer to work on the entire image, even if the edges may be not entirely useful, do to curvature and jaggedness. So I wish there were a button to set the scale so the entire image is visible.

Once the work is done, the shape of the image may be altered somewhat, due to distorting the mesh. I want at least one dimension to totally fill the frame, during the processing from filter preview into actual image, since my superstitions tell me I get more effective pixels that way. I haven't tested it, so maybe I'm wrong. Still, it would be nice if there were FIT and FILL options, as there are in the Lightroom navigator, to set the scale to exactly the correct values. As it is, I type numbers into the scale adjustment, or scrub the slider, or use the arrows with or without the shift key. But it takes time, and sliding the image up or down, when it's something that computers should be doing for us. Of course, I may further optimize the scale, prior to applying the changes, if I'm intending to crop the image further.

Summary


So there's my list. One of my requests is already implemented. Are any others already there, just waiting for me to find the right commands? Will Adobe think I'm out-to-lunch, or will I be receiving royalty checks ($0.003 a year) for inventing brilliant ideas?

Monday, July 15, 2013

Dear John Nack #1

Dear John.

Please arrange for Adobe to implement the following feature for me.

I love the "Visualize Spots" checkbox in the LightRoom / Camera Raw "Healing Brush" as a way to locate dust spots that need to be cleaned away.

The problem is, you need to be zoomed in at 100% to effectively deal with sensor dust, and sometimes it's not clear whether a particular mark on the screen is a fault or a feature. Then you need to click to normal view, and back to the edge-detection view. It's a problem having to move the cursor down to the checkbox, back to the spot to clean away, and back to the checkbox. A key-chord combination to enable and disable the edge-detected view would be a great benefit ... and there are so many to choose from! It could be Ctrl-H, since it's a Hide operation; or like overflow/underflow indication, it could simply use the control key. Only while healing, you understand.

That's all right, no royalties are necessary.

Tom

16 July .... Brilliant! John says to click the 'A' key when using the healing brush, to switch back and forth between the normal view and the edge-detection view. 'A' is for 'Admirable'!

Sunday, May 12, 2013

If I Could Change Perl

Is there something that irritates you about Perl? One little thing you wish you could change, to make life so much easier?

For me, it's the way declarations work. Whether it's with local, our or my, you can declare a variable name, or a list of several variable names:

my ($x, $y, $z);
Of course, you can initaliaze variables as you declare them.
my $bank_balance = -999_999;
my ( $x, $y, $z ) = ( 0, 0, 0 );

But if you have a number of variables to declare, and they aren't directly related to each other, as (x, y, z) clearly are, it would be so much better to declare the variable and immediately assign a value to it on the same line, the way C, Javascript and numerous sensible langages do.

Currently, 'my', 'our' and 'local' expect a variable name, or a list of mariable names. So one possibility would be to provide an alternative form which takes a hash. Ideally, values defined in one line could be used lower down.

my {
    $sides => 3,
    $lengths => [3, 4, 5],
   };
I suppose people will ignore this article or come out with an explanation of why I'm wrong.
All the same, what little feature would make your Perl day better?

Sunday, April 21, 2013

Learning Perl5i #3 revisted

I was somewhat uncomfortable that my solution to the combinatorics task, which involved a single, not very long routine, became so long with the addition of command line processing and POD  documentation. For one thing, while it had some information about how to invoke the routine, it did not have tests.

I still feel that a book on programming, say, should have a fully-implemented solution once a chapter, perhaps, to show the way things should be done. But that is too long for every single bit of code. Full documentation and sample implementations stretch on too long, compared to the few lines a snippet actually deserves.

Providing tests may still be appropriate. They take up less space than full documentation, yet explain how the various components work, by the very act of stress-testing those lines of code. Tests provide examples of how the code should be invoked.

Revising the combinatorics task into a module, this generates:

use perl5i::2;

# ----------------------------------------
# generate combinations of length $n consisting of characters
# from the sorted set @set, using each character once in a
# combination, with sorted strings in sorted order.
#
# Returns a list of array references, each containing one 
# combination.
#
func combine($n, @set) {
    return unless @set;
    return map { [ $_ ] } @set if $n == 1;

    my ($head) = shift @set;
    my @result = combine( $n-1, @set );
    for my $subarray ( @result ) {
$subarray->unshift( $head );
    }
    return ( @result, combine( $n, @set ) );
}

# ------------------------------------------------------------------
# Tests
#
func runtests() {
    eval { use Test::More }; # only include if testing

    test_no_set();
    test_length_zero();
    test_length_one();
    test_longer();
    done_testing();
}

func test_no_set() {
  is( combine( 1, () ), undef, 
      'set == empty list returns empty array' );
  is( combine( 1 ), undef, 
      'set not provided returns empty array' );
}

func test_length_zero() {
  is( combine( 0, 'a' ), undef, 'zero length returns empty array' );
}

func test_length_one() {
  my ( @results ) = combine( 1, 'a' );
  is_deeply( \@results, [['a']],
    'length 1 returns unary set as array element');

  @results = combine( 1, 'a', 'b', 'c' );
  is_deeply( \@results, [['a'], ['b'], ['c']],
    'length 1 returns larger set as array elements');
}
func test_longer() {
  my ( @results ) = combine( 2, 'a', 'b', 'c' );
  is_deeply( \@results, [['a', 'b'], ['a', 'c'], ['b', 'c']],
    'longer length generates list of  combinations');
}
# ------------------------------------------------------------------
# Run tests if invoked as a program, rather than in cluded as a 
# module.
#
runtests() unless caller();

Output from invoking the module as a program:

bash-3.2$ perl combinations.pli
ok 1 - set == empty list returns empty array
ok 2 - set not provided returns empty array
ok 3 - zero length returns empty array
ok 4 - length 1 returns unary set as array element
ok 5 - length 1 returns larger set as array elements
ok 6 - longer length generates list of  combinations
1..6

Thursday, April 18, 2013

Learning Perl5i #3

I've long admired the way functional languages specify multiple implementations of a routine for different sets of argument values, to detect terminal conditions. Converting a Perl6 solution  of a combinatorics task to Perl5i, I realized the plain Perl solution isn't necessarily all that bad, either.

The problem is to list the different ways you can select M elements from a set of N. Select 2 elements from a set of 4 would lead to the values ( 1, 2 ); ( 1, 3 ); ( 1, 4 ); ( 2, 3 ); ( 2, 4 ); ( 3, 4 ). Oh yeah, they want the characters in each combination in sorted order, and  the list of combinations sorted, too.

So it all consists of a single routine which gets invoked as combine(3, ['a'..'e']).

Ignore the first couple of lines, for a moment. If the first character of the set exists in a combination, it must be in the first position, since the characters are in sorted order. That means the remainder of the combination must be one character shorter, made of the remaining characters. So that part calls for a recursive solution:

* pull off the first character from the alphabet;
* recursively determine combinations of length -1 from the remainder of the set;
* reassemble be prefixing the first character onto each solution.

The other possibility is that the first character is not in the solution. That calls for recursively invoking the routine with the original length, but a smaller alphabet. If we do that often enough, we reach a situation where the alphabet is empty. This situation is handled by the first line we skipped over. In fact, we could optimize and abort if the size of the alphabet is smaller than the length of string we are requesting.

The more normal end case is when we are asking for a single character, the last in the sequence. In this situation, each character in the set is a candidate, so we return each character as an element in an anonymous array. Returning to the calling level, we then prefix the previous head of the alphabet onto the sequence using unshift. When we reach the top level, we have a list of arrays, each array being one combination.


While I was satisfied with the solution, I was unhappy with hard-coding the invocation. If I'm trying to demonstrate good coding, I should allow the program to be invoked with command-line arguments, to vary the way it is used.

So I added my favourite command-line options module, Getopt::Long, and modified the main section to fetch and use options:

my $options = parse_options();
say @$_ for combine( $options->{length}, 
                     @{$options->{alphabet}} );

The routine to read options looks like this:

func parse_options() {
    my %options = ( length => 3,
   set => 5,
 );
    GetOptions( \%options, 'length=s', 'set=s' )
or die( 'some usage message';

    $options{alphabet} = 
        [ ('a'..'z')[0..$options{set}-1] ];
    return \%options;
}

Getopt::Long has a  rich set of options to support single character or long argument names, to allow flags, options with string or numeric values, hashes and even multiple values, as well as supporting multiple names and abbreviations. You can specify a parameter, and then specify a reference to a scalar in which to store the value, but I prefer to pass a reference to a hash as the first argument, which gets all the values.

By setting some values in the hash, you can specify default values.

In this case I allow two arguments, the length of the strings, M in combinatorics talk, and the size of the alphabet, N in combinatorics talk. I then create an alphabet of set N by taking an appropriately-sized subset of the sequence a to z.



But if GetOptions fails because the argument list is totally unusable, you need to report an error. And it should probably provide a usage message, describing how to invoke the program. My favourite solution is Pod::Usage, which makes it easy to display the POD contained in the file ... but that means documenting the program with POD.

So the question is, is this getting silly? Or is it an appropriate example to present to people wanting to learn modern Perl?


use perl5i::2;
use Getopt::Long;
use Pod::Usage;

# ----------------------------------------
# Generate combinations of length $len consisting
of characters from the sorted set @chars, using 
each character once in a combination,with sorted
# strings in sorted order.
#
# We will use a recursive solution:
# * If we run out of eligable characters, we've
#   gone too far, and won't find a solution along
#   this path.
# * If we are looking for a single character, each 
#   character in @set is eligible, so return each
#   as the single element of an array.
# * We have not yet reached the last character, so
#   there are two possibilities:
#   1) push the first element onto the front of an 
#      N-1 length combination from the remainder of
#      the set.
#   2) skip the current element, and generate an  
#      N-length combination from the remainder
#
func combine($len, @chars) {
  return unless @chars;
  return map { [ $_ ] } @chars if $len == 1;

  my ($head) = shift @chars;
  my @result = combine( $len-1, @chars );
  for my $subarray ( @result ) {
    $subarray->unshift( $head );
  }
  return ( @result, combine( $len, @chars ) );
}

func parse_options() {
    my %options = ( length => 3,
   set => 5,
 );
    GetOptions( \%options, 'length=s', 'set=s',
                'man', 'help' )
or pod2usage(2);
    pod2usage(1)  if $options{help};
    pod2usage(-verbose => 2)  if $options{man};

    $options{alphabet} =
        [ ('a'..'z')[0..$options{set}-1] ];
    return \%options;
}

my $options = parse_options();
say @$_
    for combine( $options->{length},
                 @{$options->{alphabet}} );
__END__


=pod

=head1 NAME

combinations.pli - determine possible combinations of M elements from a set of N

=head1 VERSION

This documentation applies to combinations.pli version 0.0.1

=head1 SYNOPSYS

    combinations.pli [--length M] [--set N] \
                     [-man] [-help]

=head1 OPTIONS

=over 4

=item length M

Create strings of this length

=item set N

Use an alphabet of this many characters

=item help

Display a brief summary of information about the program.

=item man

Display the full documentation.

=back

=head1 DESCRIPTION

Generate combinations of length C<length> consisting of characters from the sorted set C<alphabet>, using each character once in a combination, with sorted strings in sorted order.

=cut

Tuesday, April 16, 2013

Learning Perl5i #2

Continuing the exploration of Perl5i beyond part one, I decided to treat perl5i as a language and use it to implement tasks at Rosetta Code.

Since Moose is a complete OO solution, I use a lightweight approach to OO, where used.

The first RC task I implemented is 100 doors: see the full implementation.

In terms of documentation, I gave each routine a small header in which I show how the routine is invoked, specify the inputs and outputs, and summarize the primary actions of the routine.

Since the task is defined in terms of a number of doors, and operations on those doors, it seemed appropriate to use an object. "some object" + "operations on that object" ==> "segregate into an OO implementation".

I used a simple constructor with initialization performed in _init() to simplify subclassing. The constructor doesn't need to be modified, just a new _init() written to handle additional attributes or arguments, if any. The new implementation can handle the duties of the original routine, or better, invoke the original as $self->SUPER::_init( @_ ).

The initializer stores how many doors we are dealing with, then then creates an array of doors. We are interested in doors 1..N, but we actually create one more, 0..N, since that's the way Perl arrays work. We'll simply ignore door zero, it is permanently closed. One subtle detail about the x multiplier: $CLOSED x $N is 0000..., string repetition; list repetition uses parentheses: ($CLOSED) x $N to generate ( 0, 0, 0, ... ).

The instructions say there are N passes, in which you toggle every door, every other door, every Nth door. I created toggle() to toggle a single door, toggle_n() to process a single pass, and toggle_all() to handle all the passes.

Besides eliminating duplication and excessive typing, one advantage of the ternary operator ( ? : ) over an if-block is that it is clear a single l-value is the target.

Simple statement modifier loops like these are, I believe, quicker than more general loops, and they offer simpler optimization in the future into parallel processing, but they also communicate that we are dealing with a set of data. Too often, people coming to Perl from C and Java think in terms of indices: I get the first index; I get the first element in the array; I do something ... I prefer to think in terms of sets, like a Unix pipeline: Take this array of elements, do something to them, ...

Note in toggle_n(), that $n * int( N / $n ) is the largest multiple of $n les than N. Taking the sequence 1.. int($self->{N} / $n ) and multiplying each element by $n produces $n, 2 * $n, 3 * $n, ... $n * int( N / $n ), the list of doors to toggle on that pass.

The final requirement is to print which doors are open.  grep() takes a code block and a list of values. Values are passed if they generate a true value in the block, and barred if they generate a false value.

Putting the routines together into a demonstration of the 100 door task becomes a simple three-line sequence.

Saturday, March 23, 2013

Learning Perl5i

I've been looking at the module perl5i, which puts a sideways twist on Perl, eliminating tons of boring boilerplate, and introduce many conveniences. In this case, the i eliminates complexity.

Installing perl5i installs a number of other modules as well, on the other hand life becomes better once they are installed.

If you don't have cpanm or one of the other improved CPAN installers, the simplest way is to install perl5i and its friends using the command

     sudo cpan perl5i

You may need to type in yes to have cpan  install dependencies. Some modules are needed only temporarily during installation, and you are asked whether you want them permanently installed. Perl modules don't take up very much space, so I always go for it. Installation is a bit different on Windows or Linux machines, but you can figure it out, you're a mighty Perl programmer!

One consideration is that major versions of perl5i may change in drastic ways. But you don't include perl5i; what you specify is perl5i::2. The newest module includes perl5i::0 and perl5i::1 as well, so old code is supported until you are ready to upgrade them.

The immediate benefit is that you no longer have to enable strictness. perl5i automatically provides

     use warnings;
  use strict;

So it costs you 14 characters to type

    use perl5i::2;

and straight off the bat it saves you 24 characters ....profit!


Oh, and it automatically activates features say, state and switch.


But wait! There's more! Not only does it slice and dice, it also julienes!

Well, no cutting anything in any shape ... but perl5i DOES provide autodie. If your open() doesn't work, the program dies; if the close() doesn't work, the program dies; if print() or a system() call or unlink() don't work, the program dies with an exception that turns into a string if you don't handle it.

Having a program die is an effective way to trigger in-house failure detection systems, such as Nagios. So simply doing the things you want, without checking return values, becomes a viable way to write a secure program that detects problems. If you need to catch and handle problems, perl5i provides Try::Tiny. There are other attempts at exception handling; any of them would be clearer than using eval. Try::Tiny is small, it does the job, and the intent is clear.

    try {
        open my $h, '<', '/does/not/exist';
    } 
    catch {
        say "the open() died with message $_";
    };

You can also add a finally block, to perform things that need to happen regardless of success or failure. The single weakness is that try is a statement, not a block, so it needs a semi-colon

So that's a major from installing perl5i, and we've barely gotten started.