Forum archive 2000-2006

Nandor Sieben - evaluator swallowing more than one answer boxes

Nandor Sieben - evaluator swallowing more than one answer boxes

by Arnold Pizer -
Number of replies: 0
inactiveTopicevaluator swallowing more than one answer boxes topic started 6/29/2005; 10:27:48 PM
last post 7/4/2005; 6:54:02 PM
userNandor Sieben - evaluator swallowing more than one answer boxes  blueArrow
6/29/2005; 10:27:48 PM (reads: 1548, responses: 11)
How can I write an evaluator that eats up several answer boxes? I know that I could ask for a comma separated list rather than several answer boxes but this is a little inconvenient in the application we have in mind. I am not absolutely sure but I belive basis_cmp can do this. Unfortunately basis_cmp is a little complicated so I couldn't figure out how exactly this is done. If I understand it correctly ANS simply fills a list with evaluators. Then I think there must be another list containing as many elemnts as answer boxes. Then a function checks if these two lists have the same size and calls the evaluators one by one with the corresponding student answers. Is this correct? I'd like to somehow change this and have only 2 evaluators and 3 answers and call the second evaluator with the last 2 answers. Nandor

<| Post or View Comments |>


userDavide P. Cervone - Re: evaluator swallowing more than one answer boxes  blueArrow
6/29/2005; 11:08:02 PM (reads: 1787, responses: 0)
You might try the MultiPart object that is part of the new Parser. It allows you to have one answer checker that operates on more than one answer blank. See the discussion at

http://webhost.math.rochester.edu/webworkdocs/discuss/msgReader$3277#3300

for details. If you are really intent on writing your own, it is a bit complicated, but can be done.

Davide

<| Post or View Comments |>


userMichael Gage - Re: evaluator swallowing more than one answer boxes  blueArrow
6/29/2005; 11:34:09 PM (reads: 1828, responses: 0)
One way to do this, built in to the older answer checkers such as checkbox_cmp, uses the fact that if several inputs blanks (ans_rules) have the same name they are all returned as a pointer to an array. (There was an older CGI mechanism where they were returned as nul separated lists) If you look at some of the code it might look a bit complicated because it takes both possibilities into account. The code in AnswerEvaluator->get_student_answer will show you what is being done.

In any case as a simple test try inserting three answer blanks -- the last two with the same name. Then use two answer evaluators -- the last one should get a pointer to an array with two elements. In practice the order of the answers appears in the same order as the blanks, jsut what you would "expect" , but there is no guarantee in the HTML spec -- in fact it says explicitly that you can't rely on the order. None-the-less many of our routines do depend on the order and so far all browsers have met our expectation.

For the tools used in producing the answer blanks look at NAMED_ANS_ARRAY_EXTENSIONS and related macros in PGbasicmacros.pl and at some of the ...._NAME and ...NAME_EXTENSTION macros in PG.pl. The last four macros in Davide's parserMultiPart.pl use the low level routines in PG to mask the complexity.

The trickier work is in naming the answer blanks correctly. Once that is done the the browser/mod_perl software takes care of passing the group of answers as a referenece to an array.

This is not really a complete explanation, but I hope i've given you some useful ideas of where to look in order to understand the process.

-- Mike

<| Post or View Comments |>


userEdgar Fisher - Re: evaluator swallowing more than one answer boxes  blueArrow
7/3/2005; 7:46:59 PM (reads: 1771, responses: 0)
What do you mean by "name the answer the blanks with the same name"? I have done this:
################################################
sub Iso_build{
my($width) = @_;
ans_rule($width);
}
################################################
sub Iso_Eval{
my (%vals) = @_;
sub {
my @stud_in = @_;
$score = 1;
$message = '';



my $ans_hash = { score => $score,
correct_ans => '',
student_ans => '',
preview_latex_string => '',
ans_message => ($score) ? '' : $message
};
$ans_hash;
}
}
################################################

I then call the function Iso_build twice and use ANS(Iso_Eval()) but it only evaluates one answer.... I tried looking at the other files listed, but don't see implementation of randomly named objects and subroutines. Only the previously defined ones.

<| Post or View Comments |>


