[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 5373 - (download) (as text) (annotate)
Sun Aug 19 02:01:57 2007 UTC (12 years, 3 months ago) by dpvc
File size: 7349 byte(s)
Normalized comments and headers to that they will format their POD
documentation properly.  (I know that the POD processing was supposed
to strip off the initial #, but that doesn't seem to happen, so I've
added a space throughout.)

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9