WeBWorK Problems

Two versions of a correct str_cmp answer possible?

Two versions of a correct str_cmp answer possible?

by Paul Seeburger -
Number of replies: 8

I am using a str_cmp checker to evaluate student input of an inequality involving two variables, since I have not yet found a nicer way to do this.

I want to know if there is a way to allow two or more possible strings as correct answers for one answer blank.

For example, I want "x^2 + y^2 < 10" and "y^2 + x^2 < 10" to both be considered correct.  I can be okay without "10 > x^2 + y^2", even though this should also be equivalent, since it is not quite as nice in form.

Currently, I can check either one individually, but the other option is considered incorrect using the following code:

$domain = "x^2 + y^2 < $a";
ANS( str_cmp($domain,'remove_whitespace'));

Similarly, if I want to allow students to enter the whole set-builder notation for the domain of a function of two variables, I want a way to allow either of the following options [using ':' or '|' between (x, y) and the condition]:

"{ (x, y) : x^2 + y^2 < 10}" or "{ (x, y) | x^2 + y^2 < 10}"

And then there is the combination of both variations to consider...

I suppose a Context could be created or a custom answer checker may be needed, but is there already an easy way to do this?

If I do use a custom checker, how can I remove the white space in the student answer to do the compares myself?

Can I replace the '|' with a ':' in the student answer before checking it?

Thanks!

Paul

In reply to Paul Seeburger

Re: Two versions of a correct str_cmp answer possible?

by Davide Cervone -
You could try using the contextArbitraryString.pl macro file, which allows you to use MathObjects to essentially get unparsed student answers. See comments at the top of the file for details. Bascially, you could do something like
    loadMacros("contextArbitraryString.pl");
    Context("ArbitraryString");
    
    ANS(Compute("The string I want")->cmp(checker => sub {
      my ($correct,$student,$ans) = @_;
      $student = $student->value; # get student answer string
      $student =~ s/ //g; # remove whitespace
      return $student eq "{(x,y):x^2+y^2<10}" ||
             $student eq "{(x,y):y^2+x^2<10}";
    }));
Again, I don't recommend this approach to handling answers that include mathematics, as student could write correct answers in other ways, e.g.,
    { (x,y) : 10 > x^2 + y^2 }
    { (x,y) : x^2 < 10 - y^2 }
    { (x,y) : (x+y)^2 < 10 + 2xy }
or any of a number of other ways. To really handle all the cases, you would effectively have to write your own parser, and that is just not worth it.
In reply to Davide Cervone

Re: Two versions of a correct str_cmp answer possible?

by Paul Seeburger -

Thanks again, Davide!!

This looks quite useful!  And you demonstrated a way to replace characters from the student answer with something else also, if I am not mistaken.

If I wanted to allow "2*x + 1" as a correct version of "2x + 1", I could use the line

$student =~ s/*//g;

to remove the * symbol, am I right?

This may also allow me to handle some of the other possible alternate acceptable forms to solutions.

I do have  a certain form of the condition in mind that I would accept on written work here, since I stress the importance of giving the clearest possible form of the condition (and not just any equivalent form).  This may give me that kind of control where a context driven solution may allow forms of the condition to be marked correct that I would not want to be given credit.

For example, I would not give full credit to any of the following:

 { (x,y) : 10 > x^2 + y^2 } { (x,y) : x^2 < 10 - y^2 } { (x,y) : (x+y)^2 < 10 + 2xy } 



                                    
In reply to Paul Seeburger

Re: Two versions of a correct str_cmp answer possible?

by Davide Cervone -
If I wanted to allow "2*x + 1" as a correct version of "2x + 1", I could use the line

   $student =~ s/*//g;