userMichael Gage - Re: evaluator swallowing more than one answer boxes  blueArrow
7/3/2005; 9:49:51 PM (reads: 1777, responses: 0)
What you are trying to do is a bit complicated and I don't have a simple model to point you to. If you haven't read Managing answers yet start there -- it gives an overview of most of the mechanism used to connect an answer blank with an answer evaluator.

ans_rule, by itself, automatically increments the label for the answer blank (e.g. AnSwEr01, AnSwEr02) etc. so all of your answers above had individual answers.

The next thing to look at is the description at PGbasicmacros.pl about answer blanks. I think the closest thing to what you want is the ANS_RADIO and ANS_RADIO_OPTION. There is also an ANS_CHECKBOX and ANS_CHECKBOX_OPTION, but you will need to read the actual code in PGbasicmacros.pl to see how that works.

A model of how to evaluate these input vectors together is checkbox_cmp in PGanswermacros.pl (again you will have to read the code, the pod documentation is incomplete). This is not the best model, since it does not use an AnswerEvaluator which will do much of the work for you. It is however a place to start. (AnswerEvaluators are described in AnswerHash.pm)

The linear algebra macros in PGmatrixmacros.pl and PGmorematrixmacros.pl handle more complicated situations. The examples in Davide Cervone's MultiPart.pm object are the most recent and the cleanest.

Hope this helps.

-- Mike

<| Post or View Comments |>


userEdgar Fisher - Re: evaluator swallowing more than one answer boxes  blueArrow
7/4/2005; 2:31:13 PM (reads: 1739, responses: 0)
Ok, I now have a handle on how to call the evaluator with an array of answers. However, I was wondering about a couple of things. First, I tried the @{$in} stuff and it doesn't work. Instead I have to use @list = split "\0", @in[0], which the docs say is old hat.

Also, is there any way to have each answer blank display only that value in the answer preview box? Along with that is whether there is a way to not change the value in the answer boxes. They all become the value of the first box because of this function call. I have looked in the files and not found where I can change that. I will continue to look, but need some help finding the right lines to look at.

<| Post or View Comments |>


userMichael Gage - Re: evaluator swallowing more than one answer boxes  blueArrow
7/4/2005; 3:12:10 PM (reads: 1715, responses: 0)
This seems to be browser and or CGI dependent. I have a feeling that mod_perl has gone back to the \0 method for separating answers. I'm also seeing the null separated string method so I'm wondering if the switch from CGI to mod_perl has caused this. In any case if you use AnswerEvaluator objects the method get_student_answer automatically protects you from this.

I'm not sure if you can get the control you ask for using this version of multiple answers. There is a more sophisticated version of analyzing multiple answers for one evaluator which is used by some of the linear algebra problems. This allows the labels for the inputs to be different. It was written by Liam Rafferty under Arnie Pizer's direction and I can't yet give precise directions on its use (there is no documentation). The answer labels involved start with ArRaY -- you'll find the code in PG.pl and in PGmorematrixmacros.pl in BASIS_CMP -- the important filter is ans_array_filter.

It might help if you can give us a sample version of the kind of problem you are trying to check. There might be simpler tools that would allow for answer evaluation. Could you post the code of a simple version of the type of problem you are writing?

-- Mike

<| Post or View Comments |>


userEdgar Fisher - Re: evaluator swallowing more than one answer boxes  blueArrow
7/4/2005; 3:32:53 PM (reads: 1720, responses: 0)
The context of the problem is given some graphs, find which are isomorphic and from those, what is a vertex correspondence between them. So I can't simply use a string compare because there is likely more than one correspondence, especially with random graphs. This is about as simple as I could make it and still retain the basic shape of the question and my problems.
loadMacros("PGstandard.pl");



TEXT(&beginproblem);
$showPartialCorrectAnswers = 1;



$size = random(6,7);
$table = begintable($size);



@letters = ('A'..'G');
push @row1, "Original Vertices";
push @row2, "Isomorphic Vertices";



