WeBWorK Problems

Gateway Quiz Problems --- What precisely can't I do?

Gateway Quiz Problems --- What precisely can't I do?

by Christopher Heckman -
Number of replies: 14
I'm teaching an online course and want to use Gateway Quizzes to give tests. There are some types of problems that won't translate (such as ans_array_extension ).

Does anyone know precisely which elements of WeBWorK authoring won't translate to Gateway?

I ask because I did a massive rewrite, getting rid of ans_array_extension (and learning about MathObjects in the process). However, I'm at the point where the problem works correctly when I try it out in the editor, but I get a weird error message when trying to take it as a GatewayQuiz:

Can't call method "data" on an undefined value at [PG]/lib/Value.pm line 698

Line 698 doesn't contain any executable code, though. WeBWorK is dying inside this code for some reason:

sub good_cs { # good_cs (A, R, r) # basis for column space
   my ($A, $R, $r) = @_;
   my ($m, $n) = $A->dimensions;
   my @a; my $i = 1;
   for (my $j = 1; $j <= $n; $j++) {
      if ($R -> element ($i, $j) > 0.5) {
         for (my $k = 1; $k <= $m; $k++) { $a[$k-1][$i-1] = $A -> element($k, $j); }
         $i ++;
         }
      }
   Matrix (@a);
}

Once again, it's only dying when actually taking a quiz.
In reply to Christopher Heckman

Re: Gateway Quiz Problems --- What precisely can't I do?

by Davide Cervone -
There should not be any restrictions with the use of MathObjects within quizzes. I suspect that if you used the seed from the quiz in the editor page, you would get the same problem.

Line 698 in the current version of [pg]/lib/Value.pm is

    $M = $M->data->[$i];
of the extract() method of the base MathObject class. Since the Matrix element calls extract, it looks like one of your element calls is the culprit.

From the code snippet you give, it appears that you are incrementing $i inside both loops (over the columns and rows), and use $i as a row index in the first element() call. I suspect that $i is getting too big and is walking off the end of the matrix.

Check that the value of $i and see if that doesn't get bigger than $m in your quiz.

In reply to Davide Cervone

Re: Gateway Quiz Problems --- What precisely can't I do?

by Christopher Heckman -
That was what it was, but the actual bug was a combination of two things which worked on their own.

Having a stack trace would be nice in the case of WeBWorK bugs, because that would have at least told me what line in the routine was causing the trouble.
In reply to Christopher Heckman

Re: Gateway Quiz Problems --- What precisely can't I do?

by Davide Cervone -
There should be a stack trace farther down in the error output. (At least there is for regular problems; I'm not sure what happens in the Quiz setting, since I've never used them.)

For me, I see something like

    Can't call method "data" on an undefined value at [PG]/lib/Value.pm line 699
    Died within Value::extract called at line 8 of (eval 2919)
    from within main::testError called at line 11 of (eval 2919)
in a section with a heading of "Error Details". It is below the listing of the problem, so look around and you might find more of the error messages below.
In reply to Christopher Heckman

Re: Gateway Quiz Problems --- What precisely can't I do?

by Christopher Heckman -
I found another quiz-only error message (i.e., the problem works fine in homework mode but bombs in gateway/quiz mode):

Can't use string ("0") as an ARRAY ref while "strict refs" in use at [PG]/lib/Matrix.pm line 305