to remove the * symbol, am I right?
No. The * is a special symbol in regular expressions (that's the name of the pattern-matching mechanism for substitutions like this). It means "the previous thing repeated 0 or more times", but since there is no repeated thing, this is an error. For example, /a*/ would match any number (including 0) of a's, while /[0-9]*/ would be any number of digits (and possibly none).

To get a literal asterisk, you need to quote it, usually with a backslash in perl. E.g., /\*/. But in PG, backslashes are doubled automatically (so that you don't have to double them by hand for TeX commands). That means /\*/ would become /\\*/, which is represents any number of backslashes in a row (including none). That's not what you want. So PG uses ~~ to represent a single backslash (sigh). That means you need to use

    $student =~ s/~~*//;
to remove asterisks.

I don't think this is really what you want to do, however. That will make some incorrect answers into correct ones. For example, if the correct answer is 6x then 6**x (six to the x power) will be marked correct, as will 6*x*, which is not even a syntactically correct expression.

Furthermore, some correct answers will be marked incorrect. E.g., 3*2*x (a correct answer) will become 32x (an incorrect one).

This type of pattern-based substitution is fraught with pitfalls. Evaluating these types of answers as strings is the wrong approach, and you are just going to get into trouble trying to do it this way.

  • You are not going to be able to handle all the correct answers in a reasonable way (the number of permutations is too great).
  • You will mark some correct answers incorrect and some incorrect answers correct (as shown above).
  • You will not get the usual syntax checking on the expressions, or the helpful error messages when students enter invalid equations.
  • Your questions will work substantially differently from all the other WeBWorK problems you may assign (that do proper syntax checking).
  • Even if you do provide some error messages, these will not be consistent with the ones produced by MathObjects, which can be a source of needless confusion for students.

You may think that this is requiring clarity, but students will see it as either broken or arbitrary unless you are very specific about the format you are expecting. And I don't see how you can be without giving away the answer. Saying it is the "clearest" or "simplest" form is not sufficient, in my opinion.

Your sense of what is clear or simple is something that you have developed over many years of mathematical experience. That is experience that calculus students don't have, and do not achieve over night. Unless your problems give a lot of support about obtaining the desired format (in terms of syntax messages and hints when their format isn't correct), I think you have a recipe for disaster.

While it is possible to write context's that do provide that type of support, it is not trivial, and you have to be very explicit about what is allowed and what isn't. Since that probably varies from problem to problem, it is usually not practical to go that way.

WeBWorK's philosophy has always been that equivalent answers are correct, even if they are written in an unusual way. The student answer is restricted only for specific situations (e.g., factoring a polynomial, giving an answer as a fraction rather than a decimal, etc.), and then only when it is made clear to the student what that format is. Students who use WeBWorK will have come to expect that. If you intend to change that paradigm, you are going to have to be very clear with your students about that.

In reply to Davide Cervone

Re: Two versions of a correct str_cmp answer possible?

by Paul Seeburger -

Thanks again, Davide!

I appreciate your comprehensive understanding of the workings of WebWork!

First, I did figure out a way to remove the '*'.  I used:

$student =~ tr/ *//d;

This actually took out the asterisk and also took out extra spaces.  Maybe I just got lucky though and it is not really doing what I thought, but it seems to be working correctly.

I can see that I am still approaching these problems from a different philosophy (maybe I will be convinced otherwise someday).  My hopes for my WebWork problems is to help my students become proficient in both the mechanics of these problems and also the notation and form of the steps to get to the answers as well as the answers.

For me, the form of the answer is often important, as I would guess it is for you as well, at least on paper.  I would like to train my students through WebWork problems to use the same proper notation and steps to show their clear work (and answers) as I would expect on paper.

Because of this expectation, I am doing what I can to find ways to require exact answers where appropriate (especially to definite integrals, etc.) and acceptable forms for answers in problems like the one in this thread.  I can see that some variation may be acceptable, but there are a small collection of forms that I want students to naturally use to describe the domain of a function of two variables (in a two-dimensional way).  I do not need these problems to give credit for every mathematically equivalent answer.  I just want them to give credit for the answers I would count as correct on paper, and to hopefully give the students some helpful hints in the right direction when they make common mistakes.

Thanks again, Davide!

Paul

In reply to Paul Seeburger

Re: Two versions of a correct str_cmp answer possible?

by Davide Cervone -
$student =~ tr/ *//d;

Yes, that will get rid of all the asterisks in the student answer. This will have the side-effect of making some correct answers incorrect and some incorrect answers correct, as I describe above. I think this is asking for trouble.

I would like to train my students through WebWork problems to use the same proper notation and steps to show their clear work (and answers) as I would expect on paper.

I don't think WeBWorK is particularly well suited to that goal. But you have to do what you think is best.
In reply to Paul Seeburger

Re: Two versions of a correct str_cmp answer possible?

by Davide Cervone -
Just as an example of the complication that you are going to face, if you wanted
    y = (1+3x)/2
as an answer, I think you would need to accept all of the following:
  y = (1+3x)/2
  y = 1/2 + 3x/2
  y = 1/2 + (3/2)x
  y = 1/2 + (3x)/2
  y = (1/2)(1+3x)
  y = .5 + 1.5x
  y = .5 + (3/2)x
  y = 1/2 + 1.5x
  y = .5(1+3x)
  y = (3x)/2 + 1/2
  y = 3x/2 + 1/2
  y = (3/2)x + 1/2
  y = (3x)/2 + 1/2
  y = (1/2)(3x + 1)
  y = 1.5x + .5
  y = (3/2)x + .5
  y = 1.5x + 1/2
  y = .5(3x+1)
  y = (1+3*x)/2
  y = 1/2 + 3*x/2
  y = 1/2 + (3/2)*x
  y = 1/2 + (3*x)/2
  y = (1/2)(1+3*x)
  y = (1/2)*(1+3*x)
  y = (1/2)*(1+3x)
  y = .5 + 1.5*x
  y = .5 + (3/2)*x
  y = 1/2 + 1.5*x
  y = .5(1+3*x)
  y = .5*(1+3*x)
  y = .5*(1+3x)
  y = (3*x)/2 + 1/2
  y = 3*x/2 + 1/2
  y = (3/2)*x + 1/2
  y = (3*x)/2 + 1/2
  y = (1/2)*(3x + 1)
  y = (1/2)*(3*x + 1)
  y = (1/2)(3*x + 1)
  y = 1.5*x + .5
  y = (3/2)*x + .5
  y = 1.5*x + 1/2
  y = .5(3*x+1)
  y = .5*(3*x+1)
  y = .5*(3x+1)
I would also accept things like
  y = (1/2)+((3x)/2)
  y = (1+(3x))/2
  ...
and so on. You may say that you would not accept extraneous parentheses; but one of the things that looking at student answers clearly shows is that their understanding of parentheses is not very good, and they don't know what is extraneous and what isn't.

Then there is the question of whether to accept

   2y = 1 + 3x
and all its permutations. This is "simpler" than y=(1+3x)/2 in some ways, so perhaps that is better.

Trying to deal with all these as string comparisons is going to be impractical. That is why we used parsed expressions, because that understands the mathematical meaning, whereas string comparisons don't. The parsing also allows for syntax errors to be generated automatically, and type checking to be performed.

Direct string processing is never going to be as effective.

In reply to Davide Cervone

Re: Two versions of a correct str_cmp answer possible?

by Paul Seeburger -

Ok, Davide, I tried this checker in one of my domain problems and it seems to work, but the displayed correct answer (when the student answer has been entered) is coming up with "x2 + y2 lt; 17" in place of the "x^2+y^2<=17" that I put in as "The string I want" in your code.  The funny thing is that in the Preview pane, the <= is displayed as is.

See my code below:

ANS(Compute("x^2+y^2<=$a")->cmp(checker => sub {
my ($correct,$student,$ans) = @_;
$student = $student->value; # get student answer string
$student =~ s/ //g; # remove whitespace
return $student eq "x^2+y^2<=$a" ||
$student eq "y^2+x^2<=$a";
}));

Any ideas on how to make the correct answer display correctly?

Also, why does the macro make the exponents look pretty but leave the <= as is in the Preview of the student answer and not make it look nice with ≤.

I assume this approach will make it possible for me to also give meaningful answer hints for certain common incorrect (or non-simplest) forms of the answer.

Thanks again!

Paul

In reply to Paul Seeburger

Re: Two versions of a correct str_cmp answer possible?

by Davide Cervone -
The first thing you should do is get an updated copy of contextArbitraryString.pl and either replace the one in pg/macros or put it in your course's templates/macros directory. This fixes a number of display issues.

But it will show the result as a text string (verbatim), not as formatted mathematics. That's because you are using an arbitrary string, not parsed mathematics, so it shows the string. There is no guarantee that the student answers (or the professor's for that matter) is valid mathematical expression, and so there is no guarantee that it can be turned into a TeX expression.

And even if it could, the way that is done is to use a Context to parse the math into a valid MathObject, and then ask that MathObject to produce its TeX form. Your context treats everything as a string, and the TeX form of a string is a verbatim version of itself, so x^2+y^2<=10 should show up exactly like it was typed (no powers, and no conversion of <=).

To get something better, you would need to have a context in which things like <= are defined and can produce their proper TeX forms. That's not what you currently have.

There is a contextTypeset.pl file that includes a context that provides the ability to generate TeX without having to have mathematics that MathObjects knows how to evaluate (just typeset). That could be used to replace the TeX that the ArbitraryString context has places in the AnswerHash. You would use an answer post-filter for that. But there is no guarantee that the student answer can be converted even using that (if it has other syntax errors).

As I said, using raw strings for evaluating mathematical answers is fraught with pitfalls.