for ($i = 0; $i < $size; $i++){
push @row1, $letters[$i];
push @row2, NAMED_ANS_RULE('iso_ans', 1);
}
$table .= row(@row1);
$table .= row(@row2);
$table .= endtable();
################################################
sub Iso_Eval{
my ($graph) = @_;
sub {
my @stud_in = @_;



@list = split "\0", @stud_in[0];
$score = 1;
$message = 'Good';
$text = join ',', @list;
my $ans_hash = { score => $score,
correct_ans => '',
student_ans => $text,
preview_latex_string => @list,
ans_message => ($score) ? '' : $message
};
$ans_hash;
}
}
################################################
BEGIN_TEXT
$BR
From the given graphs (omitted), list the vertex correspondence between them
in the following table.
$BR
$table
$BR
END_TEXT



NAMED_ANS("iso_ans", Iso_Eval(5));



ENDDOCUMENT();

<| Post or View Comments |>


userMichael Gage - Re: evaluator swallowing more than one answer boxes  blueArrow
7/4/2005; 6:06:34 PM (reads: 1726, responses: 1)
# Here is an initial suggestion.  This will allow you to check your graphs.
# the handling of errors won't be ideal
# I think you'll want to use ideas from PGmorematrixmacros.pl for that
# remember to CHANGE ~~ to \ when moving subroutines to a .pl file!!!




DOCUMENT();



loadMacros(
"PGstandard.pl",
PGmorematrixmacros.pl,
PGanswermacros.pl,
);



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



$size = random(6,7);
$table = begintable($size);



@letters = ('A'..'G');
push @row1, "Original Vertices";
push @row2, "Isomorphic Vertices";



for ($i = 0; $i < $size; $i++){;
push @row1, $letters[$i];
push @row2, NAMED_ANS_RULE('iso_ans', 1);
};
$table .= row(@row1);
$table .= row(@row2);
$table .= endtable();
################################################
sub Iso_Eval {
my $graph = shift; # correct answer object
# routines to handle options in standard ways
my %options = @_;
# standard methods for handling options
# CHANGE ~~ to \ when moving to a macro .pl file!!!!!
assign_option_aliases(~~%options,

);
set_default_options(~~%options,
'debug' => 0,
'type' => 'Iso_Eval',
);

my $answer_evaluator = new AnswerEvaluator(
correct_ans => $graph,
);
# initialize debug feature. debug=>1 prints out trace
$answer_evaluator->{debug} = $options{debug};

# You can install pre_filters massage/normalize the student answers and correct answers
#Here is the actual evaluation
$answer_evaluator->install_pre_filter( sub {
my $rh_ans = shift;
# insert code to compare $rh_ans->{student_ans} and $rh_ans->{correct_ans}
$rh_ans; # return answer hash
});

# You can install post_filters to clean up error messages and so forth

$answer_evaluator;
}
################################################
BEGIN_TEXT
$BR
From the given graphs (omitted), list the vertex correspondence between them
in the following table.
$BR
$table
$BR
END_TEXT



NAMED_ANS("iso_ans"=> Iso_Eval(5) );



ENDDOCUMENT();

<| Post or View Comments |>


userDavide P. Cervone - Re: evaluator swallowing more than one answer boxes  blueArrow
7/4/2005; 6:44:12 PM (reads: 1994, responses: 0)
OK, here is another approach, based on using WeBWorK's tools for this. It's not a completely happy solution, but my MultiPart object was supposed to be that. Anyhow, here it is.

 


 

    DOCUMENT();        # This should be the first executable line in the problem.


loadMacros(
"PG.pl",
"PGbasicmacros.pl",
"PGanswermacros.pl",
);


TEXT(&beginproblem);


#
# This will only work once in a problem (you would need to
# keep track of the rule separately if you wanted multiple
# sets of answers in a single problem).
#
$ruleCount = 0;
sub extra_ans_rule {NAMED_ANS_RULE_EXTENSION(RECORD_FORM_LABEL("Part".(++$ruleCount)),@_)}


