[system] / trunk / pg / macros / answerComposition.pl Repository:
ViewVC logotype

View of /trunk/pg/macros/answerComposition.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5551 - (download) (as text) (annotate)
Tue Oct 2 20:48:05 2007 UTC (12 years, 2 months ago) by sh002i
File size: 6854 byte(s)
improved formatting for docs -- these were in pod sections but were all
formatted as verbatim sections, and i moved them into normal paragraphs,
lists, etc. should make things more readable from the web.

    1 =head1 NAME
    2 
    3 answerComposition.pl - An answer checker that determines if two functions
    4 compose to form a given function.
    5 
    6 =head1 DESCRIPTION
    7 
    8 answerComposition.pl provides an answer checker that determines if two functions
    9 compose to form a given function. This can be used in problems where you ask a
   10 student to break a given function into a composition of two simpler functions,
   11 neither of which is allowed to be the identity function.
   12 
   13 =cut
   14 
   15 sub _answerComposition_init {}; # don't reload this file
   16 
   17 =head1 MACROS
   18 
   19 =head2 COMPOSITION_ANS
   20 
   21  COMPOSITION_ANS($f, $g, %options)
   22 
   23 An answer checked to see if $f composed with $g matches a given function,where
   24 $f and $g are one possible decomposition of the target function, and options are
   25 any of the options allowed by composition_ans_list() below.
   26 
   27 $f and $g are used to display the "correct" answer, and the composition is
   28 computed from them.
   29 
   30 This function actually supplies TWO answer checkers, for the two previous answer
   31 blanks.  So be sure to call it immediately after the answer blanks have been
   32 supplied. (It may be best to use the NAMED_COMPOSITION_ANS checker below, which
   33 specifies the answer blanks explicitly.)
   34 
   35 Example:
   36 
   37  BEGIN_TEXT
   38  \(f\circ g = (1+x)^2\) when
   39  \(f(x)\) = \{ans_rule(20)\} and \(g(x)\) = \{ans_rule(20)\}
   40  END_TEXT
   41  COMPOSITION_ANS("x^2","1+x");
   42 
   43 =cut
   44 
   45 sub COMPOSITION_ANS {
   46   my $f = shift; my $g = shift;
   47   my $fID = ANS_NUM_TO_NAME($main::ans_rule_count-1);
   48   my $gID = ANS_NUM_TO_NAME($main::ans_rule_count);
   49   my %ans = composition_ans_list($fID=>$f,$gID=>$g,@_);
   50   ANS($ans{$fID},$ans{$gID});
   51 }
   52 
   53 =head2 NAMED_COMPOSITION_ANS
   54 
   55  NAMED_COMPOSITION_ANS($fID=>$f, $gID=>$g, %options)
   56 
   57 An answer checked to see if $f composed with $g matches a given function, where
   58 $fID and $gID are the names of the answer rules for the functions $f and $g, and
   59 $f and $g are the answers for the functions. %options are any of the options
   60 allowed by composition_ans_list() below.
   61 
   62 This routine allows you to put the answer blanks for $f and $g at any location
   63 in the problem, and in any order.
   64 
   65 Example:
   66 
   67  BEGIN_TEXT
   68  \(g\circ f = (1+x)^2\) when
   69  \(f(x)\) = \{NAMED_ANS('f',20)\} and \(g(x)\) = \{NAMED_ANS('g',20)\}
   70  END_TEXT
   71  NAMED_COMPOSITION_ANS(f => "x^2", g => "1+x");
   72 
   73 =cut
   74 
   75 sub NAMED_COMPOSITION_ANS {NAMED_ANS(composition_ans_list(@_))}
   76 
   77 =head2 composition_ans_list
   78 
   79  composition_ans_list($fID=>$f, $gID=>$g, %options)
   80 
   81 This is an internal routine that returns the named answer checkers
   82 used by COMPOSITION_ANS and NAMED_COMPOSITION_ANS above.
   83 
   84 $fID and $gID are the names of the answer rules for the functions and $f and $g
   85 are the answers for these functions. %options are from among:
   86 
   87 =over
   88 
   89 =item S<C<< var => 'x' >>>
   90 
   91 the name of the variable to use when
   92 both functions use the same one
   93 
   94 =item S<C<< vars => ['x','t'] >>>
   95 
   96 the names of the variables for $f and $g
   97 
   98 =item S<C<< showVariableHints => 1 or 0 >>>
   99 
  100 do/don't show errors when the variable
  101 used by the student is incorrect
  102 
  103 =back
  104 
  105 =cut
  106 
  107 sub composition_ans_list {
  108   my ($fID,$f,$gID,$g,%params) = @_; my @IDs = ($fID,$gID);
  109   #
  110   #  Get options
  111   #
  112   $params{vars} = [$params{var},$params{var}] if $params{var} && !$params{vars};
  113   $params{showVariableHints} = 1 unless defined($params{showVariableHints});
  114   my $isPreview = $main::inputs_ref->{previewAnswers};
  115   my $vars = $params{vars} || [];
  116   my @options = (ignoreInfinity=>0,ignoreStrings=>0);
  117   my ($i,$error);
  118 
  119   #
  120   #  Get correct answer data and determine which variables to use
  121   #
  122   $f = Value->Package("Formula")->new($f); $g = Value->Package("Formula")->new($g);
  123   my %correct = ($fID => $f, $gID => $g);
  124   my %x = ($fID => $vars->[0], $gID => $vars->[1]);
  125   foreach $i (@IDs) {
  126     unless ($x{$i}) {
  127       die "Can't tell which variable to use for $correct{$i}: ".
  128              "use var=>'x' or vars=>['x','y'] to specify it"
  129   if scalar(keys %{$correct{$i}->{variables}}) > 1;
  130       $x{$i} = (keys %{$correct{$i}->{variables}})[0];
  131     }
  132     die "$correct{$i} is not a function of $x{$i}"
  133       unless defined($correct{$i}->{variables}{$x{$i}});
  134   }
  135   my %y = ($fID => $x{$gID}, $gID => $x{$fID});
  136   my %ans = ($fID => message_cmp($f), $gID => message_cmp($g));
  137   my $fog = $f->substitute($x{$fID}=>$g);  #  the composition
  138 
  139   #
  140   #  Check that the student formulas parse OK,
  141   #  produce a number, contain the correct variable,
  142   #  don't contain the composition itself in a simple way,
  143   #  and aren't the identity.
  144   #
  145   my %student = ($fID => $main::inputs_ref->{$fID},
  146      $gID => $main::inputs_ref->{$gID});
  147   foreach $i (@IDs) {
  148     next unless defined($student{$i});
  149     $student{$i} = Parser::Formula($student{$i});
  150     if (!defined($student{$i})) {$error = 1; next}
  151     $ans{$i}->{rh_ans}{preview_latex_string} = $student{$i}->TeX;
  152     if ($student{$i}->type ne 'Number') {
  153       $ans{$i} = $correct{$i}->cmp(@options);
  154       $error = 1; next;
  155     }
  156     if ($x{$fID} ne $x{$gID} && defined($student{$i}->{variables}{$y{$i}})) {
  157       $ans{$i}->{rh_ans}{ans_message} = "Your formula may not contain $y{$i}"
  158   unless $isPreview || !$params{showVariableHints};
  159       $error = 1; next;
  160     }
  161     if (!defined($student{$i}->{variables}{$x{$i}})) {
  162       $ans{$i}->{rh_ans}{ans_message} = "Your formula is not a function of $x{$i}"
  163   unless $isPreview || !$params{showVariableHints};
  164       $error = 1; next;
  165     }
  166     if (($student{$i}->{tree}->class eq 'BOP' &&
  167    ($fog == $student{$i}->{tree}{lop} || $fog == $student{$i}->{tree}{rop})) ||
  168   ($student{$i}->{tree}->class eq 'UOP' && $fog == $student{$i}->{tree}{op})) {
  169       $ans{$i}->{rh_ans}{ans_message} =
  170         "Your formula may not have the composition as one of its terms";
  171       $error = 1; next;
  172     }
  173     if ($fog == $student{$i}) {
  174       $ans{$i}->{rh_ans}{ans_message} =
  175   "Your formula my not be the composition itself";
  176       $error = 1; next;
  177     }
  178     if ($student{$i} == $x{$i}) {
  179       $ans{$i}->{rh_ans}{ans_message} = "The identity function is not allowed"
  180   unless $isPreview;
  181       $error = 1; next;
  182     }
  183 
  184   }
  185 
  186   #
  187   #  If no error, and both answers are given, check if compositions are equal
  188   #
  189   if (!$error && defined($student{$fID}) && defined($student{$gID})) {
  190     if ($fog == $student{$fID}->substitute($x{$fID}=>$student{$gID})) {
  191       $ans{$fID}->{rh_ans}{score} = $ans{$gID}->{rh_ans}{score} = 1;
  192     }
  193   }
  194 
  195   return (%ans);
  196 }
  197 
  198 =head2 message_cmp
  199 
  200  message_cmp($correct)
  201 
  202 Returns an answer evaluator that always returns incorrect, with a given error
  203 message. Used by COMPOSITION_ANS to produce "dummy" answer checkers for the two
  204 parts of the composition.
  205 
  206 =cut
  207 
  208 sub message_cmp {
  209   my $correct = shift;
  210   my $answerEvaluator = new AnswerEvaluator;
  211   $answerEvaluator->ans_hash(
  212      type => "message",
  213      correct_ans => $correct->string,
  214      ans_message => $message,
  215   );
  216   $answerEvaluator->install_evaluator(sub {shift});
  217   return $answerEvaluator;
  218 }
  219 
  220 1;
  221 

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9