How do I fix this one? (I didn't get any help from Googling or the Wiki.)

(BTW: Why doesn't someone put a list of WeBWorK's error messages on the Wiki, and then give a plain English description of what's wrong, and how to fix it?)
In reply to Christopher Heckman

Re: Gateway Quiz Problems --- What precisely can't I do?

by D. Brian Walton -
This is not specific to Quiz vs Homework mode. It has to do with the random seed. Some randomly generated problems are valid, and others are not.  For example, when I tried it, Seed 1234 gave an error but Seed 1247 worked.

It would take a bit more time to actually try to figure out which step needed extra error checking to avoid the error, but I thought I'd point this out up front.

Brian Walton

In reply to Christopher Heckman

Re: Gateway Quiz Problems --- What precisely can't I do?

by D. Brian Walton -
The error is occurring at the answer-checking stage, or more precisely because you sometimes have never defined the row space or column space matrix.

See the following segment from your code:
if ($rank == 2) { 
   $cs = [entries_of_column ($A, $b[0]), entries_of_column ($A, $b[1]) ]; 
   $rs = [entries_of_row ($A, 1), entries_of_row ($A, 2) ];
   } 
elsif ($rank == 3) {
   $cs = [entries_of_column ($A, $b[0]), entries_of_column ($A, $b[1]), entries_of_column ($A, $b[2]) ]; 
   $rs = [entries_of_row ($A, 1), entries_of_row ($A, 2), entries_of_row ($A, 3) ];
   }
else { $cs = 0; $rs = 0; }

Notice that if the rank is anything but 2 or 3, you are assigning the number 0 to both $cs and $rs.  The same thing happens later when defining $ns for the null space.

When doing answer checking, you use:
ANS (basis_cmp ($rs));
ANS (basis_cmp ($cs));
ANS (basis_cmp ($ns));
And this is where the error actually is thrown.

I think this could be fixed if a loop were used to generate the row space and null space.

Best wishes,
- Brian
In reply to D. Brian Walton

Re: Gateway Quiz Problems --- What precisely can't I do?

by Davide Cervone -
I see you beat me to the punch. Sorry for the repeat answer.
In reply to D. Brian Walton

Re: Gateway Quiz Problems --- What precisely can't I do?

by Christopher Heckman -
I think this could be fixed if a loop were used to generate the row space and null space.

I started out by using a loop, but I got all kinds of strange Perl errors, so I took the brute-force approach instead.
In reply to Christopher Heckman

Re: Gateway Quiz Problems --- What precisely can't I do?

by Christopher Heckman -
Actually, what happened is that when I used basis_cmp, I got an error that the "conjugate" function was not defined in that context.
  • Can't locate object method "conjugate" via package "Value::Real" at [PG]/lib/Matrix.pm line 408
    Died within Matrix::conj called at line 450 of [PG]/lib/Matrix.pm
    from within Matrix::transpose called at line 1902 of [PG]/lib/MatrixReal1.pm
    from within MatrixReal1::_transpose called at line 328 of (eval 4111)
    from within main::compare_basis called at line 565 of [PG]/lib/AnswerHash.pm
    from within AnswerEvaluator::evaluate called at line 1 of (eval 4127)
Here's the code for my "minimal criminal":

##KEYWORDS('linear algebra', 'systems of linear equations')
## DBsubject('Linear Algebra')
## Author('Christopher Heckman')
## Institution('Arizona State University')
## Section1('')
## Problem1('')

########################################################################

DOCUMENT();      

loadMacros(
   "PG.pl",
   "PGbasicmacros.pl",
   "PGchoicemacros.pl",
   "PGanswermacros.pl",
   "PGgraphmacros.pl",
   "PGmatrixmacros.pl",
   "PGnumericalmacros.pl",
   "PGauxiliaryFunctions.pl",
   "PGmorematrixmacros.pl",
   "MathObjects.pl",
   "Value.pl",
   "parserVectorUtils.pl",
);

TEXT(beginproblem());
$showPartialCorrectAnswers = 1;

Context("Complex");
Context() -> texStrings;

sub matrix2array { # matrix2array (matrix)
   my $A = shift;
   my ($m, $n) = $A -> dimensions;
   my @arr = [(0) x $m] for 1 .. $n;
   for (my $i = 0; $i < $m; $i++) { for (my $j = 0; $j < $n; $j++) {
      $arr[$j][$i] = Real ($A -> element ($i + 1, $j + 1));
      }}
   @arr;
   }

$A = Matrix ([[1,2],[3,4],[5,6]]);
$B2 = [matrix2array ($A)];

BEGIN_TEXT
Enter a list of vectors.
\{ ans_rule (25) \}
END_TEXT

Context()->normalStrings;

ANS (basis_cmp ($B2));

COMMENT('MathObject version.');
ENDDOCUMENT();    
In reply to Christopher Heckman

Re: Gateway Quiz Problems --- What precisely can't I do?

by Christopher Heckman -
UsingWW won't let me edit this post, so I should point out that I found out the solution (by "trying one last thing"):

sub matrix2array { # matrix2array (matrix)
   my $A = shift;
   my ($m, $n) = $A -> dimensions;
   my @arr = [(0) x $m] for 1 .. $n;
   for (my $i = 0; $i < $m; $i++) { for (my $j = 0; $j < $n; $j++) {
      $arr[$j][$i] = $A -> element ($i + 1, $j + 1) -> value;
      }}
   @arr;
   }

The problem was that you can't take the conjugate of a Real MathObject (this causes an error) but you can take the conjugate of a "raw float". Or, equivalently:

If your matrix entry is ...Then the conjugate function ...
Real (0)crashes
0returns 0

(BTW, the basis created by the sub consists of the columns of $A.)

In reply to Christopher Heckman

Re: Gateway Quiz Problems --- What precisely can't I do?

by Davide Cervone -
I'm glad that you figured out the problem. (You had done so before I had the chance to point that out to you.)

This has to do with the fact that there are two implementations for Matrices in WeBWorK: the MathObject matrices that you get with Context("Matrix") and the traditional ones you get from the Perl Matrix package. The latter do now know about MathObjects, and since the basis_cmp() macro uses the traditional matrices, the error you are getting is due to that incompatibility. That is one reason you can't pass a MathObject Matrix to basis_cmp() directly.

You are correct to use the value() method of the MathObject Matrix entries to get the perl reals rather than MathObjects. (Note that in your original, the Real() around the element extraction was redundant, since the Matrix entries are already MathObject Reals).

A number of the matrix macros need to be updated to work with MathObject Matrices (or the MathObject Matrices could be updated to include methods that correspond to those older macros).
In reply to Christopher Heckman

Re: Gateway Quiz Problems --- What precisely can't I do?

by Davide Cervone -
The problem file you provided sets $rank = random (3, 4); which means that $rank is either 3 or 4. The code below that checks for $rank equal to 1, 2 or 3, and sets up $rs, $cs, and $ns based on that. Note that the cases for 1 and 2 are not needed, so $rank will never be one of those, and that the case for 4 is missing. Instead, you get the else blocks, which set all three variables to 0 rather than an array reference.

In the answer section, you pass $rs and the other variables to basis_cmp(), which expects an array reference as its argument. In the case where $rank is 4 (roughly half the time), you will pass basis_cmp() the value 0 rather than an array reference. The error message you have received indicates that that is what is happening.

It would help to provide the complete error message, which in this case was

   Can't use string ("0") as an ARRAY ref while "strict refs" in use at [PG]/lib/Matrix.pm line 305
   Died within Matrix::new_from_col_vecs called at line 194 of [PG]/macros/PGmorematrixmacros.pl
   from within main::BASIS_CMP called at line 169 of [PG]/macros/PGmorematrixmacros.pl
   from within main::basis_cmp called at line 163 of (eval 10026)
Note that this indicates (bottom line) that the originating call was to basis_cmp(), so that would have told you where to look first. The obvious thing to check is the values of the arguments passed to basis_cmp(), which is what I did, and found $rs equal to 0, an invalid value for basis_cmp(). Looking back to see where $rs was set allowed me to see what the problem was.

Note that this is an error produced by Perl itself (the language underlying WeBWorK), and not a message from WeBWorK specifically. It would be difficult to list all the messages that Perl could produce, and harder yet to tell you how to fix the problems. The message already said what was wrong (a 0 was used where an array was expected), and told you where that occurred (in basis_cmp()). That is about as good as we can expect from the system, in my opinion. I don't see how it could tell you where to look earlier in your code for the true cause of the problem.

In reply to Davide Cervone

Re: Gateway Quiz Problems --- What precisely can't I do?

by Christopher Heckman -
Ah, the perils of re-using code ...

But why did it say 
 Can't use string ("0") as an ARRAY ref
and not
 Can't use string ("0") as an ARRAY ref
then? Why did the 0 get converted into a string?
In reply to Christopher Heckman

Re: Gateway Quiz Problems --- What precisely can't I do?

by Davide Cervone -
Both errors you list are the same, but I'm assuming that the second is supposed to be
  Can't use real (0) as an ARRAY ref
or something like that.

The error message comes from a line that includes

    $vec->[0]
where $vec is the value you passed to basis_cmp() (the zero in this case). Perl doesn't have "hard" types like a language such as C++ has, and $code is what Perl terms a "scalar" value. That could be a number, a string, a reference to an array or an object, or a few other things. Perl will convert between types automatically as needed, so no explicit type coercion is needed in most cases.

The -> in $vec->[0]asks Perl to dereference a reference to an object of some kind, and so the scaler $vec is supposed to be either a reference to an object, or a string that is the name of an object class. (E.g., Value->Error() is valid because Value is the name of a class). So Perl tries to make the number 0 into a valid scalar that can be used on the left of ->. In this case, it can't covert to an object reference, so converts to a string in hopes that the string value will be the name of a class (in Perl, a "package"). but the string 0 is not the name of a class, so you get the error.