sub myChecker {
my @correct = @_;


my $ans = new AnswerEvaluator;
$ans->ans_hash(
correct_ans => join(", ",@correct), # show all answers in one line
type => "multiple answer", # or whatever you want
);


$ans->install_evaluator(sub {
my $ans = shift;
my @correct = @_;


#
# Collect student answers from $inputs_ref
#
my @student = ($ans->{student_ans});
foreach my $i (1..$ruleCount) {
my $x = $inputs_ref->{"Part$i"}; $x = "" unless defined($x);
push(@student,$x);
}


#
# Check student's answers against professor's
#
$ans->score(1); my @latex = ();
foreach my $i (0..$ruleCount) {
$student[$i] =~ s/(^ +| +)//g; # trim leading and trailing spaces
### need to do error checking on student answers here ###
$ans->score(0) if ($correct[$i] ne $student[$i]);
if ($student[$i] eq "") {push(@latex,"\_\_"); $student[$i] = "__ "}
else {push(@latex,"{\rm $student[$i]}")}
}
$ans->{preview_latex_string} = join(", ",@latex);
$ans->{student_ans} = join(", ",@student);


return $ans;
},@_);


# don't do blank check (so if the first blank is empty, we still get called)
$ans->install_pre_filter('erase');


return $ans;
}


BEGIN_TEXT
Enter A and B: \{ans_rule(2)\}, \{extra_ans_rule(2)\}
END_TEXT


ANS(myChecker('A','B'));


ENDDOCUMENT(); # This should be the last executable line in the problem.

 


The key parts to note are that NAMED_ANS_RULE_EXTENSION creates an answer rule that is not tied to an answer checker, and RECORD_FORM_LABEL makes its contents be retained by the WW database (so the student's answers for this blank will be recorded).

The first rule is a normal one that gets associated with an answer checker, but the second (and potentially more) blanks are not. The first answer checker has to look up the values that have been entered by the student. This is done by accessing the $input_refs array reference.

This sample doesn't do any error checking, but you would probably want to do that in the loop at the location indicated. Also, the check given here is just a straight string compare between the student and professor answers. Obviously, you would need to do whatever you need to do to check your graph.

Note that the checker handles creation of the answer preview LaTeX string and combines the student (and correct) answers into a single string. Since the student answers are shown in a single row of the answer response area at the top of the page, the answers are separated by commas, and underscores are used to mark any blank entries to make them more visible.

Finally, I have used an AnswerEvaluator object rather than pure code, to give you an example of how to do that.

Hope that is clear.

 


On the other hand, I still think the Parser's MultiPart object is a better choice for this. Here is another example, this time based on the MultiPart object. All the complexity of dealing with the answer rules, combining answers, looking up student answers, error checking and reporting, and so on, have been handled by the MultiPart. You just have to be concerned with the check you want to perform.

 

    DOCUMENT();        # This should be the first executable line in the problem.


loadMacros(
"PG.pl",
"PGbasicmacros.pl",
"PGanswermacros.pl",
"Parser.pl",
"contextString.pl",
"parserMultiPart.pl",
);


TEXT(&beginproblem);


Context("String")->strings->are(
A => {caseSensitive=>1},
B => {caseSensitive=>1},
);


$mp = MultiPart("A","B")->with(
singleResult => 1,
checker => sub {
my ($correct,$student,$self) = @_; # get the parameters
for my $i (0..scalar(@correct)-1) {
return 0 if $correct->[$i] != $student->[$i];
}
return 1;
},
);


BEGIN_TEXT
Enter A and B: \{$mp->ans_rule(2)\}, \{$mp->ans_rule(2)\}
END_TEXT


ANS($mp->cmp);


ENDDOCUMENT(); # This should be the last executable line in the problem.

 


Here, we set up a string context for the labels that we want the student to enter. (You could use numbers as strings if you want.) The rest is pretty simple: just do whatever check you want to do in the checker routine.

Hope one of these suits your needs.

Davide

<| Post or View Comments |>


userMichael Gage - Re: evaluator swallowing more than one answer boxes  blueArrow
7/4/2005; 6:54:02 PM (reads: 1715, responses: 0)
I was going to suggest looking at the code in the subroutine ans_array_filter PGmorematrixmacros.pl, which works similarly to the first example that Davide gives above, however I also think his MultiPart object gives a more elegant handling of the problem.

I volunteer to look into rewriting BASIS_CMP to use the MultiPart object unless someone thinks this is a bad idea.

-- Mike

<| Post or View Comments |>