viored has asked for the wisdom of the Perl Monks concerning the following question:
Hey,
So I'm trying to make a lower triangular distance matrix in an itterative fashion. I had a function hd(a,b) which returns the distance between two objects a and b. I then want to iteratively add rows to this matrix as more objects are added, but I want to only add new rows, not recalculate the old ones. so I wrote this
$hd::size1 = scalar @{\@{$main::M[0]}};
$hd::size = $hd::size1 - 1;
for ($hd::i=$hd::save; $hd::i<= $hd::size; $hd::i++) #this creates
+ and adds to the hd array
{
$hd::store= [];
for ($hd::j=0; $hd::j < $hd::i; $hd::j++)
{
$hd::temp = &hd($main::M[0][$hd::i], $main::M[0][$hd::j]);
print $hd::temp;
print "\n";
push $hd::store, $hd::temp;
}
push @{$main::hd}, $hd::store;
}
$hd::save = $hd::size
for reference, main::M stores all the objects, and $main::hd is initialized as [];, and hd::save is initialized at 1 and updated each time the loops completes with hd::save = hd::size;
Whenever I follow this up with a module, it says the the first row of my matrix has no columns. but, when I use the following code (something I wrote for myself for self-reference)
#!/usr/bin/perl
#ex2
use warnings;
use strict;
sub clust;
$main::hd=[[]];
$main::a = [0.25];
$main::b = [0.25,0.5];
$main::C = [1,0.75,0.75];
$main::hdt = 0.4;
$main::c = [];
$main::c1 = 1;
$main::c2 = 0.75;
$main::c3 = 0.75;
#how to add elements to an array
push $main::c, $main::c1;
push $main::c, $main::c2;
push $main::c, $main::c3;
#how to add arrays to arrays
push @{$main::hd}, $main::a;
push @{$main::hd}, $main::b;
push @{$main::hd}, $main::c;
&clust;
for ($loop::i=0; $loop::i<=3; $loop::i++)
{
print $clust::cluster_ids->[$loop::i], "\n";
}
sub clust {
use Algorithm::Cluster::Thresh;
use Algorithm::Cluster qw/treecluster/;
$clust::tree = treecluster(data=>$main::hd, method=>'a');
$clust::cluster_ids = $clust::tree->cutthresh($main::hdt);
}
The module works perfectly. I think the error is how I'm iteratively storing things. Any ideas?
EDIT: The error was in my definition of hd::save. I orginally defined it as $hd::size, but that causes it to recalculate the last object from the previous time step. Changing it to $hd::save=$hd::size +1; fixed everything. This meant the matrix was not diagonal, it had weird kinks in it. Thanks everyone who helped!!!!!
Re: Array storage issue
by hippo (Bishop) on Apr 06, 2014 at 21:44 UTC
|
| [reply] |
|
> perl
use strict;
$x=23;
__END__
Global symbol "$x" requires explicit package name at - line 2.
Cheers Rolf
( addicted to the Perl Programming Language)
| [reply] [d/l] |
|
My issue isn't strict, I don't know why everyone says that. I have a small sample program that works perfectly, but I'm trying to merge something like it into the main code I'm working on. I think my problem is in the hd::store=[]; statement. When I push things into another array, does it push the values or just a reference to the values? Can I make it push just the values?
| [reply] |
|
|
|
Sorry, I don't know what that is. All the perl I know I've self-taught from online function guides. I write things this way because it works, I'm not great at it.
| [reply] |
|
c:\@Work\Perl\monks>perl -wMstrict -e
"for ($loop::i = 0; $loop::i < 3; $loop::i++) {
clust($loop::i)
}
print qq{\n};
;;
for (my $i = 0; $i < 3; $i++) {
clust2($i);
}
;;
;;
sub clust {
my ($n) = @_;
;;
for ($loop::i = 0; $loop::i < 3; $loop::i++) {
my $m = $n * $loop::i;
print qq{= $m };
}
print qq{\n};
}
;;
sub clust2 {
my ($n) = @_;
;;
for (my $i = 0; $i < 3; $i++) {
my $m = $n * $i;
print qq{- $m };
}
print qq{\n};
}
"
= 0 = 0 = 0
- 0 - 0 - 0
- 0 - 1 - 2
- 0 - 2 - 4
Global data is, IMHO, always problematic. If you are looking for up-to-date on-line general introductory tutorials, I would suggest perlintro, perhaps followed by chromatic's freely downloadable Modern Perl.
| [reply] [d/l] |
|
Sorry, I don't know what that is. All the perl I know I've self-taught from online function guides. I write things this way because it works, I'm not great at it.
When you get the time :) Tutorials has a bunch
Modern Perl by chromatic a loose description of how experienced and effective Perl 5 programmers work....You can learn this too.
Learn Perl in about 2 hours 30 minutes a tutorial reviewed and recommended by Perl Tutorial Hub
All of these, like perlintro, teach about Coping with Scoping , using lexical variables, because when programs grow beyond one screen , you'll want and argument passing
| [reply] |
|
Oh, if you mean why do I define all my variables with packages like main? Because when I first started perl, whenever I tried to use "my" my program wouldn't work. So I just started giving things packages, and haven't stopped. It just seems more stable.
| [reply] |
|
... when I first started perl, whenever I tried to use "my" my program wouldn't work.
It would have been very useful to have explored the reasons why your use of lexical variables wouldn't work. It's not too late to begin!
... packages ... just [seem] more stable.
Package data is global data. Global data is, IMHO, always problematic.
The story goes that during one of the Pearl Harbor attacks on December 7, 1941, General Walter Short, commander of the Army forces in Pearl, was struck in the chest by a spent 50-caliber machinegun round and knocked to the ground. The bullet's impact didn't even break the skin, but when someone picked it up and showed it to Short, he said "It would have been better if it had killed me."
When the day comes (and come it will if it has not already) that you are knocked on your ass by a chunk of global data at the end of a long trajectory from its point of origin, you may have some of the same feelings.
| [reply] |
|
|
|
|
> It just seems more stable.
no they are definitely not.
Package variables should be the well chosen exception, because they are global.
And sorry your code is unreadable for me... so I can't help.
Cheers Rolf
( addicted to the Perl Programming Language)
| [reply] |
Re: Array storage issue
by Anonymous Monk on Apr 06, 2014 at 22:52 UTC
|
You can use ddumperBasic debugging checklist to visualize the data structure you have (lesson courtesy of Basic debugging checklist and brian's Guide to Solving Any Perl Problem )
If I do that I see that the first row is indeed empty
[[], [0.25], [0.25, 0.5], [1, 0.75, 0.75]];
Try to follow https://metacpan.org/source/MDEHOON/Algorithm-Cluster-1.52/perl/examples/ex5_treecluster
This is how you should write that, pass arguments (often references to arrays), return values, meaningful names
This is your code cleaned up, some comments, but the data unfixed (I would use ex5_treecluster data as starting point )
#!/usr/bin/perl --
#~ clust-brain.pl
#~ 2014-04-06-15:43:25
#~
#~ perltidy -olq -csc -csci=10 -cscl="sub : BEGIN END if " -otr -opr
+-ce -nibc -i=4 -pt=0 "-nsak=*"
#!/usr/bin/perl --
use strict;
use warnings;
use Data::Dump qw/ dd /;
Main( @ARGV );
exit( 0 );
sub Main {
## compact notation
## first stored in an arrayref
# my $hd = [[], [0.25], [0.25, 0.5], [1, 0.75, 0.75]];
## then stored in a named array
# my @the_hd = ([], [0.25], [0.25, 0.5], [1, 0.75, 0.75]);
## same thing more verbose notation
## array ref first
my $hd_arrayref;
$hd_arrayref->[1][0] = 0.25; #d1
$hd_arrayref->[2][0] = 0.25; #d1
$hd_arrayref->[2][1] = 0.5; #d1
$hd_arrayref->[3][0] = 1; #d1
$hd_arrayref->[3][1] = 0.75; #d1
$hd_arrayref->[3][2] = 0.75; #d1
## named array second
my @hd_array;
$hd_array[1][0] = 0.25; #d1
$hd_array[2][0] = 0.25; #d1
$hd_array[2][1] = 0.5; #d1
$hd_array[3][0] = 1; #d1
$hd_array[3][1] = 0.75; #d1
$hd_array[3][2] = 0.75; #d1
## putting values in an array ref without loops
# my $cluster_ids = ( 0, 1, 2, 3 );
# my $cluster_ids = [ 0 .. 3 ];
my $hdt = 0.4;
## call clust_brain() function ... no need for short names
#~ my $cluster_ids = clust_brain( $hd_arrayref, $hdt );
my $cluster_ids = clust_brain( \@hd_array, $hdt );
## because we "import"ed dd from Data::Dump we don't have to type full
+ name
# Data::Dump::dd( $cluster_ids );
dd( $cluster_ids );
} ## end sub Main
sub clust_brain {
## ARGUMENT PASSING, first arg reference, second arg number
my( $hd_ref, $some_hdt ) = @_;
use Algorithm::Cluster::Thresh;
use Algorithm::Cluster qw/treecluster/;
## you my $varname ONCE to make it
my $tree = treecluster( data => $hd_ref, method => 'a' );
## then you call method cutthresh on $varname with argument
my $var_i_call_cluster_ids_also = $tree->cutthresh( $some_hdt );
## you return the value
return $var_i_call_cluster_ids_also;
} ## end sub clust_brain
__END__
| [reply] [d/l] [select] |
|
I'm going to go try this out now. I'll let you know how it turns out. A hopeful thanks in advance!!
| [reply] |
|
|