reduce()
function in PGauxiliaryFunctions.pl
, which is being loaded by PGstandard.pl
, so your sub reduce
doesn't seem to be redefining that, and the reduce()
call you are making is actually to the original one. That macro is supposed to reduce two values to lowest terms, and it expects two arguments. Since you haven't passed it any, the one that it called $num
is undefined, and so on line 206 of PGauxiliaryFunctions.pl
, this is causing problems. I suspect there will be messages in the server log about attempts to redefine reduce()
, but I haven't checked that.There are two approaching to solving the problem: either rename your
reduce()
to something else (like Reduce()
or ReduceMatrix()
), or don't load PGstandard.pl
and load the files it refers to manually.I agree that the references to
... line x of (eval y)
are not very helpful. At one point I had added code to translate the eval y
references back to the files that they came from, but somewhere along the line that seems to have been removed. I will have to look into putting it back.Davide
reduce()
is compiled first, and then the loadMacros()
runs, running the contents of the macro files dynamically, so they are compiled second, overriding your version. But I haven't experimented to see if that is true.
As for passing the matrix, I don't think this is the way you want to do it. Here are some issues to think about. Suppose you have an array
@C = (1,2,3);and then pass that to a function
sub Example { my @M = @_; ... } Example(@C);this means that you are actually passing the array by value, not by reference. That means the contents of the array
@C
are passed as three parameters to the function, just as though you had entered
Example(1,2,3);and
@M
will get a copy of the original array. So if you change @M
in the subroutine, that doesn't change @C
. (Although you could return the array @M
and use
@C = Example(@C);though that is not the most efficient approach.)
When you make your matrix as
@C = ([1,2],[3,4]);this means that
@C
is an array of references to arrays, so when you pass this to the subroutine
Example(@C);you are passing the array by value, but the values passed are the references to the row arrays, so those references are copied, they still refer to the same rows. That means that if you did
$M[0][1] = 100;that would change the 2 to a 100 in the
@C
matrix. But if you did
($M[0],$M[1]) = ($M[1],$M[0]);in the subroutine, that would not exchange the rows in
@C
An alternative approach would be to use an array reference rather than an array, as in
$C = [[1,2],[3,4]]; Example($C);In this case, you would use
$C->[0][1]
rather than $C[0][1]
to get access to the 2 in the matrix. If you use
sub Example { my $M = shift; ... }then you can use
$M->[$i][$j]
within the subroutine, and if you do
($M->[0],$M->[1]) = ($M->[1],$M->[0]);this will change
$C
as well, because you have passed a reference to the array of references (rather than passing all the row references by value).
It is also possible to pass a reference to @C
. In Perl, you would use
Example(\@C);but in PG, all backslashes are doubled, so that doesn't work. Instead, PG uses
~~
to get a single backslash (awkward, but that's how it works). So you could use
sub Example { my $M = shift; ... } @C = ([1,2],[3,4]); Example(\@C);to pass the reference to
@C
.
Hope that answers your question.
Davide
Davide
Regarding the radio buttons options, it's probably worth noting that the syntax [ 0, 1, 2 ]
is just a reference to an array. So we can generate arbitrary options by resorting to Perl. Before doing that, a couple of notes about Perl and references might be useful.
@a = ( 0, 1, 2 ); # an array $a = \@a; # a reference to that array $b = [ @a ]; # a reference to a copy of the array $c = [ 0, 1, 2 ]; # a reference to an anonymous array
With this in mind, it may be obvious(?) how to resolve your problem. If $matrix_size
is the size of your matrix, then we could do any of
@a = (); for ( my $i=0; $i<=$matrix_size; $i++ ) { $a[$i] = $i; } $mc = RadioButtons( [@a], $rank ); # or @a = ( 0..$matrix_size ); # the array (0,1,...,$matrix_size) $mc = RadioButtons( [@a], $rank ); # or $mc = RadioButtons( [(0..$matrix_size)], $rank );
Note that these take advantage of the fact that Perl is an untyped language: we can take @a=(0,1);
or @a=("0","1");
and the two will be equivalent. If the options for the buttons were explicitly strings (e.g., "one", "two", etc.) we wouldn't be able to use the list expansion operator ..
, which fills in all values between the starting and ending one.
And I'm guessing that the rank 1 dimension error is the bug that Davide fixed recently; see my post to the main WeBWorK forum about dimension 1 matrices.
Hopefully that's helpful!
Gavin